feat(builtins): add the aspect ci command group (bazelrc + warming) - #1295
Merged
Conversation
…#1294) Introduces the `aspect ci` command group — the CI-runner-facing commands that the Aspect Workflows integrations call. This PR lands the whole group in one shot: `aspect ci bazelrc` and `aspect ci warming` (the latter folded in from #1063, which this supersedes). The in-CLI successor to `rosetta bazelrc`. On an Aspect Workflows CI runner, `aspect <task>` already routes Bazel through the runner's remote cache, repository cache, and per-runner output paths (via the `workflows` feature + `get_bazelrc_flags`). A bare `bazel build` started from the same job gets none of that. This command writes those same flags to a Bazel rc file so vanilla `bazel` invocations on the runner pick them up too. - Reuses `get_bazelrc_flags` — the single source of truth the `workflows` feature uses — so the generated rc can't drift from what `aspect <task>` injects. - Everything lands under one `common` section plus the runner's `startup` flags; version-gated `(flag, constraint)` tuples are resolved against the Bazel version detected on the runner (assumed-latest when undetectable, matching the runtime's `constraint_matches`). - Defaults to `~/.bazelrc` (the first user rc Bazel loads), overridable with `--output`. File output only — no stdout mode — and it refuses to run off a Workflows runner. - Unit tests cover the constraint gating, flag resolution, and rc rendering (`aspect dev test-bazelrc`). Pre-populates Bazel caches on a CI runner: cleans prior Bazel state under `${ASPECT__STORAGE_PATH}`, runs `bazel build --nobuild` against the given targets, and — on an Aspect Workflows runner — invokes `/etc/aspect/workflows/bin/warming_archive` to upload the populated caches to the warming bucket. Carried over from #1063; the only change is the `BazelTrait` load rewritten to the canonical `@aspect//traits.axl` form required by the public/private load lint that landed after that branch was cut. The CI integrations (the setup-aspect GitHub Action, Buildkite plugin, CircleCI orb, GitLab component) call `aspect ci bazelrc` instead of `rosetta bazelrc` once `rosetta` is gone from the runner image. --- - Searched for relevant documentation and updated as needed: yes (docsite PR switches the integrations from `rosetta bazelrc` to `aspect ci bazelrc`) - Breaking change (forces users to change their own code or config): no - Suggested release notes appear below: yes - Added the `aspect ci` command group: `aspect ci bazelrc` writes a Bazel rc (default `~/.bazelrc`) that routes raw `bazel` calls on an Aspect Workflows CI runner through the runner's caches — the in-CLI replacement for `rosetta bazelrc` — and `aspect ci warming` pre-populates and archives the runner's Bazel caches. - New test cases added (`bazelrc_test.axl`: version-constraint gating, mixed plain/tuple flag resolution, rc rendering; `aspect dev test-bazelrc`). - Manual testing: - `aspect ci bazelrc` off a runner exits non-zero with a clear message and writes nothing; on a runner (or faked via `ASPECT_WORKFLOWS_RUNNER=1`) it writes the `startup`/`common` flags with version-gated flags resolved against the local `bazel --version`. - `aspect ci warming --help` and group registration verified; both subcommands appear under `aspect ci`. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
✨ Aspect Workflows Tasks📅 Sun Jun 28 02:49:56 UTC 2026
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 629ceaea37
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
The summary said only "pre-populate Bazel caches", omitting that on an Aspect Workflows runner the task also invokes warming_archive to create and upload the warming archives. Reword the summary and description so the help reflects both responsibilities (and that the archive step is skipped off a Workflows runner). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The runtime no longer exposes a mutable `ctx.bazel.startup_flags`; startup flags are resolved from the build's active/per-call RunCommand (resolve_invocation_flags). The carried-over warming task still did `ctx.bazel.startup_flags.extend(...)`, which would fail with an attribute error on every `aspect ci warming` run before Bazel ever spawned. Build a blank rc with `ctx.bazel.new_rc(startup_flags=...)` (reads no on-disk .bazelrc) and pass it via `build(rc=...)`; command flags stay in `flags=`, which `build` appends to the rc's resolved options. Verified end-to-end: the --output_base startup flag now lands ahead of the `build` verb and the task runs clean off-runner. Thanks to the Codex review on #1295 for catching it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bazelrc.axl hand-rolled constraint_matches + resolve_flags to resolve the version-gated `(flag, constraint)` tuples from get_bazelrc_flags, duplicating logic the bazelrc crate already owns (and version_gte in build_metadata.axl). Load the build flags into a blank RunCommand via ctx.bazel.new_rc(flags=...) and expand the `common` section, which filters version-gated options against the Bazel version — the same path every other Bazel invocation uses. Drops constraint_matches, resolve_flags, and the version_tuple import (−112/+37 across the file + its test). _detect_bazel_version stays (new_rc needs the version passed in; only parse_rc auto-probes, and that reads an on-disk rc we don't want), and render_bazelrc stays (nothing renders a loadable rc file) — it now unwraps the (flag, condition) tuples that expand yields for surviving gated options. Verified the resolved flag set matches the old behavior on Bazel 8/7/6 and the assumed-latest (no bazel) case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…and) The `common` pseudo-command (a flag applied to every Bazel command) only exists since Bazel 6.3.0; on older Bazel a `common` line is an unrecognized-command error. Pick the rc sections by detected version: - Bazel >= 6.3.0, or version undetectable (assume latest): one `common` section, as before. - Bazel < 6.3.0: spell the flags out under `build` (inherited by test/run/coverage/cquery/aquery/fetch/clean/…) and `query` (the one action-relevant command that does NOT inherit `build`). Emitting every flag under `query` is safe here because this path only runs on Bazel < 6.3.0, where all the flags get_bazelrc_flags emits are accepted by `query` — the flags newer Bazel rejects on `query` (e.g. --incompatible_remote_results_ignore_disk) are version-gated to ranges where we use `common` instead and never reach the per-command path. Verified the section choice and flag set across Bazel 8.0.0 / 6.3.0 / 6.2.1 / 5.4.0. Unit tests cover command_sections (threshold) and render (common vs build+query, startup emitted once). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing) `bazel --version` can report a release candidate (`8.0.0-rc2`). Passed verbatim to new_rc, semver VersionReq matching treats the pre-release specially: `8.0.0-rc2` does NOT satisfy `>=8.0.0`, so the Bazel-8 cache flags were wrongly dropped on an rc build. Drop the `-…` suffix so an rc matches the same constraints its release will — mirroring the runtime's own `bazel info release` parser (info.rs::parse_release), the canonical version detector. (`version_tuple` already ignored the suffix for the 6.3.0 section comparison, so only the new_rc gating was affected.) Verified 8.0.0-rc2 now keeps the >=8 flag; 7.4.1 / 6.2.1 unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bazelrc.axl shelled out to `bazel --version` in its own _detect_bazel_version helper, duplicating version detection the runtime already does (and which feature/workflows.axl + resolve_rc_version each do separately too). Expose the runtime's detection to AXL and reuse it. - info.rs: add release_version(), a process-wide OnceLock-memoized probe via `bazel info release`, so every caller shares one probe instead of each spawning bazel. parse_release now preserves the full version (incl pre-release) rather than stripping. - mod.rs: add the `ctx.bazel.version(strip=True)` method — returns the release version as a str (None for non-release/unknown). strip defaults to True (drops the pre-release suffix, what gating + the 6.3.0 section threshold want); strip=False returns the exact reported version (e.g. "8.0.0-rc2"). Move the pre-release-suffix handling into constraint_matches (the single gating chokepoint) so an rc matches the same constraints its release will, regardless of which caller supplied the version. - bazelrc.axl: drop _detect_bazel_version; call ctx.bazel.version(). Tests: parse_release preserves rc/pre suffixes; constraint_matches gates an rc as its release (new pre_release_matches_its_release_constraints). Verified `aspect ci bazelrc` across 8.0.0-rc2 / 8.0.0 / 7.4.1 / 6.2.1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two implementation details were leaking into user-facing output:
- The `warming_archive` binary path (`/etc/aspect/workflows/bin/warming_archive`)
appeared in the `aspect ci warming` skip warning and its --help description.
Reword to "uploads the populated caches to the warming bucket".
- The `ASPECT_WORKFLOWS_RUNNER` env var name appeared in the off-runner messages
of both `ci bazelrc` ("(ASPECT_WORKFLOWS_RUNNER unset)") and `ci warming`
("ASPECT_WORKFLOWS_RUNNER is not set"). Reword to "Not on an Aspect Workflows
runner" / "not on an Aspect Workflows runner".
The path constant, the env-var read, and the dev-facing module docstring keep
the concrete values — only user-facing strings change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`aspect ci bazelrc` writes ~/.bazelrc by default, but `get_bazelrc_flags` includes `--nohome_rc` in its startup flags (correct for the workflows feature, which passes them as command-line startup flags to `aspect <task>`). Written into ~/.bazelrc itself, `--nohome_rc` is self-defeating: Bazel reads the home rc, then that flag tells it to ignore the very file carrying our flags. Filter `--nohome_rc` out of the startup flags before rendering the rc. `--nosystem_rc` stays — it suppresses the separate /etc/bazel.bazelrc (e.g. a stale rc left by a prior rosetta run), which we do want. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generated rc configures raw `bazel` to use the Aspect Workflows runner's full set of services and optimizations, not only its cache. Reword the rc header comment, the task summary, and the module docstring from "routes raw `bazel` calls through ... cache" to "configures raw `bazel` calls to use ... services and optimizations". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t on runners Previously the command refused unless on a Workflows runner. But many of the flags aren't runner-specific and are useful on any CI. Split them: - Generic (any CI): --remote_upload_local_results, --heap_dump_on_oom, --generate_json_trace_profile, --experimental_repository_cache_hardlinks, --remote_accept_cached, --disk_cache=, --remote_timeout, --remote_retries, --grpc_keepalive_timeout. Plus the remote-cache endpoint flags from the ASPECT_WORKFLOWS_REMOTE_CACHE / _REMOTE_BYTESTREAM_URI_PREFIX env vars (which can be set off a runner too). - Runner-specific (only on a Workflows runner): --repository_cache and the per-runner output paths (mount-dependent), --remote_header=x-identity (runner identity), --nosystem_rc, and the cache-compression gates — the Workflows remote cache doesn't support compression, so those only apply when talking to it on a runner. Behavior by context: - Workflows runner: full set (unchanged from before). - Other CI, or explicit --output: generic + remote-cache-env flags only. - Local with no --output: refuse, so we don't stomp the dev's ~/.bazelrc. BES backend is intentionally NOT emitted as rc flags: on a runner that would double-stream build events for `aspect <task>` (which already wires BES via a runtime sink). Extracts get_generic_bazelrc_flags() in lib/environment.axl; get_bazelrc_flags (the runner path, shared with feature/workflows.axl) composes it + the runner-specific flags, so the runner set is unchanged. Verified across all three contexts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The skip-archive message was written raw to stderr with a lowercase `warning:` prefix. Route it through the shared `warn(std, msg)` helper so it renders as a colored `WARNING:` line, consistent with `ci bazelrc` and the rest of the CLI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reword the docstring, rc header comment, and task summary to call the non-`aspect <task>` invocations "vanilla `bazel`" — clearer naming. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspect ci command group (bazelrc + warming) (#1294)aspect ci command group (bazelrc + warming)
bazelrc.axl / environment.axl: - Fix the stale `get_runner_bazelrc_flags` doc cross-reference. - Rewrite the task description (it claimed "only runs on a runner", no longer true) to describe the runner / other-CI / local behavior accurately. - Tighten the verbose new_rc/expand comment. warming.axl: - Read the storage mount from `ASPECT_WORKFLOWS_RUNNER_STORAGE_PATH` (the var the runner actually sets) instead of the stale `ASPECT__STORAGE_PATH`. - Resolve the warming archiver from `ASPECT_WORKFLOWS_RUNNER_WARMING_ARCHIVER`, falling back to /etc/aspect/workflows/bin/warming_archive. If neither is present, error with a hint to upgrade the aspect-cli (links to releases) instead of failing opaquely. - Refresh the docstring/description (drop the stale env var and hardcoded path). Tests: add get_generic_bazelrc_flags coverage (generic set is runner-independent; remote-cache env flags included when set). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gregmagolan
force-pushed
the
aspect-ci-bazelrc-task
branch
from
June 28, 2026 02:38
a34d537 to
060d588
Compare
`rosetta` is an implementation detail users shouldn't see in `--help`. The module docstring keeps the migration note for maintainers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There's no existence check on ~/.bazelrc — off a runner and off CI the command simply writes nothing by default (an explicit --output is required). Reword the description, error message, docstring, and comment to say that, rather than implying it detects and avoids overwriting an existing file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gregmagolan
added a commit
to aspect-build/bazel-examples
that referenced
this pull request
Jun 28, 2026
) Points every CI provider at the renamed/released Aspect Workflows `setup-aspect` integrations. | Provider | Old → New | |---|---| | GitHub Actions | `aspect-build/setup-aspect` v2026.25.1 → v2026.26.1 | | Buildkite | `aspect-build/aspect-workflows#…` → `aspect-build/setup-aspect#…` v2026.26.0 (plugin id is the repo slug with `-buildkite-plugin` stripped) | | CircleCI | orb `aspect-build/aspect-workflows@2026.25.3` → `aspect-build/setup-aspect@2026.26.2` (alias + `setup` command renamed to match) | | GitLab | component `aspect-workflows-gitlab-component/setup@2026.25.5` → `setup-aspect-gitlab-component/setup@2026.26.0`, and the job-template anchor `extends: .aspect-workflows-setup` → `.setup-aspect` | Runner queue tags/labels (`aspect-workflows`, `aspect-default`), CircleCI workflow names, and `.aspect/workflows/` config paths are unchanged — those aren't the plugin names. ### Notes for review - The plugins now *prefer* `aspect ci bazelrc`, which is still in flight in aspect-build/aspect-cli#1295. Until that CLI ships on the runner image, the plugins fall back to `rosetta bazelrc` (the designed graceful fallback), so CI should still pass. - The warming jobs still use `rosetta run warming` (the `aspect ci warming` AXL task isn't released yet — TODO comments retained in each config). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Adds the
aspect cicommand group — the CI-runner-facing commands that the Aspect Workflows integrations (the setup-aspect GitHub Action, Buildkite plugin, CircleCI orb, GitLab component) call. Two commands:aspect ci bazelrcWrites a Bazel rc so vanilla
bazelcalls pick up the same Aspect Workflows configuration thataspect <task>injects. What it writes depends on where it runs:--output: the generic flags only, plus the remote-cache endpoint whenASPECT_WORKFLOWS_REMOTE_CACHE/ASPECT_WORKFLOWS_REMOTE_BYTESTREAM_URI_PREFIXare set — nothing tied to a runner's mounts or identity.--output: writes nothing, so it doesn't clobber the developer's~/.bazelrc.Defaults to
~/.bazelrc. Build flags go undercommonon Bazel ≥ 6.3.0, or underbuild+queryon older Bazel (nocommonpseudo-command). Version-gated flags are resolved against the Bazel version (auto-detected, memoized, assumed-latest when unknown). File output only.aspect ci warmingPre-populates Bazel caches on a CI runner: cleans prior Bazel state under the runner's storage mount, runs
bazel build --nobuildagainst the given targets, and — on an Aspect Workflows runner — runs the warming archiver (ASPECT_WORKFLOWS_RUNNER_WARMING_ARCHIVER, defaulting to/etc/aspect/workflows/bin/warming_archive) to upload the populated caches. Off a Workflows runner the archive step is skipped.Supporting runtime change
Adds
ctx.bazel.version()— the Bazel release version (memoizedbazel info releaseprobe, shared across callers), with astripflag for the pre-release suffix. Pre-release suffixes are ignored when matching version-gated flag constraints so a release candidate gates as its release.Changes are visible to end-users: yes
Searched for relevant documentation and updated as needed: yes (the CI integrations and docsite call
aspect ci bazelrc)Breaking change (forces users to change their own code or config): no
Suggested release notes appear below: yes
Added the
aspect cicommand group:aspect ci bazelrcwrites a Bazel rc that routes vanillabazelcalls through Aspect Workflows services, andaspect ci warmingpre-populates and archives a runner's Bazel caches.Test plan
bazelrc_test.axl,aspect dev test-bazelrc): generic vs runner-specific flag split,~/.bazelrcstartup-flag handling, thecommonvsbuild/queryversion threshold, and rc rendering. Rust tests for the version probe and constraint matching (incl. pre-release handling).aspect ci bazelrcon a runner / other CI / off CI;aspect ci warmingon and off a runner, including the missing-archiver upgrade message.