Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .github/workflows/asv-benchmarking-comment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: ASV Benchmarking (Comment)

# Runs AFTER "ASV Benchmarking (PR)" completes. Because it is triggered by
# workflow_run, it executes from the default branch with the repository's own
# GITHUB_TOKEN (read-write), so it CAN post a comment even when the benchmark
# run came from a fork PR (where the token is read-only). It only downloads a
# results artifact and posts text -- it never checks out or executes PR/fork
# code, which keeps the write token safe. Fixes #1547.

on:
workflow_run:
workflows: ["ASV Benchmarking (PR)"]
types:
- completed

permissions:
issues: write
pull-requests: write

jobs:
comment:
name: Post benchmark comment
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Download benchmark results artifact
uses: actions/download-artifact@v7
with:
name: asv-benchmark-results-Linux
path: asv-results
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Post or update result comment
uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');

// PR number and results were saved by the benchmark workflow.
const issue_number = parseInt(
fs.readFileSync('asv-results/pr_number.txt', 'utf8').trim(), 10);
const compareResults = fs.readFileSync(
'asv-results/asv_compare_results.txt', 'utf8');
const { owner, repo } = context.repo;

const newComment = `
## ASV Benchmarking

<details>
<summary>Benchmark Comparison Results</summary>

${compareResults}
</details>
`;

const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number,
});

const botComment = comments.find(
c => c.user.login === 'github-actions[bot]'
&& c.body.includes('## ASV Benchmarking'));

if (botComment) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: botComment.id,
body: newComment,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body: newComment,
});
}
63 changes: 11 additions & 52 deletions .github/workflows/asv-benchmarking-pr.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
name: ASV Benchmarking (PR)

# This workflow runs untrusted fork code, so it only gets a read-only token and
# no write access. It must NOT post comments itself (forks get a read-only token
# -> 403). Instead it uploads the results + PR number as an artifact, and the
# separate asv-benchmarking-comment.yml (triggered via workflow_run) posts the
# comment with the repo's write token. See issue #1547.
permissions:
issues: write
pull-requests: write
contents: read

on:
pull_request:
Expand Down Expand Up @@ -55,60 +59,15 @@ jobs:
asv compare --split ${{ github.event.pull_request.base.sha }} ${GITHUB_SHA} > asv_compare_results.txt
working-directory: ${{ env.ASV_DIR }}

- name: Save PR number
if: always()
run: echo "${{ github.event.pull_request.number }}" > ${{ env.ASV_DIR }}/pr_number.txt

- uses: actions/upload-artifact@v7
if: always()
with:
name: asv-benchmark-results-${{ runner.os }}
path: |
${{ env.ASV_DIR }}/results
${{ env.ASV_DIR }}/asv_compare_results.txt

- name: Post or update result comment
id: comment
uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const compareResults = fs.readFileSync('${{ env.ASV_DIR }}/asv_compare_results.txt', 'utf8');
const { owner, repo } = context.repo;
const issue_number = context.issue.number;

// Customize the comment content with your action results
const newComment = `
## ASV Benchmarking

<details>
<summary>Benchmark Comparison Results</summary>

${compareResults}
</details>
`;

// Fetch existing comments on the PR
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number,
});

// Find if there is an existing comment by this action
const botComment = comments.find(comment => comment.user.login === 'github-actions[bot]');

if (botComment) {
// Update the existing comment
await github.rest.issues.updateComment({
owner,
repo,
comment_id: botComment.id,
body: newComment,
});
} else {
// Create a new comment
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body: newComment,
});
}
${{ env.ASV_DIR }}/pr_number.txt
Loading