ci(release): warm the release profile in R2 from main every night - #344
Open
hyperb1iss wants to merge 1 commit into
Open
hyperb1iss wants to merge 1 commit into
hyperb1iss wants to merge 1 commit into
Conversation
Release builds run only on tags and release dispatches, and tags read the shared compiler cache without writing it, so nothing ever stored a release-profile compile. In 0.6.1 the macOS sidecar build missed 1,954 of 1,956 cacheable units and took 232 minutes; the Windows one missed 2,422 and took 101. CI/CD gains a warm dispatch mode. From main it runs the real release build jobs (credentials check, web assets, Native App, Linux release) without signing, and skips the normal CI lanes the way smoke does. Signing and publishing stay on tags and full dispatches. Running on main, warm writes every compile to R2 for the next tag to read. A new Release Cache Warm workflow dispatches it nightly, and RELEASING.md says when to run it by hand. Signing runs for any tag ref, so the credentials job, which every signing and release build job needs, refuses warm outside main. Warm also takes its own concurrency group: the main group never cancels, so a long warm run would otherwise leave main pushes pending, and a newer push cancels the older pending run. Web assets and the release lanes set save-if false so release dispatches never save their target directories into the Actions budget; R2 still receives their compiles. Warm uploads expire after a day. The Tauri bundle steps run cargo outside the cache wrappers, so they name RUSTC_WRAPPER directly and the app's dependency tree is cached too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hyperb1iss
force-pushed
the
nova/release-cache-warm
branch
from
October 2, 2026 23:24
9ce4297 to
c6f1347
Compare
|
Warning Review limit reached
This review includes 6 billable files and costs up to $1.50. Or wait 32 minutes for your next included review. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (6)
Comment |
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Release builds stop compiling the release profile from scratch on every tag. A new
warmmode for the CI/CD dispatch runs the real release build jobs onmain(web assets, Native App for Windows and macOS, and the Linux release lanes) without signing and without the normal CI lanes. Because it runs onmain, every compile it performs lands in the shared R2 cache, and the next tag's release builds read those entries instead of compiling them. A new Release Cache Warm workflow dispatches it every night, and RELEASING.md covers dispatching it by hand before a release that follows a lockfile or toolchain change.Why
Tags read R2 but never write it, and
mainnever built the release profile, so no release-profile compile was ever cached. The 0.6.1 tag run shows the cost: the macOS sidecar build missed 1,954 of 1,956 cacheable units and took 232 minutes, making Native App (macos-arm64) a 250-minute job and the long pole of every release. The Windows sidecar build missed 2,422 units and took 101 minutes.How it works
main, pull requestfulldispatchwarmdispatch frommainsmokewarmdispatch from any other refThe last row closes a real hole. The macOS signing job runs for any tag ref, so a warm dispatch from a tag would have notarized. The credentials job, which every signing and release build job needs, now fails a warm run that is not on
main.Supporting changes:
maingroup never cancels in progress, so a multi-hour warm run would otherwise leave main pushes pending, and a newer push cancels an older pending run.save-if: "false". A warm run never saves a release target directory into the Actions cache, and R2 still receives every compile because its write mode follows the trusted ref, notsave-if.RUSTC_WRAPPER: sccacheand the app's own dependency tree is cached too.0is upload-artifact's "repository default").mainpushes and the tag's own runs.Verification
just verifypasses locally (Rust fmt + lint + test) (not applicable: no Rust changes)just denypasses (required for dependency or license changes)just ui-testandjust ui-buildpass (required forcrates/hypercolor-ui/)just sdk-lint,just sdk-check, andjust sdk-buildpass (required forsdk/)just python-verifypasses (required forpython/)just compat-checkpasses (required fordata/drivers/vendors/*.toml)just docs-buildpasses (required for docs or README changes)cd docs && zola checkpasses (required for docs link/content changes)scripts/orpackaging/)just e2e-buildpasses with the normal Servo stack (required for daemon/UI/effect integration changes)just e2e-build-cpupasses when validating the CPU smoke fallbackjust e2epasses against the Servo stack (required for end-to-end behavior changes; starts daemon/browser)The new
scripts/tests/release-cache-warm.test.mjsevaluates the realif:expressions from ci.yml for each trigger. It checks which jobs run on warm, that nothing signs or publishes, that warm is refused offmain, the changes-job outputs, and the concurrency group. It also checks thesave-if, retention, and Tauri wiring, plus the scheduler. Every mutation I tried was caught, including dropping or inverting the refusal step, signing on warm, sharing the concurrency group, and saving an archive from a release lane. The macOS release test's "signing runs exactly when the build runs" check now allows exactly one exception: warm builds unsigned.All workflow contract suites pass locally:
node --test .github/actions/rust-build-cache/*.test.mjs scripts/tests/*.test.mjs, 72 tests, with sccache 0.17.0. One macOS release test needsshasum, which I shimmed on Linux; CI has it. actionlint reports nothing new.An independent review confirmed three more things. A tag build should hit a warm run's dependency entries: neither version step exports env, the
tauri.conf.jsonversion patch reaches only the uncached app binary, and main's last Windows run already hit R2 on 584 of 586 units.CARGO_INCREMENTAL=0reaches the Tauri steps. And a GITHUB_TOKEN dispatch creates a run, which release.yml already relies on.The real proof needs a merge. The first warm run on
maincompiles cold and fills R2, and then the next tag's Native App jobs should report mostly cache hits. I'll dispatch the first warm run by hand once this lands rather than wait for the schedule.Notes for reviewers
mainstill repeats every release link, because sccache never caches links.mainwrote. A leaked read-write key could poison them without a commit. This is the two-key model SERVO_BUILD_CACHING.md already documents, and onlymaincan reach that key.🤖 Generated with Claude Code