Benchmark #107
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: Benchmark | |
| on: | |
| schedule: | |
| # Run daily at 06:00 UTC | |
| - cron: '0 6 * * *' | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'src/**' | |
| - 'benchmarks/**' | |
| - 'package.json' | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - 'src/**' | |
| - 'benchmarks/**' | |
| workflow_dispatch: # Allow manual trigger | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| actions: read | |
| jobs: | |
| benchmark: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - run: npm ci | |
| - run: npm run build | |
| # Install competitors for comparison | |
| - run: npm install --no-save pino winston bunyan consola | |
| # Run throughput benchmark and capture output. Throughput.mjs writes | |
| # ./benchmark-throughput.json with structured metrics in addition to | |
| # human-readable console output. | |
| - name: Run throughput benchmark | |
| id: bench | |
| run: | | |
| echo "## Benchmark Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| node benchmarks/throughput.mjs 2>&1 | tee benchmark-output.txt >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| # Run size benchmark; writes ./benchmark-size.json | |
| - name: Run size benchmark | |
| run: | | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## Bundle Size" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| node benchmarks/size.mjs 2>&1 | tee -a benchmark-output.txt >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| # Pull the most recent baseline JSON from the latest successful main run. | |
| # Missing artifact (first run, deleted, etc.) is non-fatal — compare.mjs | |
| # will mark every metric as 🆕. | |
| - name: Download baseline benchmark from main | |
| if: github.event_name == 'pull_request' | |
| uses: dawidd6/action-download-artifact@v6 | |
| with: | |
| workflow: benchmark.yml | |
| branch: main | |
| name: benchmark-baseline-main | |
| path: baseline | |
| if_no_artifact_found: warn | |
| search_artifacts: true | |
| # Build markdown comparison report (traffic-light tables per metric). | |
| # Always exits 0 — never blocks the merge. | |
| - name: Compare against baseline | |
| if: github.event_name == 'pull_request' | |
| env: | |
| KONSOLE_RAW_OUTPUT: ${{ github.workspace }}/benchmark-output.txt | |
| run: node benchmarks/compare.mjs | |
| # Store this run's full results as a per-SHA artifact (kept 90 days). | |
| - name: Upload per-SHA benchmark results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: benchmark-results-${{ github.sha }} | |
| path: | | |
| benchmark-output.txt | |
| benchmark-throughput.json | |
| benchmark-size.json | |
| retention-days: 90 | |
| # On main pushes & schedule, also upload under a stable name so PR runs | |
| # can fetch this as the baseline. Overwrites the previous baseline. | |
| - name: Upload baseline benchmark (main only) | |
| if: github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: benchmark-baseline-main | |
| path: | | |
| benchmark-throughput.json | |
| benchmark-size.json | |
| retention-days: 90 | |
| overwrite: true | |
| # Post comment on PR with benchmark comparison | |
| - name: Comment on PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| let body; | |
| try { | |
| body = fs.readFileSync('benchmark-report.md', 'utf8'); | |
| } catch (e) { | |
| // Fallback if compare.mjs failed to write a report — embed raw output. | |
| const raw = fs.readFileSync('benchmark-output.txt', 'utf8'); | |
| body = '## 📊 Benchmark Results\n\n' + | |
| '_Comparison report unavailable — showing raw output._\n\n' + | |
| '<details><summary>Full output</summary>\n\n```\n' + raw + '\n```\n</details>'; | |
| } | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const existing = comments.find((c) => | |
| c.user.type === 'Bot' && c.body.includes('📊 Benchmark Results'), | |
| ); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body, | |
| }); | |
| } |