mirror of
https://github.com/Respect/Validation.git
synced 2026-03-14 14:25:45 +01:00
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.
This commit is contained in:
parent
e1ff5aa8fc
commit
26c0292bf9
2 changed files with 118 additions and 9 deletions
78
.github/workflows/ci-perf.yml
vendored
78
.github/workflows/ci-perf.yml
vendored
|
|
@ -21,19 +21,41 @@ on:
|
|||
options:
|
||||
- 'latest'
|
||||
- 'rebaseline'
|
||||
pull:
|
||||
description: 'Pull request number to benchmark (optional)'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: Benchmarks
|
||||
pr-benchmarks:
|
||||
name: PR Benchmarks
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.pull }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BENCHMARK_SHA: ${{ github.sha }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: true
|
||||
persist-credentials: false
|
||||
|
||||
- name: Checkout PR head
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PR=${{ github.event.inputs.pull }}
|
||||
# Validate that PR is numeric to avoid injection or unexpected ref resolution
|
||||
if ! printf '%s\n' "$PR" | grep -Eq '^[0-9]+$'; then
|
||||
echo "Invalid pull request number: '$PR'. Expected a numeric value." >&2
|
||||
exit 1
|
||||
fi
|
||||
# fetch the pull request head (works for forks)
|
||||
git fetch origin "pull/${PR}/head:pr-${PR}" || git fetch origin "+refs/pull/${PR}/head:pr-${PR}"
|
||||
git checkout "pr-${PR}"
|
||||
echo "Checked out PR #${PR}"
|
||||
echo "BENCHMARK_SHA=$(git rev-parse --verify HEAD)" >> "$GITHUB_ENV"
|
||||
|
||||
- uses: ./.github/actions/setup-action
|
||||
with:
|
||||
extensions: xdebug
|
||||
|
|
@ -48,13 +70,57 @@ jobs:
|
|||
run: |
|
||||
# Baseline does not exist or rebaseline requested. Generate it.
|
||||
if [ -z "$(ls -A .phpbench)" ] || [ "${{ github.event.inputs.baseline || 'latest' }}" = "rebaseline" ]; then
|
||||
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${GITHUB_SHA}
|
||||
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${BENCHMARK_SHA}
|
||||
|
||||
# Baseline exists. Compare against it.
|
||||
else
|
||||
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${GITHUB_SHA} --ref=latest --tolerate-failure
|
||||
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${BENCHMARK_SHA} --ref=latest --tolerate-failure
|
||||
fi
|
||||
|
||||
# Generate report for human consumption
|
||||
vendor/bin/phpbench report --report=aggregate --ref=latest |
|
||||
tail -n+2 | head -n-2 | tr '+' '|' > report.md
|
||||
|
||||
cat report.md > "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
historical-benchmarks:
|
||||
name: Historical Benchmarks
|
||||
if: >-
|
||||
github.event_name != 'workflow_dispatch' ||
|
||||
!github.event.inputs.pull
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BENCHMARK_SHA: ${{ github.sha }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: true
|
||||
|
||||
- uses: ./.github/actions/setup-action
|
||||
with:
|
||||
extensions: xdebug
|
||||
|
||||
- name: Fetch Benchmarks
|
||||
run: |
|
||||
git fetch origin benchmarks
|
||||
mkdir -p .phpbench
|
||||
git checkout origin/benchmarks -- .phpbench || echo "No previous benchmarks found"
|
||||
|
||||
- name: Run Benchmarks
|
||||
run: |
|
||||
# Baseline does not exist or rebaseline requested. Generate it.
|
||||
if [ -z "$(ls -A .phpbench)" ] || [ "${{ github.event.inputs.baseline || 'latest' }}" = "rebaseline" ]; then
|
||||
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${BENCHMARK_SHA}
|
||||
|
||||
# Baseline exists. Compare against it.
|
||||
else
|
||||
vendor/bin/phpbench run --report=aggregate --progress=plain --store --tag=${BENCHMARK_SHA} --ref=latest --tolerate-failure
|
||||
fi
|
||||
|
||||
# Generate report for human consumption
|
||||
vendor/bin/phpbench report --report=aggregate --ref=latest |
|
||||
tail -n+2 | head -n-2 | tr '+' '|' > report.md
|
||||
|
|
|
|||
49
.github/workflows/panda.yml
vendored
49
.github/workflows/panda.yml
vendored
|
|
@ -3,34 +3,77 @@ name: TheRespectPanda Bot
|
|||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
if: startsWith(github.event.comment.body, '@TheRespectPanda')
|
||||
|
||||
jobs:
|
||||
listen-comment:
|
||||
if: startsWith(github.event.comment.body, '@TheRespectPanda')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
steps:
|
||||
- uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.PANDA_GITHUB_PAT }}
|
||||
script: |
|
||||
const body = (context.payload.comment && context.payload.comment.body).trim() || '';
|
||||
const usage = 'Usage: `@TheRespectPanda ping|help`';
|
||||
const usage = 'Usage: `@TheRespectPanda ping|help|benchmark`';
|
||||
|
||||
if (!body.startsWith('@TheRespectPanda')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let answer;
|
||||
|
||||
switch (body) {
|
||||
case '@TheRespectPanda ping':
|
||||
answer = 'Pong! 🐼';
|
||||
break;
|
||||
|
||||
case '@TheRespectPanda':
|
||||
case '@TheRespectPanda help':
|
||||
answer = 'Hello! I am TheRespectPanda Bot. ' + usage;
|
||||
break;
|
||||
|
||||
case '@TheRespectPanda benchmark':
|
||||
// Only runnable on pull requests
|
||||
if (!context.payload.issue.pull_request) {
|
||||
answer = 'The `benchmark` command can only be used on pull requests.';
|
||||
break;
|
||||
}
|
||||
|
||||
// Only members can trigger benchmarks
|
||||
const association = context.payload.comment.author_association;
|
||||
const allowedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR'];
|
||||
if (!allowedAssociations.includes(association)) {
|
||||
answer = 'Only repository members can trigger benchmarks.';
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
// dispatch the perf workflow
|
||||
const ref = (context.payload.repository && context.payload.repository.default_branch) || 'main';
|
||||
|
||||
const workflowId = 'ci-perf.yml';
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: workflowId,
|
||||
ref,
|
||||
inputs: {
|
||||
baseline: 'latest',
|
||||
pull: String(context.issue.number)
|
||||
}
|
||||
});
|
||||
|
||||
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/workflows/${workflowId}`;
|
||||
answer = `Triggered phpbench benchmarks for PR #${context.issue.number} — workflow run: ${runUrl}`;
|
||||
} catch (err) {
|
||||
answer = `Failed to trigger benchmarks: ${err.message}`;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
answer = "I'm sorry, I don't understand that command. " + usage;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue