Skip to content

Releases check that CI passed instead of rerunning the tests, ~5 min faster (#915) - #922

Merged
ccoventry merged 3 commits into
devfrom
ci/release-skip-duplicate-tests-915
Oct 23, 2026
Merged

ccoventry merged 3 commits into
devfrom
ci/release-skip-duplicate-tests-915

Conversation

@ccoventry

Copy link
Copy Markdown
Owner

Release note: none

Closes #915

The release workflows (release_stable.yml, release_experimental.yml) no longer rerun cargo test --workspace and the Vitest unit tests that CI already passed on the same code. A new early step, Require passing CI on this commit, runs .github/scripts/require_ci_passed.py:

  1. Reads the required status checks of the branch's ruleset with GET /repos/{repo}/rules/branches/{branch} (dev for experimental, main for stable), so the list follows the rulesets with no copy to keep in sync. Matches on the exact check name and the app id (integration_id 15368, GitHub Actions).
  2. Collects the commits with the same tree as the one being built: the commit itself, its parents, and the heads of its PRs (commits/{sha}/pulls), each compared by git/commits/{sha} tree sha.
  3. Reads their check runs (commits/{sha}/check-runs). Per commit only the latest run of a check counts (a re-run replaces a failure). A check passes on success, neutral or skipped, as the rulesets count them.
  4. Passes when every required check passed, fails loudly with a per-check table and an ::error:: naming the missing or failed ones, and waits (30 s polls, up to 45 min) while a run is still going.

Workflow permissions gain checks: read. The stable workflow gains the same "Record the commit being built" step the experimental one has. --locked stays on the hook DLL build; its comment moved with it. docs/versioning_and_releases.md has a new section on the check.

Decisions

  • Which commit, and why a same-tree commit counts. Stable builds main's dev -> main merge commit (v0.2.0 = 4fa6e97), which has no check runs: CI runs on PRs and on pushes to dev, never on main. Its second parent, dev's tip e9298df, has the identical tree and every required check, including PR into main comes from dev from the release PR. The rule "any commit with the identical tree" is sound because both rulesets require an up-to-date branch: the PR head already contains the base, so the merge commit's tree equals the head's, and CI's pull_request run (which tests the PR merged into its base) tested exactly that tree. Experimental builds dev's head, which normally has its own push CI; right after a merge, while that push CI is still running, the merged PR's head (same tree) already carries the passes, so the release doesn't wait. A tree no CI run tested (an admin push past the rulesets) fails the release; there is no bypass input, deliberately.
  • Required list = the target branch's ruleset, read at run time, not hard-coded. main adds PR into main comes from dev.
  • Frontend unit tests removed too (5-9 s): CI's required Frontend e2e tests job runs npm run test:unit first, so they were duplicated as well. npm ci stays: the Tauri build needs it.
  • Waits rather than fails on a running check, so an experimental dispatch right after a merge just waits for CI instead of failing. 45 min cap.
  • A failed latest run on one same-tree commit doesn't veto a pass on another (e.g. dev's push run flaked but the PR run passed): same tree, and the rulesets let it merge on that pass.

Validation (local runs against real release commits)

Unit tests: python -m unittest discover -s .github/scripts -p "test_*.py" → 33 tests OK (13 new in test_require_ci_passed.py; CI's "Release notes collector tests" step discovers them). The check took 3.5 s locally.

v0.2.0 stable (4fa6e97, main merge commit, no CI of its own):

Commit 4fa6e97d2b5bfd204f081e23569e7e1302e49cfc, required checks of main: Rust workspace tests, Frontend e2e tests, Clippy, PR into main comes from dev, Hooks 32-bit, Web analyzer and Python
Commits with the same tree: 4fa6e97d2b5bfd204f081e23569e7e1302e49cfc, e9298df4296e3cbdf50f4c91dc988e473ef55dde
  PASS     Rust workspace tests         success on e9298df429 https://github.com/ccoventry/dod-studio/actions/runs/39740814336/job/119697316332
  PASS     Frontend e2e tests           success on e9298df429 https://github.com/ccoventry/dod-studio/actions/runs/39740814336/job/119697316764
  PASS     Clippy                       success on e9298df429 https://github.com/ccoventry/dod-studio/actions/runs/39740814336/job/119697316573
  PASS     PR into main comes from dev  success on e9298df429 https://github.com/ccoventry/dod-studio/actions/runs/39740814386/job/119697316187
  PASS     Hooks 32-bit                 success on e9298df429 https://github.com/ccoventry/dod-studio/actions/runs/39740814336/job/119697316522
  PASS     Web analyzer and Python      success on e9298df429 https://github.com/ccoventry/dod-studio/actions/runs/39740814336/job/119697316688
All required CI checks passed on this tree.
exit 0

Last experimental build (experimental-latest = e9298df, dev merge of #916):

Commit e9298df4296e3cbdf50f4c91dc988e473ef55dde, required checks of dev: Rust workspace tests, Frontend e2e tests, Clippy, Hooks 32-bit, Web analyzer and Python
Commits with the same tree: e9298df4296e3cbdf50f4c91dc988e473ef55dde, cd2142db49c283dabbd4a7bbb2faf4564a9d08af
  PASS     Rust workspace tests     success on e9298df429 https://github.com/ccoventry/dod-studio/actions/runs/39740814336/job/119697316332
  ... (all 5 PASS)
All required CI checks passed on this tree.
exit 0

A PR head whose Rust tests failed (15ec6cd, fix/live-bob-889):

  FAIL     Rust workspace tests     failure on 15ec6cd8b2 https://github.com/ccoventry/dod-studio/actions/runs/39586802605/job/119177615217
  PASS     Frontend e2e tests       success on 15ec6cd8b2 ...
::error::Required CI checks did not pass on 15ec6cd8b2's tree: Rust workspace tests
exit 1

A commit no CI ever ran on (7d2da6e, an upstream dod-tools commit): all six MISSING ... no run on any same-tree commit, exit 1.

Job times

Before, from the last seven release runs (seconds; the after column is the same run minus the two removed steps plus ~5 s for the check, since a release can't be run from a PR):

Run Workflow Job Rust tests Frontend unit Build, sign, publish After (est.)
39742006488 stable v0.2.0 998 445 6 393 ~552
39738971135 experimental 834 252 8 380 ~579
39733994333 experimental 594 150 6 275 ~443
39727802729 experimental 854 259 8 388 ~592
39714103160 experimental 1148 252 9 386 ~892
39554649554 experimental 561 158 5 249 ~403
39550062926 experimental 1387 615 8 539 ~769

So 2.5-10 min off each release, ~5 min on average over these seven. The rust-cache the release job saves also shrinks, since it no longer holds the test-profile build (~6m49s of compile in the v0.2.0 run).

LTO (measured note only, no change)

[profile.release] is lto = true, codegen-units = 1. In the "Build, sign, and publish" step of warm-cache runs, only ~6 crates compile, and the release cargo build takes 3m34s / 5m47s / 6m01s (runs 39733994333, 39738971135, 39742006488). Almost all of that is after Compiling native starts: native codegen on one codegen unit plus the fat-LTO link of desktop-studio (e.g. 06:32:23 → 06:35:53). Vite (~0.2 s) and bundling + signing the MSI/NSIS (~20-50 s) are the rest. lto = "thin" with the default 16 codegen units would spread that over the runner's 4 cores; my estimate, not measured, is 1.5-3 min saved per release, at the cost of a somewhat larger and possibly slightly slower binary. Measuring it properly means two cold release builds plus installer size and a parse / Overviews timing each way; that changes what ships, so it stays the user's call (#915 option 2).

🤖 Generated with Claude Code

The release workflows reran cargo test --workspace and the Vitest unit
tests that CI had already passed on the same code. A new step,
require_ci_passed.py, reads the branch ruleset's required checks and
fails the release unless each one passed on the commit or on a commit
with the same tree (a dev -> main merge commit has no CI of its own;
its PR head does). It waits while a run is still going.

Closes #915

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Re-checked 10-22 before the user's call: ran this PR's require_ci_passed.py against today's dev head 0f5a9be (the #926 merge): all 5 required checks PASS on the merge commit itself (its push CI), same-tree commit 90c4bc6 found. Branch updated with dev.

🤖 Generated with Claude Code

@ccoventry
ccoventry merged commit 004bbb6 into dev Oct 23, 2026
5 checks passed
@ccoventry
ccoventry deleted the ci/release-skip-duplicate-tests-915 branch October 23, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Chore] Release builds take ~10 min: skip the Rust tests CI already ran, maybe thinner LTO

1 participant