ci-metrics #1008
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ci-metrics — the recorder (ADR-0047). Every time a tracked workflow | |
| # completes, this sweeps the recent completed runs, appends anything not yet | |
| # recorded to the orphan `ci-metrics` branch (NDJSON, one shard per month), | |
| # and re-renders DASHBOARD.md + site/summary.json there. phux-site's /ci | |
| # page reads summary.json straight off raw.githubusercontent.com, so the | |
| # public dashboard updates the moment this pushes — no site rebuild. | |
| # | |
| # SINGLE WRITER: nothing else may push to `ci-metrics`. The concurrency | |
| # group serializes collectors; GitHub keeps only the newest queued run when | |
| # several pile up, and that is fine BY DESIGN — collect-runs.sh sweeps a | |
| # window and diffs against what is recorded, so a cancelled collector's runs | |
| # are picked up by the next one. The weekly scheduled sweep is the backstop | |
| # that also refreshes the dashboard through quiet stretches. | |
| # | |
| # SECURITY: workflow_run executes with repo permissions, so this must never | |
| # run code from the triggering ref. It checks out main only, treats | |
| # artifact contents as data (schema-validated JSON lines, size-capped), and | |
| # needs just contents:write (the metrics branch) + actions:read (the API | |
| # sweep). GITHUB_TOKEN pushes do not re-trigger workflows, so no loops. | |
| name: ci-metrics | |
| on: | |
| workflow_run: | |
| workflows: | |
| - ci | |
| - stress | |
| - observatory | |
| - release | |
| - release-please | |
| - publish-crate | |
| - conventional-commits | |
| types: [completed] | |
| schedule: | |
| - cron: "45 6 * * 1" # Mondays 06:45 UTC, after the observatory | |
| workflow_dispatch: | |
| inputs: | |
| window: | |
| description: "How many recent completed runs to sweep (backfill knob)." | |
| type: string | |
| default: "40" | |
| permissions: | |
| contents: write | |
| actions: read | |
| concurrency: | |
| group: ci-metrics-writer | |
| cancel-in-progress: false | |
| jobs: | |
| record: | |
| name: record + render | |
| runs-on: ubuntu-latest | |
| steps: | |
| # The scripts, from main — never from the triggering ref. | |
| - uses: actions/checkout@v7 | |
| # The data branch. Seeded once by hand (see ADR-0047); this fails | |
| # loudly if it ever disappears rather than silently re-rooting history. | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ci-metrics | |
| path: metrics | |
| - name: Sweep runs + render dashboard | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| WINDOW: ${{ inputs.window || '40' }} | |
| run: | | |
| set -euo pipefail | |
| bash scripts/ci/collect-runs.sh --out metrics --window "$WINDOW" | |
| bash scripts/ci/render-dashboard.sh metrics | |
| - name: Push to ci-metrics | |
| run: | | |
| set -euo pipefail | |
| cd metrics | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add -A | |
| if git diff --cached --quiet; then | |
| echo "nothing new to record" | |
| exit 0 | |
| fi | |
| git commit -m "record ci metrics ($(date -u +%Y-%m-%dT%H:%MZ))" | |
| # The concurrency group makes a competing writer near-impossible, | |
| # but a rebase-retry costs nothing and makes it actually impossible | |
| # to clobber (NDJSON appends + regenerated derived files rebase | |
| # cleanly; the derived files are re-rendered next sweep anyway). | |
| for _ in 1 2 3; do | |
| git push origin HEAD:ci-metrics && exit 0 | |
| git pull --rebase -X theirs origin ci-metrics || true | |
| done | |
| echo "::error::could not push ci-metrics after 3 attempts" | |
| exit 1 | |
| - name: Dashboard excerpt | |
| if: always() | |
| run: | | |
| if [ -f metrics/DASHBOARD.md ]; then | |
| head -60 metrics/DASHBOARD.md >>"$GITHUB_STEP_SUMMARY" | |
| fi |