diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 9558e05f40..231f890c83 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -24,7 +24,6 @@ on: permissions: contents: read - pull-requests: write concurrency: group: benchmarks-${{ github.ref }} @@ -80,6 +79,14 @@ jobs: sudo Xvfb :99 -ac -screen 0 1400x1000x24 & echo "DISPLAY=:99" >> $GITHUB_ENV + - name: Record PR number for the comment follow-up + # Fork PRs run with a read-only GITHUB_TOKEN, so this job cannot post the + # results comment. The post-benchmark-comment workflow does that in the + # base-repo context; it needs the PR number, which isn't in the + # workflow_run payload for fork PRs, so hand it over via the artifact. + if: always() && github.event_name == 'pull_request' + run: echo "${{ github.event.pull_request.number }}" > benchmarks/pr-number.txt + - name: Run benchmarks id: bench run: | @@ -98,31 +105,9 @@ jobs: path: | benchmarks/results.json benchmarks/summary.md + benchmarks/pr-number.txt retention-days: 30 - - name: Comment results on the PR - if: always() && github.event_name == 'pull_request' - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - let body = '## Dash performance benchmarks\n\n_no summary produced_'; - try { body = fs.readFileSync('benchmarks/summary.md', 'utf8'); } catch (e) {} - const marker = ''; - body = `${marker}\n${body}`; - const {owner, repo} = context.repo; - const issue_number = context.issue.number; - const comments = await github.paginate( - github.rest.issues.listComments, {owner, repo, issue_number}); - const existing = comments.find(c => c.body && c.body.includes(marker)); - if (existing) { - await github.rest.issues.updateComment( - {owner, repo, comment_id: existing.id, body}); - } else { - await github.rest.issues.createComment( - {owner, repo, issue_number, body}); - } - - name: Fail on hard regression if: always() run: | diff --git a/.github/workflows/post-benchmark-comment.yml b/.github/workflows/post-benchmark-comment.yml new file mode 100644 index 0000000000..227da32306 --- /dev/null +++ b/.github/workflows/post-benchmark-comment.yml @@ -0,0 +1,69 @@ +name: Post Benchmark Comment + +# Posts the benchmark results comment in the base-repo context (with a +# read/write token) after the Performance Benchmarks workflow finishes. Fork +# PRs run that workflow with a read-only GITHUB_TOKEN, so its own comment step +# would 403 ("Resource not accessible by integration"). Same pattern as +# post-test-status.yml. The results and the PR number arrive via the +# benchmark-results artifact. + +on: + workflow_run: + workflows: ["Performance Benchmarks"] + types: + - completed + +jobs: + comment: + name: Comment benchmark results + runs-on: ubuntu-latest + if: github.event.workflow_run.event == 'pull_request' + permissions: + actions: read + pull-requests: write + steps: + - name: Download benchmark results + id: download + # A cancelled or superseded benchmarks run (cancel-in-progress) still + # fires this workflow_run but never uploads the artifact. Don't fail the + # named download in that case; the comment step below just skips. + continue-on-error: true + uses: actions/download-artifact@v4 + with: + name: benchmark-results + path: benchmark-results + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Comment results on the PR + if: steps.download.outcome == 'success' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + let issue_number; + try { + issue_number = parseInt( + fs.readFileSync('benchmark-results/pr-number.txt', 'utf8').trim(), 10); + } catch (e) {} + if (!issue_number) { + console.log('No PR number recorded; nothing to comment.'); + return; + } + let body = '## Dash performance benchmarks\n\n_no summary produced_'; + try { + body = fs.readFileSync('benchmark-results/summary.md', 'utf8'); + } catch (e) {} + const marker = ''; + body = `${marker}\n${body}`; + const {owner, repo} = context.repo; + const comments = await github.paginate( + github.rest.issues.listComments, {owner, repo, issue_number}); + const existing = comments.find(c => c.body && c.body.includes(marker)); + if (existing) { + await github.rest.issues.updateComment( + {owner, repo, comment_id: existing.id, body}); + } else { + await github.rest.issues.createComment( + {owner, repo, issue_number, body}); + }