diff --git a/.bazelrc b/.bazelrc index fd6ff75beb..603ad46e4b 100644 --- a/.bazelrc +++ b/.bazelrc @@ -124,7 +124,6 @@ build:argument-comment-lint --@rules_rust//rust/toolchain/channel=nightly common:ci-windows --config=ci-bazel common:ci-windows --build_metadata=TAG_os=windows common:ci-windows --repo_contents_cache=D:/a/.cache/bazel-repo-contents-cache -common:ci-windows --repository_cache=D:/a/.cache/bazel-repo-cache # We prefer to run the build actions entirely remotely so we can dial up the concurrency. # We have platform-specific tests, so we want to execute the tests on all platforms using the strongest sandboxing available on each platform. diff --git a/.github/actions/setup-bazel-ci/action.yml b/.github/actions/setup-bazel-ci/action.yml index a1e46d2d04..a7e3b322c2 100644 --- a/.github/actions/setup-bazel-ci/action.yml +++ b/.github/actions/setup-bazel-ci/action.yml @@ -9,9 +9,9 @@ inputs: required: false default: "false" outputs: - cache-hit: - description: Whether the Bazel repository cache key was restored exactly. - value: ${{ steps.cache_bazel_repository_restore.outputs.cache-hit }} + repository-cache-path: + description: Filesystem path used for the Bazel repository cache. + value: ${{ steps.configure_bazel_repository_cache.outputs.repository-cache-path }} runs: using: composite @@ -41,17 +41,16 @@ runs: - name: Set up Bazel uses: bazelbuild/setup-bazelisk@v3 - # Restore bazel repository cache so we don't have to redownload all the external dependencies - # on every CI run. - - name: Restore bazel repository cache - id: cache_bazel_repository_restore - uses: actions/cache/restore@v5 - with: - path: | - ~/.cache/bazel-repo-cache - key: bazel-cache-${{ inputs.target }}-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }} - restore-keys: | - bazel-cache-${{ inputs.target }} + - name: Configure Bazel repository cache + id: configure_bazel_repository_cache + shell: pwsh + run: | + # Keep the repository cache under HOME on all runners. Windows `D:\a` + # cache paths match `.bazelrc`, but `actions/cache/restore` currently + # returns HTTP 400 for that path in the Windows clippy job. + $repositoryCachePath = Join-Path $HOME '.cache/bazel-repo-cache' + "repository-cache-path=$repositoryCachePath" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + "BAZEL_REPOSITORY_CACHE=$repositoryCachePath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Configure Bazel output root (Windows) if: runner.os == 'Windows' @@ -65,10 +64,6 @@ runs: $repoContentsCache = Join-Path $env:RUNNER_TEMP "bazel-repo-contents-cache-$env:GITHUB_RUN_ID-$env:GITHUB_JOB" "BAZEL_OUTPUT_USER_ROOT=$bazelOutputUserRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append "BAZEL_REPO_CONTENTS_CACHE=$repoContentsCache" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - if (-not $hasDDrive) { - $repositoryCache = Join-Path $env:USERPROFILE '.cache\bazel-repo-cache' - "BAZEL_REPOSITORY_CACHE=$repositoryCache" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - } - name: Expose MSVC SDK environment (Windows) if: runner.os == 'Windows' diff --git a/.github/workflows/README.md b/.github/workflows/README.md index e7bad82677..d14817f002 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -5,15 +5,15 @@ The workflows in this directory are split so that pull requests get fast, review ## Pull Requests - `bazel.yml` is the main pre-merge verification path for Rust code. - It runs Bazel `test` and Bazel `clippy` on the supported Bazel targets. + It runs Bazel `test` and Bazel `clippy` on the supported Bazel targets, + including the generated Rust test binaries needed to lint inline `#[cfg(test)]` + code. - `rust-ci.yml` keeps the Cargo-native PR checks intentionally small: - `cargo fmt --check` - `cargo shear` - `argument-comment-lint` on Linux, macOS, and Windows - `tools/argument-comment-lint` package tests when the lint or its workflow wiring changes -The PR workflow still keeps the Linux lint lane on the default-targets-only invocation for now, but the released linter runs on Linux, macOS, and Windows before merge. - ## Post-Merge On `main` - `bazel.yml` also runs on pushes to `main`. diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index f7f16dd994..eeefcdadac 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -58,6 +58,20 @@ jobs: target: ${{ matrix.target }} install-test-prereqs: "true" + # Restore the Bazel repository cache explicitly so external dependencies + # do not need to be re-downloaded on every CI run. Keep restore failures + # non-fatal so transient cache-service errors degrade to a cold build + # instead of failing the job. + - name: Restore bazel repository cache + id: cache_bazel_repository_restore + continue-on-error: true + uses: actions/cache/restore@v5 + with: + path: ${{ steps.setup_bazel.outputs.repository-cache-path }} + key: bazel-cache-${{ matrix.target }}-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }} + restore-keys: | + bazel-cache-${{ matrix.target }} + - name: Check MODULE.bazel.lock is up to date if: matrix.os == 'ubuntu-24.04' && matrix.target == 'x86_64-unknown-linux-gnu' shell: bash @@ -112,12 +126,11 @@ jobs: # Save bazel repository cache explicitly; make non-fatal so cache uploading # never fails the overall job. Only save when key wasn't hit. - name: Save bazel repository cache - if: always() && !cancelled() && steps.setup_bazel.outputs.cache-hit != 'true' + if: always() && !cancelled() && steps.cache_bazel_repository_restore.outputs.cache-hit != 'true' continue-on-error: true uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 with: - path: | - ~/.cache/bazel-repo-cache + path: ${{ steps.setup_bazel.outputs.repository-cache-path }} key: bazel-cache-${{ matrix.target }}-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }} clippy: @@ -148,28 +161,55 @@ jobs: with: target: ${{ matrix.target }} + # Restore the Bazel repository cache explicitly so external dependencies + # do not need to be re-downloaded on every CI run. Keep restore failures + # non-fatal so transient cache-service errors degrade to a cold build + # instead of failing the job. + - name: Restore bazel repository cache + id: cache_bazel_repository_restore + continue-on-error: true + uses: actions/cache/restore@v5 + with: + path: ${{ steps.setup_bazel.outputs.repository-cache-path }} + key: bazel-cache-${{ matrix.target }}-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }} + restore-keys: | + bazel-cache-${{ matrix.target }} + - name: Set up Bazel execution logs shell: bash run: | mkdir -p "${RUNNER_TEMP}/bazel-execution-logs" echo "CODEX_BAZEL_EXECUTION_LOG_COMPACT_DIR=${RUNNER_TEMP}/bazel-execution-logs" >> "${GITHUB_ENV}" - - name: bazel build --config=clippy //codex-rs/... + - name: bazel build --config=clippy lint targets env: BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }} shell: bash run: | - # Keep the initial Bazel clippy scope on codex-rs and out of the - # V8 proof-of-concept target for now. + bazel_clippy_args=( + --config=clippy + --build_metadata=COMMIT_SHA=${GITHUB_SHA} + --build_metadata=TAG_job=clippy + ) + if [[ "${RUNNER_OS}" == "Windows" ]]; then + # Some explicit targets pulled in through //codex-rs/... are + # intentionally incompatible with `//:local_windows`, but the lint + # aspect still traverses their compatible Rust deps. + bazel_clippy_args+=(--skip_incompatible_explicit_targets) + fi + + bazel_target_lines="$(./scripts/list-bazel-clippy-targets.sh)" + bazel_targets=() + while IFS= read -r target; do + bazel_targets+=("${target}") + done <<< "${bazel_target_lines}" + ./.github/scripts/run-bazel-ci.sh \ -- \ build \ - --config=clippy \ - --build_metadata=COMMIT_SHA=${GITHUB_SHA} \ - --build_metadata=TAG_job=clippy \ + "${bazel_clippy_args[@]}" \ -- \ - //codex-rs/... \ - -//codex-rs/v8-poc:all + "${bazel_targets[@]}" - name: Upload Bazel execution logs if: always() && !cancelled() @@ -183,10 +223,9 @@ jobs: # Save bazel repository cache explicitly; make non-fatal so cache uploading # never fails the overall job. Only save when key wasn't hit. - name: Save bazel repository cache - if: always() && !cancelled() && steps.setup_bazel.outputs.cache-hit != 'true' + if: always() && !cancelled() && steps.cache_bazel_repository_restore.outputs.cache-hit != 'true' continue-on-error: true uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 with: - path: | - ~/.cache/bazel-repo-cache + path: ${{ steps.setup_bazel.outputs.repository-cache-path }} key: bazel-cache-${{ matrix.target }}-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }} diff --git a/justfile b/justfile index 7dc6ae1005..43afbf93d8 100644 --- a/justfile +++ b/justfile @@ -69,8 +69,9 @@ bazel-lock-check: bazel-test: bazel test --test_tag_filters=-argument-comment-lint //... --keep_going +[no-cd] bazel-clippy: - bazel build --config=clippy -- //codex-rs/... -//codex-rs/v8-poc:all + bazel_targets="$(./scripts/list-bazel-clippy-targets.sh)" && bazel build --config=clippy -- ${bazel_targets} [no-cd] bazel-argument-comment-lint: diff --git a/scripts/list-bazel-clippy-targets.sh b/scripts/list-bazel-clippy-targets.sh new file mode 100755 index 0000000000..d6351d1f89 --- /dev/null +++ b/scripts/list-bazel-clippy-targets.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "${repo_root}" + +# Resolve the dynamic targets before printing anything so callers do not +# continue with a partial list if `bazel query` fails. +manual_rust_test_targets="$(bazel query 'kind("rust_test rule", attr(tags, "manual", //codex-rs/... except //codex-rs/v8-poc/...))')" + +printf '%s\n' \ + "//codex-rs/..." \ + "-//codex-rs/v8-poc:all" + +# `--config=clippy` on the `workspace_root_test` wrappers does not lint the +# underlying `rust_test` binaries. Add the internal manual `*-unit-tests-bin` +# targets explicitly so inline `#[cfg(test)]` code is linted like +# `cargo clippy --tests`. +printf '%s\n' "${manual_rust_test_targets}"