Skip to content

ci: share Rust builds across jobs (sccache + build-once CLI artifact)#401

Open
bordumb wants to merge 3 commits into
mainfrom
ci/share-builds
Open

ci: share Rust builds across jobs (sccache + build-once CLI artifact)#401
bordumb wants to merge 3 commits into
mainfrom
ci/share-builds

Conversation

@bordumb

@bordumb bordumb commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Problem

Nearly every CI job compiled the same dependency graph, and each job cached target/ + ~/.cargo under its own key namespace (-clippy-, -test-, -smoke-, …). Nothing was shared across jobs — on a single PR the workspace was compiled cold well over a dozen times, and the crate registry was stored redundantly under ~10 keys.

What this does

Three levers, no check changes:

  1. sccache (shared compiler cache). The setup-rust composite now installs mozilla-actions/sccache-action and sets RUSTC_WRAPPER=sccache with the GHA backend. sccache is content-addressed, so a crate compiled once in any job/runner is reused everywhere its inputs match. Applied to ci.yml, node-sdk, python-sdk, verify-commits, and test-windows-build.
  2. Build-once, fan-out. A new build-cli matrix job compiles auths-cli + auths-mcp-gateway once per OS and uploads the binaries as an artifact. smoke and e2e download and run them instead of recompiling, dropping the Rust toolchain entirely. e2e keeps its gate via needs: [test, build-cli].
  3. Consolidated caching. The composite is now the single place that installs the toolchain and caches deps, via Swatinem/rust-cache (deps-only, auto-pruned) in place of the hand-rolled actions/cache blocks. Jobs whose build dir isn't the workspace target/ (fuzz-smoke, node-sdk, python-sdk) pass cache: false and keep their own scoped cache.

No checks removed

Same job set plus build-cli; every lint/test/verify command is unchanged (verified by a before/after command inventory — the only removed run: lines were the two redundant cargo build CLI invocations, now centralized in build-cli). Each job's toolchain was preserved exactly (stable/1.93/1.93.0/nightly). actionlint is clean across all workflows.

Notes for review

  • sccache-action version is pinned at v0.0.9 — worth confirming that's the intended/latest tag for this org.
  • This is validated statically (actionlint + YAML parse + check inventory); the first CI run on this branch is the real confirmation, especially sccache wiring on macOS/Windows and the artifact exec-bit on macOS.
  • Fork PRs get read-only GHA cache; sccache falls back gracefully (no failure), just fewer hits.
  • Deliberately out of scope (release/scheduled, not PR-time): release.yml, publish-*.yml, docs.yml, fuzz.yml (nightly cron). Happy to extend sccache there in a follow-up.

🤖 Generated with Claude Code

Every compiling CI job recompiled the same dependency graph in its own
per-job cache namespace, so nothing was shared across jobs. This wires
three levers to fix that:

1. sccache — the setup-rust composite now installs mozilla-actions/
   sccache-action and sets RUSTC_WRAPPER=sccache with the GHA backend, so
   a crate compiled once (in any job/runner) is reused everywhere its
   inputs match. Added to ci.yml jobs, node-sdk, python-sdk,
   verify-commits, and test-windows-build.

2. build-once, fan-out — a new build-cli job compiles auths-cli +
   auths-mcp-gateway once per OS and uploads the binaries as an artifact;
   smoke and e2e download and run them instead of recompiling (and drop
   the Rust toolchain entirely). e2e keeps its gate via
   needs: [test, build-cli].

3. consolidated caching — the composite is now the single place that
   configures the toolchain and swaps the hand-rolled actions/cache for
   Swatinem/rust-cache (deps-only, auto-pruned). Jobs whose build dir is
   not the workspace target (fuzz-smoke, node-sdk, python-sdk) pass
   cache: false and keep their own scoped cache.

No CI check was removed: same jobs (plus build-cli), same lint/test/
verify commands; only build and cache plumbing changed. Validated with
actionlint (clean) and a before/after check inventory.

Auths-Scope: sign_commit
Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd
Auths-Device: did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp
Auths-Anchor-Seq: 13
@github-actions

Copy link
Copy Markdown

Auths Commit Verification

Commit Status Details
88c4670f ✅ Verified Signed by did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp

Result: ✅ 1/1 commits verified

Auths-Scope: sign_commit
Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd
Auths-Device: did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp
Auths-Anchor-Seq: 13
@github-actions

Copy link
Copy Markdown

Auths Commit Verification

Commit Status Details
0cbf63b9 ✅ Verified Signed by did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp
88c4670f ✅ Verified Signed by did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp

Result: ✅ 2/2 commits verified

They had no server in CI, so each spent the 30s sqlx acquire_timeout retrying a
dead socket then skipped (PASS, ~13min serial, zero coverage). Give them a
dedicated ubuntu job with a postgres:16 service (service containers are
Linux-only; the macOS leg never enabled backend-postgres) and filter the binary
out of the main run so it no longer times out there.

Auths-Scope: sign_commit
Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd
Auths-Device: did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp
Auths-Anchor-Seq: 13
@github-actions

Copy link
Copy Markdown

Auths Commit Verification

Commit Status Details
71ddf1f1 ✅ Verified Signed by did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp
0cbf63b9 ✅ Verified Signed by did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp
88c4670f ✅ Verified Signed by did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp

Result: ✅ 3/3 commits verified

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.

1 participant