name: rust-ci on: pull_request: {} push: branches: - main workflow_dispatch: # CI builds in debug (dev) for faster signal. jobs: # --- Detect what changed to detect which tests to run (always runs) ------------------------------------- changed: name: Detect changed areas runs-on: ubuntu-24.04 outputs: argument_comment_lint: ${{ steps.detect.outputs.argument_comment_lint }} argument_comment_lint_package: ${{ steps.detect.outputs.argument_comment_lint_package }} codex: ${{ steps.detect.outputs.codex }} workflows: ${{ steps.detect.outputs.workflows }} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Detect changed paths (no external action) id: detect shell: bash run: | set -euo pipefail if [[ "${{ github.event_name }}" == "pull_request" ]]; then BASE_SHA='${{ github.event.pull_request.base.sha }}' HEAD_SHA='${{ github.event.pull_request.head.sha }}' echo "Base SHA: $BASE_SHA" echo "Head SHA: $HEAD_SHA" # List files changed between base and PR head mapfile -t files < <(git diff --name-only --no-renames "$BASE_SHA" "$HEAD_SHA") else # On push / manual runs, default to running everything files=("codex-rs/force" ".github/force") fi codex=false argument_comment_lint=false argument_comment_lint_package=false workflows=false for f in "${files[@]}"; do [[ $f == codex-rs/* ]] && codex=true [[ $f == codex-rs/* || $f == tools/argument-comment-lint/* || $f == justfile ]] && argument_comment_lint=true [[ $f == tools/argument-comment-lint/* || $f == .github/workflows/rust-ci.yml ]] && argument_comment_lint_package=true [[ $f == .github/* ]] && workflows=true done echo "argument_comment_lint=$argument_comment_lint" >> "$GITHUB_OUTPUT" echo "argument_comment_lint_package=$argument_comment_lint_package" >> "$GITHUB_OUTPUT" echo "codex=$codex" >> "$GITHUB_OUTPUT" echo "workflows=$workflows" >> "$GITHUB_OUTPUT" # --- CI that doesn't need specific targets --------------------------------- general: name: Format / etc runs-on: ubuntu-24.04 needs: changed if: ${{ needs.changed.outputs.codex == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }} defaults: run: working-directory: codex-rs steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@1.93.0 with: components: rustfmt - name: cargo fmt run: cargo fmt -- --config imports_granularity=Item --check cargo_shear: name: cargo shear runs-on: ubuntu-24.04 needs: changed if: ${{ needs.changed.outputs.codex == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }} defaults: run: working-directory: codex-rs steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@1.93.0 - uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2 with: tool: cargo-shear version: 1.5.1 - name: cargo shear run: cargo shear argument_comment_lint_package: name: Argument comment lint package runs-on: ubuntu-24.04 needs: changed if: ${{ needs.changed.outputs.argument_comment_lint_package == 'true' || github.event_name == 'push' }} steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@1.93.0 with: toolchain: nightly-2025-09-18 components: llvm-tools-preview, rustc-dev, rust-src - name: Cache cargo-dylint tooling id: cargo_dylint_cache uses: actions/cache@v5 with: path: | ~/.cargo/bin/cargo-dylint ~/.cargo/bin/dylint-link ~/.cargo/registry/index ~/.cargo/registry/cache ~/.cargo/git/db key: argument-comment-lint-${{ runner.os }}-${{ hashFiles('tools/argument-comment-lint/Cargo.lock', 'tools/argument-comment-lint/rust-toolchain', '.github/workflows/rust-ci.yml') }} - name: Install cargo-dylint tooling if: ${{ steps.cargo_dylint_cache.outputs.cache-hit != 'true' }} run: cargo install --locked cargo-dylint dylint-link - name: Check source wrapper syntax run: bash -n tools/argument-comment-lint/run.sh - name: Test argument comment lint package working-directory: tools/argument-comment-lint run: cargo test argument_comment_lint_prebuilt: name: Argument comment lint - ${{ matrix.name }} runs-on: ${{ matrix.runs_on || matrix.runner }} needs: changed if: ${{ needs.changed.outputs.argument_comment_lint == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }} strategy: fail-fast: false matrix: include: - name: Linux runner: ubuntu-24.04 - name: macOS runner: macos-15-xlarge - name: Windows runner: windows-x64 runs_on: group: codex-runners labels: codex-windows-x64 steps: - uses: actions/checkout@v6 - name: Install Linux sandbox build dependencies if: ${{ runner.os == 'Linux' }} shell: bash run: | sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends pkg-config libcap-dev - uses: dtolnay/rust-toolchain@1.93.0 with: toolchain: nightly-2025-09-18 components: llvm-tools-preview, rustc-dev, rust-src - uses: facebook/install-dotslash@v2 - name: Run argument comment lint on codex-rs shell: bash run: ./tools/argument-comment-lint/run-prebuilt-linter.sh # --- CI to validate on different os/targets -------------------------------- lint_build: name: Lint/Build — ${{ matrix.runner }} - ${{ matrix.target }}${{ matrix.profile == 'release' && ' (release)' || '' }} runs-on: ${{ matrix.runs_on || matrix.runner }} timeout-minutes: 30 needs: changed # Keep job-level if to avoid spinning up runners when not needed if: ${{ needs.changed.outputs.codex == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }} defaults: run: working-directory: codex-rs env: # Speed up repeated builds across CI runs by caching compiled objects, except on # arm64 macOS runners cross-targeting x86_64 where ring/cc-rs can produce # mixed-architecture archives under sccache. USE_SCCACHE: ${{ (startsWith(matrix.runner, 'windows') || (matrix.runner == 'macos-15-xlarge' && matrix.target == 'x86_64-apple-darwin')) && 'false' || 'true' }} CARGO_INCREMENTAL: "0" SCCACHE_CACHE_SIZE: 10G # In rust-ci, representative release-profile checks use thin LTO for faster feedback. CARGO_PROFILE_RELEASE_LTO: ${{ matrix.profile == 'release' && 'thin' || 'fat' }} strategy: fail-fast: false matrix: include: - runner: macos-15-xlarge target: aarch64-apple-darwin profile: dev - runner: macos-15-xlarge target: x86_64-apple-darwin profile: dev - runner: ubuntu-24.04 target: x86_64-unknown-linux-musl profile: dev runs_on: group: codex-runners labels: codex-linux-x64 - runner: ubuntu-24.04 target: x86_64-unknown-linux-gnu profile: dev runs_on: group: codex-runners labels: codex-linux-x64 - runner: ubuntu-24.04-arm target: aarch64-unknown-linux-musl profile: dev runs_on: group: codex-runners labels: codex-linux-arm64 - runner: ubuntu-24.04-arm target: aarch64-unknown-linux-gnu profile: dev runs_on: group: codex-runners labels: codex-linux-arm64 - runner: windows-x64 target: x86_64-pc-windows-msvc profile: dev runs_on: group: codex-runners labels: codex-windows-x64 - runner: windows-arm64 target: aarch64-pc-windows-msvc profile: dev runs_on: group: codex-runners labels: codex-windows-arm64 # Also run representative release builds on Mac and Linux because # there could be release-only build errors we want to catch. # Hopefully this also pre-populates the build cache to speed up # releases. - runner: macos-15-xlarge target: aarch64-apple-darwin profile: release - runner: ubuntu-24.04 target: x86_64-unknown-linux-musl profile: release runs_on: group: codex-runners labels: codex-linux-x64 - runner: ubuntu-24.04-arm target: aarch64-unknown-linux-musl profile: release runs_on: group: codex-runners labels: codex-linux-arm64 - runner: windows-x64 target: x86_64-pc-windows-msvc profile: release runs_on: group: codex-runners labels: codex-windows-x64 - runner: windows-arm64 target: aarch64-pc-windows-msvc profile: release runs_on: group: codex-runners labels: codex-windows-arm64 steps: - uses: actions/checkout@v6 - name: Install Linux build dependencies if: ${{ runner.os == 'Linux' }} shell: bash run: | set -euo pipefail if command -v apt-get >/dev/null 2>&1; then sudo apt-get update -y packages=(pkg-config libcap-dev) if [[ "${{ matrix.target }}" == 'x86_64-unknown-linux-musl' || "${{ matrix.target }}" == 'aarch64-unknown-linux-musl' ]]; then packages+=(libubsan1) fi sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}" fi - uses: dtolnay/rust-toolchain@1.93.0 with: targets: ${{ matrix.target }} components: clippy - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Use hermetic Cargo home (musl) shell: bash run: | set -euo pipefail cargo_home="${GITHUB_WORKSPACE}/.cargo-home" mkdir -p "${cargo_home}/bin" echo "CARGO_HOME=${cargo_home}" >> "$GITHUB_ENV" echo "${cargo_home}/bin" >> "$GITHUB_PATH" : > "${cargo_home}/config.toml" - name: Compute lockfile hash id: lockhash working-directory: codex-rs shell: bash run: | set -euo pipefail echo "hash=$(sha256sum Cargo.lock | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" echo "toolchain_hash=$(sha256sum rust-toolchain.toml | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" # Explicit cache restore: split cargo home vs target, so we can # avoid caching the large target dir on the gnu-dev job. - name: Restore cargo home cache id: cache_cargo_home_restore uses: actions/cache/restore@v5 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ ${{ github.workspace }}/.cargo-home/bin/ ${{ github.workspace }}/.cargo-home/registry/index/ ${{ github.workspace }}/.cargo-home/registry/cache/ ${{ github.workspace }}/.cargo-home/git/db/ key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ steps.lockhash.outputs.toolchain_hash }} restore-keys: | cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}- # Install and restore sccache cache - name: Install sccache if: ${{ env.USE_SCCACHE == 'true' }} uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2 with: tool: sccache version: 0.7.5 - name: Configure sccache backend if: ${{ env.USE_SCCACHE == 'true' }} shell: bash run: | set -euo pipefail if [[ -n "${ACTIONS_CACHE_URL:-}" && -n "${ACTIONS_RUNTIME_TOKEN:-}" ]]; then echo "SCCACHE_GHA_ENABLED=true" >> "$GITHUB_ENV" echo "Using sccache GitHub backend" else echo "SCCACHE_GHA_ENABLED=false" >> "$GITHUB_ENV" echo "SCCACHE_DIR=${{ github.workspace }}/.sccache" >> "$GITHUB_ENV" echo "Using sccache local disk + actions/cache fallback" fi - name: Enable sccache wrapper if: ${{ env.USE_SCCACHE == 'true' }} shell: bash run: echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV" - name: Restore sccache cache (fallback) if: ${{ env.USE_SCCACHE == 'true' && env.SCCACHE_GHA_ENABLED != 'true' }} id: cache_sccache_restore uses: actions/cache/restore@v5 with: path: ${{ github.workspace }}/.sccache/ key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ github.run_id }} restore-keys: | sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}- sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}- - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Disable sccache wrapper (musl) shell: bash run: | set -euo pipefail echo "RUSTC_WRAPPER=" >> "$GITHUB_ENV" echo "RUSTC_WORKSPACE_WRAPPER=" >> "$GITHUB_ENV" - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Prepare APT cache directories (musl) shell: bash run: | set -euo pipefail sudo mkdir -p /var/cache/apt/archives /var/lib/apt/lists sudo chown -R "$USER:$USER" /var/cache/apt /var/lib/apt/lists - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Restore APT cache (musl) id: cache_apt_restore uses: actions/cache/restore@v5 with: path: | /var/cache/apt key: apt-${{ matrix.runner }}-${{ matrix.target }}-v1 - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Install Zig uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2 with: version: 0.14.0 - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Install musl build tools env: DEBIAN_FRONTEND: noninteractive TARGET: ${{ matrix.target }} APT_UPDATE_ARGS: -o Acquire::Retries=3 APT_INSTALL_ARGS: --no-install-recommends shell: bash run: bash "${GITHUB_WORKSPACE}/.github/scripts/install-musl-build-tools.sh" - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Configure rustc UBSan wrapper (musl host) shell: bash run: | set -euo pipefail ubsan="" if command -v ldconfig >/dev/null 2>&1; then ubsan="$(ldconfig -p | grep -m1 'libubsan\.so\.1' | sed -E 's/.*=> (.*)$/\1/')" fi wrapper_root="${RUNNER_TEMP:-/tmp}" wrapper="${wrapper_root}/rustc-ubsan-wrapper" cat > "${wrapper}" <> "$GITHUB_ENV" echo "RUSTC_WORKSPACE_WRAPPER=" >> "$GITHUB_ENV" - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}} name: Clear sanitizer flags (musl) shell: bash run: | set -euo pipefail # Clear global Rust flags so host/proc-macro builds don't pull in UBSan. echo "RUSTFLAGS=" >> "$GITHUB_ENV" echo "CARGO_ENCODED_RUSTFLAGS=" >> "$GITHUB_ENV" echo "RUSTDOCFLAGS=" >> "$GITHUB_ENV" # Override any runner-level Cargo config rustflags as well. echo "CARGO_BUILD_RUSTFLAGS=" >> "$GITHUB_ENV" echo "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS=" >> "$GITHUB_ENV" echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS=" >> "$GITHUB_ENV" echo "CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS=" >> "$GITHUB_ENV" echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS=" >> "$GITHUB_ENV" sanitize_flags() { local input="$1" input="${input//-fsanitize=undefined/}" input="${input//-fno-sanitize-recover=undefined/}" input="${input//-fno-sanitize-trap=undefined/}" echo "$input" } cflags="$(sanitize_flags "${CFLAGS-}")" cxxflags="$(sanitize_flags "${CXXFLAGS-}")" echo "CFLAGS=${cflags}" >> "$GITHUB_ENV" echo "CXXFLAGS=${cxxflags}" >> "$GITHUB_ENV" - if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl' }} name: Configure musl rusty_v8 artifact overrides env: TARGET: ${{ matrix.target }} shell: bash run: | set -euo pipefail version="$(python3 "${GITHUB_WORKSPACE}/.github/scripts/rusty_v8_bazel.py" resolved-v8-crate-version)" release_tag="rusty-v8-v${version}" base_url="https://github.com/openai/codex/releases/download/${release_tag}" archive="https://github.com/openai/codex/releases/download/rusty-v8-v${version}/librusty_v8_release_${TARGET}.a.gz" binding_dir="${RUNNER_TEMP}/rusty_v8" binding_path="${binding_dir}/src_binding_release_${TARGET}.rs" mkdir -p "${binding_dir}" curl -fsSL "${base_url}/src_binding_release_${TARGET}.rs" -o "${binding_path}" echo "RUSTY_V8_ARCHIVE=${archive}" >> "$GITHUB_ENV" echo "RUSTY_V8_SRC_BINDING_PATH=${binding_path}" >> "$GITHUB_ENV" - name: Install cargo-chef if: ${{ matrix.profile == 'release' }} uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2 with: tool: cargo-chef version: 0.1.71 - name: Pre-warm dependency cache (cargo-chef) if: ${{ matrix.profile == 'release' }} shell: bash run: | set -euo pipefail RECIPE="${RUNNER_TEMP}/chef-recipe.json" cargo chef prepare --recipe-path "$RECIPE" cargo chef cook --recipe-path "$RECIPE" --target ${{ matrix.target }} --release --all-features - name: cargo clippy run: cargo clippy --target ${{ matrix.target }} --all-features --tests --profile ${{ matrix.profile }} --timings -- -D warnings - name: Upload Cargo timings (clippy) if: always() uses: actions/upload-artifact@v7 with: name: cargo-timings-rust-ci-clippy-${{ matrix.target }}-${{ matrix.profile }} path: codex-rs/target/**/cargo-timings/cargo-timing.html if-no-files-found: warn # Save caches explicitly; make non-fatal so cache packaging # never fails the overall job. Only save when key wasn't hit. - name: Save cargo home cache if: always() && !cancelled() && steps.cache_cargo_home_restore.outputs.cache-hit != 'true' continue-on-error: true uses: actions/cache/save@v5 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ ${{ github.workspace }}/.cargo-home/bin/ ${{ github.workspace }}/.cargo-home/registry/index/ ${{ github.workspace }}/.cargo-home/registry/cache/ ${{ github.workspace }}/.cargo-home/git/db/ key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ steps.lockhash.outputs.toolchain_hash }} - name: Save sccache cache (fallback) if: always() && !cancelled() && env.USE_SCCACHE == 'true' && env.SCCACHE_GHA_ENABLED != 'true' continue-on-error: true uses: actions/cache/save@v5 with: path: ${{ github.workspace }}/.sccache/ key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ github.run_id }} - name: sccache stats if: always() && env.USE_SCCACHE == 'true' continue-on-error: true run: sccache --show-stats || true - name: sccache summary if: always() && env.USE_SCCACHE == 'true' shell: bash run: | { echo "### sccache stats — ${{ matrix.target }} (${{ matrix.profile }})"; echo; echo '```'; sccache --show-stats || true; echo '```'; } >> "$GITHUB_STEP_SUMMARY" - name: Save APT cache (musl) if: always() && !cancelled() && (matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl') && steps.cache_apt_restore.outputs.cache-hit != 'true' continue-on-error: true uses: actions/cache/save@v5 with: path: | /var/cache/apt key: apt-${{ matrix.runner }}-${{ matrix.target }}-v1 tests: name: Tests — ${{ matrix.runner }} - ${{ matrix.target }}${{ matrix.remote_env == 'true' && ' (remote)' || '' }} runs-on: ${{ matrix.runs_on || matrix.runner }} timeout-minutes: 30 needs: changed if: ${{ needs.changed.outputs.codex == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }} defaults: run: working-directory: codex-rs env: # Speed up repeated builds across CI runs by caching compiled objects, except on # arm64 macOS runners cross-targeting x86_64 where ring/cc-rs can produce # mixed-architecture archives under sccache. USE_SCCACHE: ${{ (startsWith(matrix.runner, 'windows') || (matrix.runner == 'macos-15-xlarge' && matrix.target == 'x86_64-apple-darwin')) && 'false' || 'true' }} CARGO_INCREMENTAL: "0" SCCACHE_CACHE_SIZE: 10G strategy: fail-fast: false matrix: include: - runner: macos-15-xlarge target: aarch64-apple-darwin profile: dev - runner: ubuntu-24.04 target: x86_64-unknown-linux-gnu profile: dev remote_env: "true" runs_on: group: codex-runners labels: codex-linux-x64 - runner: ubuntu-24.04-arm target: aarch64-unknown-linux-gnu profile: dev runs_on: group: codex-runners labels: codex-linux-arm64 - runner: windows-x64 target: x86_64-pc-windows-msvc profile: dev runs_on: group: codex-runners labels: codex-windows-x64 - runner: windows-arm64 target: aarch64-pc-windows-msvc profile: dev runs_on: group: codex-runners labels: codex-windows-arm64 steps: - uses: actions/checkout@v6 - name: Set up Node.js for js_repl tests uses: actions/setup-node@v6 with: node-version-file: codex-rs/node-version.txt - name: Install Linux build dependencies if: ${{ runner.os == 'Linux' }} shell: bash run: | set -euo pipefail if command -v apt-get >/dev/null 2>&1; then sudo apt-get update -y sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends pkg-config libcap-dev fi # Some integration tests rely on DotSlash being installed. # See https://github.com/openai/codex/pull/7617. - name: Install DotSlash uses: facebook/install-dotslash@v2 - uses: dtolnay/rust-toolchain@1.93.0 with: targets: ${{ matrix.target }} - name: Compute lockfile hash id: lockhash working-directory: codex-rs shell: bash run: | set -euo pipefail echo "hash=$(sha256sum Cargo.lock | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" echo "toolchain_hash=$(sha256sum rust-toolchain.toml | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" - name: Restore cargo home cache id: cache_cargo_home_restore uses: actions/cache/restore@v5 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ steps.lockhash.outputs.toolchain_hash }} restore-keys: | cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}- - name: Install sccache if: ${{ env.USE_SCCACHE == 'true' }} uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2 with: tool: sccache version: 0.7.5 - name: Configure sccache backend if: ${{ env.USE_SCCACHE == 'true' }} shell: bash run: | set -euo pipefail if [[ -n "${ACTIONS_CACHE_URL:-}" && -n "${ACTIONS_RUNTIME_TOKEN:-}" ]]; then echo "SCCACHE_GHA_ENABLED=true" >> "$GITHUB_ENV" echo "Using sccache GitHub backend" else echo "SCCACHE_GHA_ENABLED=false" >> "$GITHUB_ENV" echo "SCCACHE_DIR=${{ github.workspace }}/.sccache" >> "$GITHUB_ENV" echo "Using sccache local disk + actions/cache fallback" fi - name: Enable sccache wrapper if: ${{ env.USE_SCCACHE == 'true' }} shell: bash run: echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV" - name: Restore sccache cache (fallback) if: ${{ env.USE_SCCACHE == 'true' && env.SCCACHE_GHA_ENABLED != 'true' }} id: cache_sccache_restore uses: actions/cache/restore@v5 with: path: ${{ github.workspace }}/.sccache/ key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ github.run_id }} restore-keys: | sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}- sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}- - uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2 with: tool: nextest version: 0.9.103 - name: Enable unprivileged user namespaces (Linux) if: runner.os == 'Linux' run: | # Required for bubblewrap to work on Linux CI runners. sudo sysctl -w kernel.unprivileged_userns_clone=1 # Ubuntu 24.04+ can additionally gate unprivileged user namespaces # behind AppArmor. if sudo sysctl -a 2>/dev/null | grep -q '^kernel.apparmor_restrict_unprivileged_userns'; then sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 fi - name: Set up remote test env (Docker) if: ${{ runner.os == 'Linux' && matrix.remote_env == 'true' }} shell: bash run: | set -euo pipefail export CODEX_TEST_REMOTE_ENV_CONTAINER_NAME=codex-remote-test-env source "${GITHUB_WORKSPACE}/scripts/test-remote-env.sh" echo "CODEX_TEST_REMOTE_ENV=${CODEX_TEST_REMOTE_ENV}" >> "$GITHUB_ENV" - name: tests id: test run: cargo nextest run --all-features --no-fail-fast --target ${{ matrix.target }} --cargo-profile ci-test --timings env: RUST_BACKTRACE: 1 NEXTEST_STATUS_LEVEL: leak - name: Upload Cargo timings (nextest) if: always() uses: actions/upload-artifact@v7 with: name: cargo-timings-rust-ci-nextest-${{ matrix.target }}-${{ matrix.profile }} path: codex-rs/target/**/cargo-timings/cargo-timing.html if-no-files-found: warn - name: Save cargo home cache if: always() && !cancelled() && steps.cache_cargo_home_restore.outputs.cache-hit != 'true' continue-on-error: true uses: actions/cache/save@v5 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ steps.lockhash.outputs.toolchain_hash }} - name: Save sccache cache (fallback) if: always() && !cancelled() && env.USE_SCCACHE == 'true' && env.SCCACHE_GHA_ENABLED != 'true' continue-on-error: true uses: actions/cache/save@v5 with: path: ${{ github.workspace }}/.sccache/ key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ steps.lockhash.outputs.hash }}-${{ github.run_id }} - name: sccache stats if: always() && env.USE_SCCACHE == 'true' continue-on-error: true run: sccache --show-stats || true - name: sccache summary if: always() && env.USE_SCCACHE == 'true' shell: bash run: | { echo "### sccache stats — ${{ matrix.target }} (tests)"; echo; echo '```'; sccache --show-stats || true; echo '```'; } >> "$GITHUB_STEP_SUMMARY" - name: Tear down remote test env if: ${{ always() && runner.os == 'Linux' && matrix.remote_env == 'true' }} shell: bash run: | set +e if [[ "${{ steps.test.outcome }}" != "success" ]]; then docker logs codex-remote-test-env || true fi docker rm -f codex-remote-test-env >/dev/null 2>&1 || true - name: verify tests passed if: steps.test.outcome == 'failure' run: | echo "Tests failed. See logs for details." exit 1 # --- Gatherer job that you mark as the ONLY required status ----------------- results: name: CI results (required) needs: [ changed, general, cargo_shear, argument_comment_lint_package, argument_comment_lint_prebuilt, lint_build, tests, ] if: always() runs-on: ubuntu-24.04 steps: - name: Summarize shell: bash run: | echo "argpkg : ${{ needs.argument_comment_lint_package.result }}" echo "arglint: ${{ needs.argument_comment_lint_prebuilt.result }}" echo "general: ${{ needs.general.result }}" echo "shear : ${{ needs.cargo_shear.result }}" echo "lint : ${{ needs.lint_build.result }}" echo "tests : ${{ needs.tests.result }}" # If nothing relevant changed (PR touching only root README, etc.), # declare success regardless of other jobs. if [[ '${{ needs.changed.outputs.argument_comment_lint }}' != 'true' && '${{ needs.changed.outputs.codex }}' != 'true' && '${{ needs.changed.outputs.workflows }}' != 'true' && '${{ github.event_name }}' != 'push' ]]; then echo 'No relevant changes -> CI not required.' exit 0 fi if [[ '${{ needs.changed.outputs.argument_comment_lint_package }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then [[ '${{ needs.argument_comment_lint_package.result }}' == 'success' ]] || { echo 'argument_comment_lint_package failed'; exit 1; } fi if [[ '${{ needs.changed.outputs.argument_comment_lint }}' == 'true' || '${{ needs.changed.outputs.workflows }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then [[ '${{ needs.argument_comment_lint_prebuilt.result }}' == 'success' ]] || { echo 'argument_comment_lint_prebuilt failed'; exit 1; } fi if [[ '${{ needs.changed.outputs.codex }}' == 'true' || '${{ needs.changed.outputs.workflows }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then [[ '${{ needs.general.result }}' == 'success' ]] || { echo 'general failed'; exit 1; } [[ '${{ needs.cargo_shear.result }}' == 'success' ]] || { echo 'cargo_shear failed'; exit 1; } [[ '${{ needs.lint_build.result }}' == 'success' ]] || { echo 'lint_build failed'; exit 1; } [[ '${{ needs.tests.result }}' == 'success' ]] || { echo 'tests failed'; exit 1; } fi - name: sccache summary note if: always() run: | echo "Per-job sccache stats are attached to each matrix job's Step Summary."