diff --git a/.github/actions/prepare-bazel-ci/action.yml b/.github/actions/prepare-bazel-ci/action.yml index bf07545e4..598c6e4c1 100644 --- a/.github/actions/prepare-bazel-ci/action.yml +++ b/.github/actions/prepare-bazel-ci/action.yml @@ -9,9 +9,6 @@ inputs: required: false default: "false" outputs: - repository-cache-hit: - description: Whether the Bazel repository cache restore hit. - value: ${{ steps.cache_bazel_repository_restore.outputs.cache-hit }} repository-cache-path: description: Filesystem path used for the Bazel repository cache. value: ${{ steps.setup_bazel.outputs.repository-cache-path }} diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 41d76f846..5d30916f9 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -109,10 +109,10 @@ jobs: path: ${{ runner.temp }}/bazel-execution-logs if-no-files-found: ignore - # Save bazel repository cache explicitly; make non-fatal so cache uploading - # never fails the overall job. Only save when key wasn't hit. + # Save the Bazel repository cache after every non-cancelled run. Keep the + # upload non-fatal so cache service issues never fail the job itself. - name: Save bazel repository cache - if: always() && !cancelled() && steps.prepare_bazel.outputs.repository-cache-hit != 'true' + if: always() && !cancelled() continue-on-error: true uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 with: @@ -186,10 +186,92 @@ jobs: path: ${{ runner.temp }}/bazel-execution-logs if-no-files-found: ignore - # Save bazel repository cache explicitly; make non-fatal so cache uploading - # never fails the overall job. Only save when key wasn't hit. + # Save the Bazel repository cache after every non-cancelled run. Keep the + # upload non-fatal so cache service issues never fail the job itself. - name: Save bazel repository cache - if: always() && !cancelled() && steps.prepare_bazel.outputs.repository-cache-hit != 'true' + if: always() && !cancelled() + continue-on-error: true + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + with: + path: ${{ steps.prepare_bazel.outputs.repository-cache-path }} + key: bazel-cache-${{ matrix.target }}-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }} + + verify-release-build: + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-24.04 + target: x86_64-unknown-linux-gnu + - os: macos-15-xlarge + target: aarch64-apple-darwin + - os: windows-latest + target: x86_64-pc-windows-gnullvm + runs-on: ${{ matrix.os }} + name: Verify release build on ${{ matrix.os }} for ${{ matrix.target }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Prepare Bazel CI + id: prepare_bazel + uses: ./.github/actions/prepare-bazel-ci + with: + target: ${{ matrix.target }} + + - name: bazel build verify-release-build targets + env: + BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }} + shell: bash + run: | + # This job exists to compile Rust code behind + # `cfg(not(debug_assertions))` so PR CI catches failures that would + # otherwise show up only in a release build. We do not need the full + # optimizer and debug-info work that normally comes with a release + # build to get that signal, so keep Bazel in `fastbuild` and disable + # Rust debug assertions explicitly. + bazel_wrapper_args=() + if [[ "${RUNNER_OS}" == "Windows" ]]; then + bazel_wrapper_args+=(--windows-msvc-host-platform) + fi + + bazel_build_args=( + --compilation_mode=fastbuild + --@rules_rust//rust/settings:extra_rustc_flag=-Cdebug-assertions=no + --@rules_rust//rust/settings:extra_exec_rustc_flag=-Cdebug-assertions=no + --build_metadata=COMMIT_SHA=${GITHUB_SHA} + --build_metadata=TAG_job=verify-release-build + --build_metadata=TAG_rust_debug_assertions=off + ) + + bazel_target_lines="$(bash ./scripts/list-bazel-release-targets.sh)" + bazel_targets=() + while IFS= read -r target; do + bazel_targets+=("${target}") + done <<< "${bazel_target_lines}" + + ./.github/scripts/run-bazel-ci.sh \ + "${bazel_wrapper_args[@]}" \ + -- \ + build \ + "${bazel_build_args[@]}" \ + -- \ + "${bazel_targets[@]}" + + - name: Upload Bazel execution logs + if: always() && !cancelled() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: bazel-execution-logs-verify-release-build-${{ matrix.target }} + path: ${{ runner.temp }}/bazel-execution-logs + if-no-files-found: ignore + + # Save the Bazel repository cache after every non-cancelled run. Keep the + # upload non-fatal so cache service issues never fail the job itself. + - name: Save bazel repository cache + if: always() && !cancelled() continue-on-error: true uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 with: diff --git a/scripts/list-bazel-release-targets.sh b/scripts/list-bazel-release-targets.sh new file mode 100644 index 000000000..900f58b02 --- /dev/null +++ b/scripts/list-bazel-release-targets.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "${repo_root}" + +# Keep this list focused on first-party Rust targets whose compile surface can +# differ when `cfg(not(debug_assertions))` becomes active. +# +# Exclude the experimental `v8-poc` target because it pulls in expensive V8 +# build machinery that is unrelated to the release-only Rust regression this +# workflow is meant to catch. +printf '%s\n' \ + "//codex-rs/..." \ + "-//codex-rs/v8-poc:all"