Skip to content
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Step 2: Build the site in CI and publish it from main
The site job merges every job's results-* artifact and builds the site in
the ruby_4.0 container, the same way the lint runs. It runs also when some
benchmark jobs failed, so every PR gets a preview, and is skipped when the
benchmark jobs did not run (a lint failure), so it adds no red check there.
When a benchmark job failed, the build is marked incomplete and the page
says a result shown as skipped may be a crash.

The preview artifact is called site-preview, outside the results-* pattern,
so a re-run of failed jobs never downloads it as results, and a re-run
replaces the earlier preview. The run's Summary page links to it, so it is
one click away, also on PRs from forks.

Only a push to main where every benchmark job passed deploys to GitHub
Pages, so a partial run never replaces the live site. Runs can finish out
of order, so when main has moved on the deploy asks pick-benchmarks.sh
whether the newer commits run benchmarks: if they do, their run deploys
newer results and this one skips; if not (a README-only merge), this run's
results are still the newest and it deploys. The deploy job is the only
one with Pages permissions, and neither job is part of benchmarks-ok, so a
Pages problem never blocks a merge.
  • Loading branch information
JuanVqz committed Sep 30, 2026
commit 1138f1eb3eb83f07cbe9ab521978e55e8cc36d8b
93 changes: 93 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,99 @@ jobs:
path: results/
if-no-files-found: warn

# Builds the results site from every job's results, also when some jobs
# failed, so a PR gets a preview (the site-preview artifact, named outside
# the results-* pattern so a re-run never downloads it). Skipped when the
# benchmark jobs did not run (a lint failure). Only a push to
# main where every job passed publishes it, so a partial run never replaces
# the live site. Not required: a Pages problem never blocks a merge.
site:
needs: [changes, rake]
if: ${{ !cancelled() && needs.changes.outputs.run == 'true' && needs.rake.result != 'skipped' }}
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
pattern: results-*
path: results/
merge-multiple: true
- name: Build the results site
# A failed benchmark job leaves no result file, like a benchmark that needs a newer Ruby, so the page says missing results may be crashes.
env:
RESULTS_INCOMPLETE: ${{ needs.rake.result != 'success' && '1' || '' }}
run: docker compose run --rm -T -e RESULTS_INCOMPLETE --entrypoint ruby ruby_4.0 script/build_results_site.rb results _site
- name: Upload the site preview
id: preview
uses: actions/upload-artifact@v4
with:
name: site-preview
path: _site/
# A re-run replaces the earlier attempt's preview.
overwrite: true
# A one-click link on the run's Summary page; it needs no extra permissions, so it works for PRs from forks too.
- name: Link the site preview in the run summary
env:
PREVIEW_URL: ${{ steps.preview.outputs.artifact-url }}
run: |
{
echo "### Results site preview"
echo ""
echo "[Download the site preview]($PREVIEW_URL) (a zip, needs a GitHub login), unzip it and open \`index.html\` in a browser."
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload the site for GitHub Pages
if: github.event_name == 'push' && github.ref_name == 'main' && needs.rake.result == 'success'
uses: actions/upload-pages-artifact@v5
with:
path: _site/

deploy:
needs: [rake, site]
if: github.event_name == 'push' && github.ref_name == 'main' && needs.rake.result == 'success' && needs.site.result == 'success'
runs-on: ubuntu-latest
# Only this job can publish; the rest of the workflow keeps the default
# token permissions.
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
# One deploy at a time; a newer merge waits instead of cancelling one that
# is halfway through.
concurrency:
group: pages
cancel-in-progress: false

steps:
# Runs can finish out of order, so an older run must not put its results back over a newer one.
# When main moved on, ask pick-benchmarks.sh (the same rule CI uses) whether the newer commits run benchmarks.
# If they do, their own run deploys newer results; if not (a README-only merge), this run's results are still the newest.
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: Check no newer run on main will deploy
id: newest
run: |
if [ "$(git rev-parse HEAD)" = "$GITHUB_SHA" ]; then
echo "deploy=true" >> "$GITHUB_OUTPUT"
exit 0
fi
GITHUB_EVENT_NAME=push GITHUB_OUTPUT=newer.txt .github/scripts/pick-benchmarks.sh "$GITHUB_SHA"
if grep -q '^run=true' newer.txt; then
echo "main moved on and its newer commits run benchmarks, so their run deploys; skipping."
echo "deploy=false" >> "$GITHUB_OUTPUT"
else
echo "main moved on, but nothing since this run affects benchmarks; deploying."
echo "deploy=true" >> "$GITHUB_OUTPUT"
fi
- name: Deploy to GitHub Pages
id: deployment
if: steps.newest.outputs.deploy == 'true'
uses: actions/deploy-pages@v5

# The check to require on main. Passes when every benchmark job passed, or
# when there was nothing to benchmark.
benchmarks-ok:
Expand Down