Skip to content

Commit 0a831cb

Browse files
committed
Allow panda.yml to request benchmark runs for PRs
This change introduces a new command to `@TheRespectPanda` bot, allowing him to dispatch the ci-perf.yml workflow benchmarks for a pull request. Initially, the bot will just trigger it and return the workflow run URL for manual inspection. Future iterations on this feature could then grab the benchmark results and update the comment.
1 parent e1ff5aa commit 0a831cb

File tree

2 files changed

+113
-5
lines changed

2 files changed

+113
-5
lines changed

.github/workflows/ci-perf.yml

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,72 @@ on:
2121
options:
2222
- 'latest'
2323
- 'rebaseline'
24+
pull:
25+
description: 'Pull request number to benchmark (optional)'
26+
required: false
2427

2528
jobs:
26-
tests:
27-
name: Benchmarks
29+
pr-benchmarks:
30+
name: PR Benchmarks
31+
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.pull }}
32+
runs-on: ubuntu-latest
33+
34+
permissions:
35+
contents: read
36+
37+
steps:
38+
- uses: actions/checkout@v6
39+
with:
40+
persist-credentials: false
41+
42+
- name: Checkout PR head (if requested)
43+
if: ${{ github.event.inputs.pull }}
44+
run: |
45+
set -euo pipefail
46+
PR=${{ github.event.inputs.pull }}
47+
# Validate that PR is numeric to avoid injection or unexpected ref resolution
48+
if ! printf '%s\n' "$PR" | grep -Eq '^[0-9]+$'; then
49+
echo "Invalid pull request number: '$PR'. Expected a numeric value." >&2
50+
exit 1
51+
fi
52+
# fetch the pull request head (works for forks)
53+
git fetch origin "pull/${PR}/head:pr-${PR}" || git fetch origin "+refs/pull/${PR}/head:pr-${PR}"
54+
git checkout "pr-${PR}"
55+
echo "Checked out PR #${PR}"
56+
echo "GITHUB_SHA=$(git rev-parse --verify HEAD)" >> "$GITHUB_ENV"
57+
58+
- uses: ./.github/actions/setup-action
59+
with:
60+
extensions: xdebug
61+
62+
- name: Fetch Benchmarks
63+
run: |
64+
git fetch origin benchmarks
65+
mkdir -p .phpbench
66+
git checkout origin/benchmarks -- .phpbench || echo "No previous benchmarks found"
67+
68+
- name: Run Benchmarks
69+
run: |
70+
# Baseline does not exist or rebaseline requested. Generate it.
71+
if [ -z "$(ls -A .phpbench)" ] || [ "${{ github.event.inputs.baseline || 'latest' }}" = "rebaseline" ]; then
72+
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${GITHUB_SHA}
73+
74+
# Baseline exists. Compare against it.
75+
else
76+
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${GITHUB_SHA} --ref=latest
77+
fi
78+
79+
# Generate report for human consumption
80+
vendor/bin/phpbench report --report=aggregate --ref=latest |
81+
tail -n+2 | head -n-2 | tr '+' '|' > report.md
82+
83+
cat report.md > "$GITHUB_STEP_SUMMARY"
84+
85+
historical-benchmarks:
86+
name: Historical Benchmarks
87+
if: >-
88+
github.event_name != 'workflow_dispatch' ||
89+
!github.event.inputs.pull
2890
runs-on: ubuntu-latest
2991

3092
permissions:
@@ -34,6 +96,7 @@ jobs:
3496
- uses: actions/checkout@v6
3597
with:
3698
persist-credentials: true
99+
37100
- uses: ./.github/actions/setup-action
38101
with:
39102
extensions: xdebug
@@ -43,7 +106,7 @@ jobs:
43106
git fetch origin benchmarks
44107
mkdir -p .phpbench
45108
git checkout origin/benchmarks -- .phpbench || echo "No previous benchmarks found"
46-
109+
47110
- name: Run Benchmarks
48111
run: |
49112
# Baseline does not exist or rebaseline requested. Generate it.
@@ -54,7 +117,7 @@ jobs:
54117
else
55118
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${GITHUB_SHA} --ref=latest --tolerate-failure
56119
fi
57-
120+
58121
# Generate report for human consumption
59122
vendor/bin/phpbench report --report=aggregate --ref=latest |
60123
tail -n+2 | head -n-2 | tr '+' '|' > report.md

.github/workflows/panda.yml

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,71 @@ jobs:
1111
permissions:
1212
issues: write
1313
pull-requests: write
14+
actions: write
1415
steps:
1516
- uses: actions/github-script@v8
1617
with:
1718
github-token: ${{ secrets.PANDA_GITHUB_PAT }}
1819
script: |
1920
const body = (context.payload.comment && context.payload.comment.body).trim() || '';
20-
const usage = 'Usage: `@TheRespectPanda ping|help`';
21+
const usage = 'Usage: `@TheRespectPanda ping|help|benchmark`';
2122
2223
if (!body.startsWith('@TheRespectPanda')) {
2324
return;
2425
}
2526
27+
let answer;
28+
2629
switch (body) {
2730
case '@TheRespectPanda ping':
2831
answer = 'Pong! 🐼';
2932
break;
33+
3034
case '@TheRespectPanda':
3135
case '@TheRespectPanda help':
3236
answer = 'Hello! I am TheRespectPanda Bot. ' + usage;
3337
break;
38+
39+
case '@TheRespectPanda benchmark':
40+
// Only runnable on pull requests
41+
if (!context.payload.issue.pull_request) {
42+
answer = 'The `benchmark` command can only be used on pull requests.';
43+
break;
44+
}
45+
46+
// Only members can trigger benchmarks
47+
const association = context.payload.comment.author_association;
48+
const allowedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR'];
49+
if (!allowedAssociations.includes(association)) {
50+
answer = 'Only repository members can trigger benchmarks.';
51+
break;
52+
}
53+
54+
try {
55+
// dispatch the perf workflow
56+
const repoInfo = await github.rest.repos.get({ owner: context.repo.owner, repo: context.repo.repo });
57+
const ref = repoInfo.data.default_branch || 'main';
58+
59+
const workflowId = 'ci-perf.yml';
60+
const dispatchResp = await github.rest.actions.createWorkflowDispatch({
61+
owner: context.repo.owner,
62+
repo: context.repo.repo,
63+
workflow_id: workflowId,
64+
ref,
65+
inputs: {
66+
baseline: 'latest',
67+
pull: String(context.issue.number)
68+
}
69+
});
70+
71+
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/workflows/${workflowId}`;
72+
answer = `Triggered phpbench benchmarks for PR #${context.issue.number} — workflow run: ${runUrl}`;
73+
} catch (err) {
74+
answer = `Failed to trigger benchmarks: ${err.message}`;
75+
}
76+
77+
break;
78+
3479
default:
3580
answer = "I'm sorry, I don't understand that command. " + usage;
3681
}

0 commit comments

Comments
 (0)