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
78 changes: 72 additions & 6 deletions .github/workflows/ci-perf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
49 changes: 46 additions & 3 deletions .github/workflows/panda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down