fix: add per-command timeouts and CI optimizations #34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Package Manager Benchmarks | |
| on: | |
| push: | |
| workflow_dispatch: | |
| inputs: | |
| fixtures: | |
| description: "The fixture to run the benchmarks on" | |
| default: '["next", "astro", "vue", "svelte", "large", "babylon"]' | |
| variations: | |
| description: "The benchmark variations to run" | |
| default: '["clean", "node_modules", "cache", "cache+node_modules", "cache+lockfile", "cache+lockfile+node_modules", "lockfile", "lockfile+node_modules", "registry-clean", "registry-lockfile"]' | |
| binaries: | |
| description: "The binaries to run the benchmarks on" | |
| default: '"npm,yarn,berry,zpm,pnpm,vlt,bun,deno,nx,turbo,node"' | |
| warmup: | |
| description: "The number of warmup runs on each benchmark" | |
| default: "2" | |
| runs: | |
| description: "The number of runs on each benchmark" | |
| default: "5" | |
| schedule: | |
| # GitHub Actions cron uses UTC. 10:17 UTC ~= 2:17 AM Pacific (PST). | |
| - cron: "17 10 * * *" | |
| # Prevent multiple runs from interfering with each other | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }}-bust | |
| cancel-in-progress: true | |
| jobs: | |
| detect-changes: | |
| name: "Detect Changes" | |
| runs-on: ubuntu-24.04-arm | |
| outputs: | |
| app_only: ${{ steps.check.outputs.app_only }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check changed files | |
| id: check | |
| run: | | |
| # For scheduled runs and manual triggers, always run benchmarks | |
| if [[ "${{ github.event_name }}" != "push" ]]; then | |
| echo "app_only=false" >> "$GITHUB_OUTPUT" | |
| echo "Non-push event (${{ github.event_name }}), running full benchmarks" | |
| exit 0 | |
| fi | |
| # Get the list of changed files between this push and the previous commit | |
| CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "") | |
| if [ -z "$CHANGED_FILES" ]; then | |
| echo "app_only=false" >> "$GITHUB_OUTPUT" | |
| echo "Could not determine changed files, running full benchmarks" | |
| exit 0 | |
| fi | |
| echo "Changed files:" | |
| echo "$CHANGED_FILES" | |
| # Check if ALL changed files are under app/ (or non-benchmark files like README, .editorconfig) | |
| APP_ONLY=true | |
| while IFS= read -r file; do | |
| case "$file" in | |
| app/*|README.md|.editorconfig|.cursor/*|.github/workflows/*) | |
| # App or non-benchmark files — safe to skip benchmarks | |
| ;; | |
| *) | |
| # Benchmark-relevant file changed | |
| APP_ONLY=false | |
| echo "Benchmark-relevant file changed: $file" | |
| break | |
| ;; | |
| esac | |
| done <<< "$CHANGED_FILES" | |
| echo "app_only=$APP_ONLY" >> "$GITHUB_OUTPUT" | |
| echo "App-only changes: $APP_ONLY" | |
| benchmark: | |
| name: "Run Benchmarks" | |
| runs-on: ubuntu-24.04-arm | |
| needs: [detect-changes] | |
| if: needs.detect-changes.outputs.app_only != 'true' | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| fixture: ${{ fromJson((github.event_name == 'push' && github.ref != 'refs/heads/main') && '["next", "astro", "vue", "svelte"]' || (inputs.fixtures || '["next", "astro", "vue", "svelte", "large", "babylon"]')) }} | |
| variation: ${{ fromJson(inputs.variations || '["clean", "node_modules", "cache", "cache+node_modules", "cache+lockfile", "cache+lockfile+node_modules", "lockfile", "lockfile+node_modules", "registry-clean", "registry-lockfile"]') }} | |
| include: | |
| - variation: "run" | |
| fixture: "run" | |
| permissions: | |
| contents: read | |
| id-token: write | |
| env: | |
| BENCH_INCLUDE: ${{ fromJson(inputs.binaries || '"npm,yarn,berry,zpm,pnpm,vlt,bun,deno,nx,turbo,node"') }} | |
| BENCH_WARMUP: ${{ (github.event_name == 'push' && github.ref != 'refs/heads/main') && '1' || (inputs.warmup || '2') }} | |
| BENCH_RUNS: ${{ (github.event_name == 'push' && github.ref != 'refs/heads/main') && '1' || (inputs.runs || '5') }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| package-manager-cache: false | |
| - name: Install & Setup Tools | |
| run: | | |
| bash ./scripts/setup.sh | |
| - name: Configure AWS Credentials | |
| if: startsWith(matrix.variation, 'registry-') | |
| uses: aws-actions/configure-aws-credentials@v6 | |
| with: | |
| role-to-assume: ${{ secrets.AWS_ROLE_ARN }} | |
| aws-region: us-east-1 | |
| - name: Get CodeArtifact Token | |
| if: startsWith(matrix.variation, 'registry-') | |
| id: aws | |
| run: | | |
| CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token \ | |
| --domain vlt \ | |
| --domain-owner 451504312483 \ | |
| --region us-east-1 \ | |
| --query authorizationToken \ | |
| --output text) | |
| echo "::add-mask::$CODEARTIFACT_AUTH_TOKEN" | |
| echo "token=$CODEARTIFACT_AUTH_TOKEN" >> "$GITHUB_OUTPUT" | |
| - name: Tune settings for heavy fixtures | |
| id: tune | |
| run: | | |
| # Heavy fixtures (large, babylon) get reduced warmup/runs to keep | |
| # individual jobs under the timeout while still producing useful data. | |
| case "${{ matrix.fixture }}" in | |
| large|babylon) | |
| echo "warmup=1" >> "$GITHUB_OUTPUT" | |
| echo "runs=3" >> "$GITHUB_OUTPUT" | |
| echo "Heavy fixture detected — using warmup=1, runs=3" | |
| ;; | |
| *) | |
| echo "warmup=$BENCH_WARMUP" >> "$GITHUB_OUTPUT" | |
| echo "runs=$BENCH_RUNS" >> "$GITHUB_OUTPUT" | |
| ;; | |
| esac | |
| - name: Run Benchmarks variations | |
| env: | |
| CODEARTIFACT_AUTH_TOKEN: ${{ steps.aws.outputs.token }} | |
| VLT_REGISTRY_AUTH_TOKEN: ${{ secrets.VLT_REGISTRY_AUTH_TOKEN }} | |
| CLOUDSMITH_REGISTRY: ${{ secrets.CLOUDSMITH_REGISTRY }} | |
| CLOUDSMITH_AUTH_TOKEN: ${{ secrets.CLOUDSMITH_AUTH_TOKEN }} | |
| BENCH_WARMUP: ${{ steps.tune.outputs.warmup }} | |
| BENCH_RUNS: ${{ steps.tune.outputs.runs }} | |
| run: | | |
| ./bench run \ | |
| --fixtures="${{ matrix.fixture }}" \ | |
| --variation="${{ matrix.variation }}" | |
| - name: Upload Benchmark Results | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: results-${{ matrix.fixture }}-${{ matrix.variation }} | |
| path: ./results/${{ matrix.fixture }}/${{ matrix.variation }}/ | |
| retention-days: 7 | |
| - name: Upload Versions Info | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: versions-${{ matrix.fixture }}-${{ matrix.variation }} | |
| path: ./results/versions.json | |
| retention-days: 7 | |
| process: | |
| name: "Process Results" | |
| runs-on: ubuntu-24.04-arm | |
| needs: [detect-changes, benchmark] | |
| if: needs.detect-changes.outputs.app_only != 'true' | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "24" | |
| - name: Download Results | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: results | |
| pattern: results-* | |
| - name: Download Versions | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: versions-temp | |
| pattern: versions-* | |
| - name: Process Results | |
| run: | | |
| ./bench process | |
| - name: Install vlt | |
| run: | | |
| npm install -g vlt@latest | |
| - name: Build Charts View | |
| run: | | |
| pushd app | |
| vlt install || true | |
| vlt run build | |
| popd | |
| - name: Upload Processed Results | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: results | |
| path: results/ | |
| retention-days: 7 | |
| deploy: | |
| name: "Deploy Results" | |
| runs-on: ubuntu-24.04-arm | |
| needs: [detect-changes, process] | |
| permissions: | |
| contents: write | |
| if: github.ref == 'refs/heads/main' && needs.detect-changes.outputs.app_only != 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Download Results | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: results | |
| path: results/ | |
| - name: Deploy to GitHub Pages | |
| uses: peaceiris/actions-gh-pages@v4 | |
| with: | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| publish_dir: results | |
| keep_files: true | |
| deploy-app: | |
| name: "Deploy App Only" | |
| runs-on: ubuntu-24.04-arm | |
| needs: [detect-changes] | |
| permissions: | |
| contents: write | |
| if: github.ref == 'refs/heads/main' && needs.detect-changes.outputs.app_only == 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "24" | |
| - name: Checkout gh-pages data | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: gh-pages | |
| path: gh-pages-data | |
| - name: Install vlt | |
| run: | | |
| npm install -g vlt@latest | |
| - name: Build App | |
| run: | | |
| pushd app | |
| vlt install || true | |
| vlt run build | |
| popd | |
| - name: Prepare deploy directory | |
| run: | | |
| # Copy the latest data files from gh-pages into the built results | |
| cp -r gh-pages-data/latest results/latest | |
| # Copy index.html and assets from the fresh build are already in results/ | |
| # The deploy action with keep_files merges with existing gh-pages content | |
| - name: Deploy to GitHub Pages | |
| uses: peaceiris/actions-gh-pages@v4 | |
| with: | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| publish_dir: results | |
| keep_files: true |