Skip to content

ci: run every Rust validation through Bazel, drop cargo - #466

Merged
tinder-maxwellelliott merged 1 commit into
masterfrom
claude/bazel-only-ci-68fbab
Aug 17, 2026
Merged

ci: run every Rust validation through Bazel, drop cargo#466
tinder-maxwellelliott merged 1 commit into
masterfrom
claude/bazel-only-ci-68fbab

Conversation

@tinder-maxwellelliott

@tinder-maxwellelliott tinder-maxwellelliott commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

CI installed a host Rust toolchain and shelled out to cargo for four checks, plus a second toolchain for MSRV. That is a second build system's worth of setup to maintain, and it pinned the checks to whatever rustc dtolnay/rust-toolchain@stable resolved to on the day rather than the compiler MODULE.bazel names — so CI and a local bazel test could disagree. Every Rust validation now runs through Bazel.

What replaced what

Was (cargo) Now (Bazel)
cargo fmt --all -- --check //:rust_format_check (rustfmt_test, transitive)
cargo clippy --all-targets -- -D warnings //:rust_clippy_check (rust_clippy_test, transitive)
cargo test --lib --bins //:rust_tests (already existed)
cargo test --test e2e //tests:e2e_test (new rust_test)
cargo check on Rust 1.85 bazel build //src:bazel-diff --extra_toolchains=…rust_msrv…

perf-gate.yaml also loses its Setup Rust step — that job already built through Bazel and never used it.

Notes for review

The lint gates pin roots rather than relying on the .bazelrc aspects. Neither rust_clippy_aspect nor rustfmt_aspect propagates along deps, so an aspect-only gate covers just the targets a build happens to name. That was already true of the existing clippy setup and meant nothing was checking tools/coverage — it turned out to be unformatted. bazel run //cli/format:rustfmt is new and fixes it; make format now calls it instead of cargo fmt --all, which only ever saw the root crate. The aspects stay in .bazelrc for fast local feedback.

The e2e port needed two changes. Its support helpers read CARGO_MANIFEST_DIR and CARGO_BIN_EXE_*, which don't exist outside cargo, so they now prefer runfiles and keep the cargo values as a fallback — cargo test still works locally. Separately, the nested Bazel each fixture spawns is now chosen by $BAZEL: inside a Bazel test the first bazel on PATH is the outer Bazel's own binary, which ignores USE_BAZEL_VERSION, and two fixtures are version-sensitive enough that this silently produced wrong results. find_bazel() already checked $BAZEL first, so this is a config change, not a code one.

MSRV keeps its own toolchain, declared in MODULE.bazel and registered but deliberately not preferred (rules_rust appends repository_set toolchains after the defaults). The job selects it with --extra_toolchains and drops the lint output groups, since 1.85's clippy carries a different lint set and would fail that job for reasons unrelated to MSRV. It's Linux/x86_64 only — a repository_set tag declares one exec triple, and the job runs on ubuntu-latest. On another host the build just falls back to the default toolchain rather than failing.

Rebasing onto #465 conflicted here, and the resolution is worth a look: that PR gated the stock Rust toolchains to //platforms:is_system_libc so exactly one toolchain matches any build. The MSRV set carries the same gate and //platforms:system_libc in its target_compatible_with, so it doesn't reintroduce the ambiguity #465 removed on //platforms:linux_x86_64_musl.

Verification

Locally on macOS: both lint gates, //:rust_tests, the tools tests, and a --config=release build all pass.

The e2e suite is 32/36. The 4 failures are external::* fixtures whose nested Bazel needs a JDK, and this machine has none (/usr/bin/java is the macOS stub) — each fails with "Unable to locate a Java Runtime", and I confirmed one fails identically under cargo test here. That job installs Temurin 21, so they should pass in CI, but that is the specific claim I could not verify locally and the thing to watch on the first run.

🤖 Generated with Claude Code

@tinder-maxwellelliott
tinder-maxwellelliott marked this pull request as ready for review August 17, 2026 21:04
CI installed a host Rust toolchain and shelled out to cargo for four checks
(fmt, clippy, unit tests, e2e) plus a separate 1.85 toolchain for the MSRV
job. That is a second build system's worth of setup to maintain, and it
pinned the checks to whatever rustc `dtolnay/rust-toolchain@stable` resolved
to on the day rather than the compiler MODULE.bazel names -- so CI and a
local `bazel test` could disagree.

Each check now has a Bazel target:

  cargo fmt --all -- --check        -> //:rust_format_check
  cargo clippy --all-targets        -> //:rust_clippy_check
  cargo test --lib --bins           -> //:rust_tests (already existed)
  cargo test --test e2e             -> //tests:e2e_test
  cargo check (Rust 1.85)           -> build with --extra_toolchains=...rust_msrv

The lint gates pin an explicit root list rather than relying on the .bazelrc
aspects. Neither aspect propagates along deps, so an aspect-only gate covers
only the targets a build happens to name -- which is why nothing was checking
tools/coverage. It was unformatted; `bazel run //cli/format:rustfmt` (new, and
what `make format` now calls) fixed it.

The e2e suite needed two changes to run under Bazel. Its support helpers read
CARGO_MANIFEST_DIR and CARGO_BIN_EXE_*, which do not exist outside cargo, so
they now prefer runfiles and keep the cargo values as a fallback -- `cargo
test` still works locally. And the nested Bazel each fixture spawns is now
chosen by $BAZEL: inside a Bazel test the first `bazel` on PATH is the outer
Bazel's own binary, which ignores USE_BAZEL_VERSION, and two fixtures are
version-sensitive enough to silently produce wrong results because of it.

MSRV keeps its own toolchain in MODULE.bazel, registered but deliberately not
preferred; the job selects it with --extra_toolchains and drops the lint
output groups, since 1.85's clippy carries a different lint set and would fail
that job for reasons unrelated to MSRV.

perf-gate.yaml loses its Setup Rust step too -- that job already built through
Bazel and never used it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tinder-maxwellelliott
tinder-maxwellelliott force-pushed the claude/bazel-only-ci-68fbab branch from bbe36c2 to 144e869 Compare August 17, 2026 21:10
@tinder-maxwellelliott
tinder-maxwellelliott merged commit 87c4742 into master Aug 17, 2026
25 checks passed
@tinder-maxwellelliott
tinder-maxwellelliott deleted the claude/bazel-only-ci-68fbab branch August 17, 2026 22:03
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