chore: add concurrency guards and pin zizmor in CI - #1126
Conversation
`ci.yml` and `zizmor.yml` had no `concurrency` block, so pushing three times to a PR ran three full matrices to completion. Only `test_notebook.yml` had one. Both now use the same group expression it already uses, with `cancel-in-progress: true`.
`release.yml` gets the same group but cancels only for pull requests, via `cancel-in-progress: ${{ github.event_name == 'pull_request' }}`. Its build job also runs on every PR to main, so superseded PR builds are worth cancelling, while a push to main or a published release must never be interrupted part way through.
Pinned `uvx zizmor` to 1.29.0, the current release. Unpinned, a new upstream audit turns CI red on a branch nobody touched. Renamed the job from "zizmor latest via PyPI" to match.
Deliberately not included. `timeout-minutes` on the test job is already fixed by #1119 on the integration branch, and adding it here would conflict when that merges up. The numpydoc hook sits on `v1.11.0rc0`, but that came from pre-commit.ci autoupdate picking the newest tag in #969, and there is no stable 1.11.0, so pinning back would just be re-bumped. A `cache: pip` step for the notebooks job is not worth it either: installing takes 75 seconds of a job that spends nine minutes running notebooks.
anevolbap
left a comment
There was a problem hiding this comment.
Inline notes on each change, so the body stays short.
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||
| # Only supersede pull request builds. A push to main or a published release | ||
| # must never be cancelled part way through. | ||
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} |
There was a problem hiding this comment.
This workflow triggers on pushes to main and on published releases, and cancelling either part way through is worse than letting a duplicate run finish. The build job still runs on every PR to main, so superseded PR builds are worth cancelling, hence the expression rather than skipping this file.
ci.yml and zizmor.yml now use the same expression for the same reason.
| run: uvx zizmor --format sarif . > results.sarif | ||
| # Pinned: an unpinned `uvx zizmor` turns CI red on an unchanged branch | ||
| # whenever upstream ships a new audit. | ||
| run: uvx zizmor@1.29.0 --format sarif . > results.sarif |
There was a problem hiding this comment.
1.29.0 is the current release, and what uvx zizmor resolved to when I checked.
The failure mode this prevents is a branch going red without anyone touching it: zizmor ships new audits regularly, and an unpinned uvx picks them up on the next run. Bumping this is then a deliberate, reviewable change, which matches how every uses: line in this repo is already pinned.
Renamed the job above, since "zizmor latest via PyPI" is no longer accurate.
Dependabot cannot see a version inside run:, so this one needs a manual bump. Noted in the step comment.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1126 +/- ##
=======================================
Coverage 95.98% 95.98%
=======================================
Files 104 104
Lines 16277 16277
Branches 912 912
=======================================
Hits 15623 15623
Misses 488 488
Partials 166 166 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The test job inherited GitHub's 6h default, so the wedged doctest described in #1117 burned a full runner on this PR's own run before being cancelled. Cap it at 30 minutes so a wedge reports `failure` in minutes. Wording matches #1119, which added the same guard on the integration branch. Restrict cancel-in-progress to pull requests in ci.yml and zizmor.yml, matching release.yml. A push to main now finishes, so the commit keeps its Codecov report and its code scanning results. Note on the zizmor pin that Dependabot cannot see a version inside `run:`, so it needs a manual bump.
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||
| # Only supersede pull request builds. A push to main must finish so the commit | ||
| # keeps its Codecov report. | ||
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} |
There was a problem hiding this comment.
Same group expression test_notebook.yml already uses, so the three behave consistently. Today a PR with three pushes runs three full matrices to completion, and nothing consumes the superseded results.
Cancellation is limited to pull requests, matching release.yml. A push to main finishes, so the commit keeps its Codecov report.
drbenvincent
left a comment
There was a problem hiding this comment.
Review
Approving — focused CI hygiene with verified motivation.
What it does:
- Adds PR-scoped
concurrencytoci.yml,zizmor.yml, andrelease.ymlso superseded PR builds cancel;mainpushes still finish (Codecov + SARIF preserved). - Pins
uvx zizmor@1.29.0— trades frozen audits for stability on untouched branches; inline comment documents manual bump. - Adds
timeout-minutes: 30on thetestjob — backstop for wedged doctests (#1117); run history on this PR shows the first push wedged ~6h before the guard landed.
Checks: CI green on latest head; branch up to date with main.
Non-blocking notes:
test_notebook.ymlstill cancels unconditionally — optional consistency follow-up.- Doctest sampling fix from #1119 on the integration branch is still the root-cause fix for #1117; this timeout is the guard only.
- Trivial comment-only overlap possible when the integration branch merges — values already align at 30 minutes.
Part of a deeper hardening pass over CI, pre-commit, packaging and pinning, done with Opus 5.
Three small things.
ci.ymlandzizmor.ymlhave noconcurrencyblock, so pushing three times to a PR runs three full matrices to completion.uvx zizmoris unpinned, so a new upstream audit can turn CI red on a branch nobody touched. And thetestjob has notimeout-minutes, so a wedged doctest holds a runner for six hours.Cancellation is limited to pull request builds, matching
release.yml. A push tomainfinishes, so the commit keeps its Codecov report and its code scanning results.Rationale for each change is inline on the diff.
On the timeout
An earlier revision of this PR left the timeout out, on the grounds that #1119 had already fixed it. That was wrong for this branch. #1119 landed on the integration branch, so
mainhas neither the guard nor the doctest sampling fix behind it. This PR's owntest (3.11)job then wedged inRun doctestsand was cancelled at the 6 hour ceiling, the third occurrence of #1117 after the two on #1087. The cap here reuses the wording from #1119 so the two branches converge instead of drifting.mainstill carries the root cause. Backporting the doctest sampling fix from #1119 is a separate change.Deliberately not included
The audit that produced this PR suggested three more changes. Each was dropped after checking, so recording why:
v1.11.0rc0. That rc came from pre-commit.ci autoupdate picking the newest tag in [pre-commit.ci] pre-commit autoupdate #969, and there is no stable 1.11.0, so pinning back would just be re-bumped next run.security-events: writeis not granted there. Wrong: Fix order-dependent interaction-term lookup in DiD effect_summary #1063 and feat: add power_analysis() with sigmoid fitting strategy (#820) #989 are genuine fork PRs and zizmor passes on both, soupload-sarifalready handles the read-only token.cache: pipon the notebooks job. Real but marginal: installing takes 75 seconds of a job that spends nine minutes running notebooks.