From 64ef6cd1e4d17c9c2aaa424e65d90011c64fd1c2 Mon Sep 17 00:00:00 2001 From: starr-openai Date: Tue, 19 May 2026 17:54:41 -0700 Subject: [PATCH] Fan out rust-ci-full nextest by platform (#23358) ## Why `rust-ci-full` was paying the full Cargo nextest build-and-run cost once per platform, with Windows ARM64 as the long pole. This change moves the heavy work into one reusable per-platform flow: build a nextest archive once, then replay it across four shards so the platform lane spends less time running tests serially. For Windows ARM64, the archive is cross-compiled on Windows x64 and replayed on native Windows ARM64 shards so the slow ARM64 machine is used for execution rather than compilation. ## What changed - split the `rust-ci-full` nextest matrix into five explicit per-platform reusable-workflow calls - add `.github/workflows/rust-ci-full-nextest-platform.yml` to build one archive, upload timings/helpers, replay four nextest shards, upload per-shard JUnit, and roll the shard status back up per platform - add Windows CI helpers for Dev Drive setup and MSVC ARM64 linker environment export so the Windows ARM64 archive can be produced on Windows x64 - keep the existing Cargo git CLI fetch hardening inside the reusable workflow, since caller workflow-level `env` does not flow through `workflow_call` - document the archive-backed shard shape in `.github/workflows/README.md` - raise the default nextest slow timeout to 30s so the sharded full-CI path does not treat every >15s test as stuck ## Verification - validated the archive/shard flow with live GitHub Actions runs on this PR branch - Windows ARM64 cross-compile latency on completed runs: - https://github.com/openai/codex/actions/runs/26118759651: `34m30s` lane e2e, `17m16s` archive build, `9m55s` shard phase - https://github.com/openai/codex/actions/runs/26120777976: `30m36s` lane e2e, `17m21s` archive build, `6m50s` shard phase - comparable pre-cross-compile sharded Windows ARM64 runs were `55m01s`, `50m21s`, and `46m42s`, so the completed cross-compile runs improved the lane by roughly `12m` to `24m` versus the prior range - latest corrected cross-compile run: https://github.com/openai/codex/actions/runs/26120777976 - Windows ARM64 archive built successfully on Windows x64 - native Windows ARM64 shards started immediately after the archive upload - 3/4 Windows ARM64 shards passed; the failing shard hit the same existing `code_mode` test failure seen outside this lane - downloaded failed-shard JUnit XML from the validation runs and confirmed the remaining red is from known test failures, not archive/shard wiring - no local Codex tests run per repo guidance ## Notes - this PR does not change developers.openai.com documentation --- .github/actions/setup-msvc-env/action.yml | 17 + .../actions/setup-msvc-env/setup-msvc-env.ps1 | 257 ++++++++++ .github/scripts/setup-dev-drive.ps1 | 62 +++ .github/workflows/README.md | 3 +- .../rust-ci-full-nextest-platform.yml | 464 ++++++++++++++++++ .github/workflows/rust-ci-full.yml | 313 +++--------- codex-rs/.config/nextest.toml | 4 +- 7 files changed, 883 insertions(+), 237 deletions(-) create mode 100644 .github/actions/setup-msvc-env/action.yml create mode 100644 .github/actions/setup-msvc-env/setup-msvc-env.ps1 create mode 100644 .github/scripts/setup-dev-drive.ps1 create mode 100644 .github/workflows/rust-ci-full-nextest-platform.yml diff --git a/.github/actions/setup-msvc-env/action.yml b/.github/actions/setup-msvc-env/action.yml new file mode 100644 index 0000000000..287cb7f217 --- /dev/null +++ b/.github/actions/setup-msvc-env/action.yml @@ -0,0 +1,17 @@ +name: setup-msvc-env +description: Expose an MSVC developer environment for the requested Windows target. +inputs: + target: + description: Rust target triple that will be built on this Windows runner. + required: true + host-arch: + description: Optional Visual Studio host architecture override. + required: false + default: "" + +runs: + using: composite + steps: + - name: Expose MSVC SDK environment + shell: pwsh + run: '& "$env:GITHUB_ACTION_PATH/setup-msvc-env.ps1" -Target "${{ inputs.target }}" -HostArch "${{ inputs.host-arch }}"' diff --git a/.github/actions/setup-msvc-env/setup-msvc-env.ps1 b/.github/actions/setup-msvc-env/setup-msvc-env.ps1 new file mode 100644 index 0000000000..e2706d9117 --- /dev/null +++ b/.github/actions/setup-msvc-env/setup-msvc-env.ps1 @@ -0,0 +1,257 @@ +param( + [Parameter(Mandatory = $true)] + [string]$Target, + + [string]$HostArch = "" +) + +# Cargo can cross-compile the Rust code for Windows ARM64 on a Windows x64 +# runner, but rustup alone does not expose the matching MSVC/UCRT include and +# library paths. Ask Visual Studio for the target-specific developer +# environment, then persist the relevant variables through GITHUB_ENV so the +# later Cargo step sees the same environment as a normal VsDevCmd shell. +switch ($Target) { + "x86_64-pc-windows-msvc" { + $TargetArch = "x64" + $RequiredComponent = "Microsoft.VisualStudio.Component.VC.Tools.x86.x64" + } + "aarch64-pc-windows-msvc" { + $TargetArch = "arm64" + $RequiredComponent = "Microsoft.VisualStudio.Component.VC.Tools.ARM64" + } + default { + throw "Unsupported Windows MSVC target: $Target" + } +} + +# VsDevCmd needs both sides of the cross compile: the architecture of the +# machine running the tools and the architecture of the binaries being linked. +# Infer the host from the runner unless a caller needs to override it. +if (-not $HostArch) { + $HostArch = if ($env:PROCESSOR_ARCHITEW6432 -eq "ARM64" -or $env:PROCESSOR_ARCHITECTURE -eq "ARM64") { + "arm64" + } else { + "x64" + } +} + +$VsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" +if (-not (Test-Path $VsWhere)) { + throw "vswhere.exe not found" +} + +# Require the target VC tools component, not merely any Visual Studio install, +# so an x64 archive producer cannot silently link ARM64 tests with the wrong +# SDK/toolchain layout. +$InstallPath = & $VsWhere -latest -products * -requires $RequiredComponent -property installationPath 2>$null +if (-not $InstallPath) { + throw "Could not locate a Visual Studio installation with component $RequiredComponent" +} + +$VsDevCmd = Join-Path $InstallPath "Common7\Tools\VsDevCmd.bat" +if (-not (Test-Path $VsDevCmd)) { + throw "VsDevCmd.bat not found at $VsDevCmd" +} + +$VarsToExport = @( + "INCLUDE", + "LIB", + "LIBPATH", + "PATH", + "UCRTVersion", + "UniversalCRTSdkDir", + "VCINSTALLDIR", + "VCToolsInstallDir", + "WindowsLibPath", + "WindowsSdkBinPath", + "WindowsSdkDir", + "WindowsSDKLibVersion", + "WindowsSDKVersion" +) + +# Run VsDevCmd inside cmd.exe because it is a batch file, then copy just the +# variables Cargo/rustc need into the GitHub Actions environment file. PowerShell +# cannot mutate the parent composite-action environment directly. +$EnvLines = & cmd.exe /c ('"{0}" -no_logo -arch={1} -host_arch={2} >nul && set' -f $VsDevCmd, $TargetArch, $HostArch) +$VcToolsInstallDir = $null +foreach ($Line in $EnvLines) { + if ($Line -notmatch "^(.*?)=(.*)$") { + continue + } + + $Name = $Matches[1] + $Value = $Matches[2] + if ($VarsToExport -contains $Name) { + if ($Name -ieq "Path") { + $Name = "PATH" + } + if ($Name -eq "VCToolsInstallDir") { + $VcToolsInstallDir = $Value + } + "$Name=$Value" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + } +} + +if (-not $VcToolsInstallDir) { + throw "VCToolsInstallDir was not exported by VsDevCmd.bat" +} + +# Prefer Rust's bundled linker when rustup provides one, then Visual Studio's +# LLVM linker, and finally MSVC link.exe. This keeps the cross-compile path close +# to Rust's normal Windows MSVC behavior while still working on runner images +# where one of those linkers is absent. +$Linker = $null +$Rustc = Get-Command rustc -ErrorAction SilentlyContinue +if ($Rustc) { + $Sysroot = (& rustc --print sysroot 2>$null).Trim() + $RustHost = & rustc -vV 2>$null | Select-String "^host: " | ForEach-Object { $_.Line.Substring(6) } + if ($RustHost) { + $RustHost = $RustHost.Trim() + } + if ($Sysroot -and $RustHost) { + $RustLld = Join-Path $Sysroot "lib\rustlib\$RustHost\bin\rust-lld.exe" + if (Test-Path $RustLld) { + $Linker = $RustLld + } + } +} +if (-not $Linker) { + $Linker = Join-Path $InstallPath "VC\Tools\Llvm\x64\bin\lld-link.exe" +} +if (-not (Test-Path $Linker)) { + $Linker = Join-Path $VcToolsInstallDir "bin\Host${HostArch}\${TargetArch}\link.exe" +} +if (-not (Test-Path $Linker)) { + throw "Windows linker not found at $Linker" +} + +# rustc passes `/arm64hazardfree` for ARM64 MSVC links. The lld variants on our +# Windows x64 archive producers reject that flag, including when rustc places it +# inside a response file. Compile a tiny forwarding wrapper that strips only +# that unsupported flag, then delegate every other argument to the real linker. +if ($TargetArch -eq "arm64" -and (Split-Path -Leaf $Linker) -match "lld") { + $WrapperDir = Join-Path $env:RUNNER_TEMP "msvc-lld-wrapper" + New-Item -Path $WrapperDir -ItemType Directory -Force | Out-Null + $WrapperPath = Join-Path $WrapperDir "lld-link-wrapper.exe" + $WrapperSource = @' +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +internal static class Program +{ + private static int Main(string[] args) + { + var linker = Environment.GetEnvironmentVariable("MSVC_REAL_LINKER"); + if (string.IsNullOrEmpty(linker)) + { + Console.Error.WriteLine("MSVC_REAL_LINKER is not set"); + return 1; + } + + var startInfo = new ProcessStartInfo(linker) + { + UseShellExecute = false, + }; + var filteredArgs = new List { "-flavor", "link", "/defaultlib:ucrt", "/nodefaultlib:libucrt" }; + foreach (var arg in args) + { + if (!string.Equals(arg, "/arm64hazardfree", StringComparison.OrdinalIgnoreCase)) + { + filteredArgs.Add(QuoteArgument(FilterResponseFile(arg))); + } + } + startInfo.Arguments = string.Join(" ", filteredArgs); + + using var process = Process.Start(startInfo); + if (process is null) + { + Console.Error.WriteLine($"Failed to start linker: {linker}"); + return 1; + } + + process.WaitForExit(); + return process.ExitCode; + } + + private static string FilterResponseFile(string argument) + { + if (argument.Length < 2 || argument[0] != '@') + { + return argument; + } + + var responsePath = argument.Substring(1); + if (!File.Exists(responsePath)) + { + return argument; + } + + var filteredResponsePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".rsp"); + var responseContents = Regex.Replace( + File.ReadAllText(responsePath), + "/arm64hazardfree", + string.Empty, + RegexOptions.IgnoreCase); + File.WriteAllText(filteredResponsePath, responseContents); + return "@" + filteredResponsePath; + } + + private static string QuoteArgument(string argument) + { + if (argument.Length == 0) + { + return "\"\""; + } + if (argument.IndexOfAny(new[] { ' ', '\t', '"' }) < 0) + { + return argument; + } + + var quoted = new StringBuilder("\""); + var backslashes = 0; + foreach (var character in argument) + { + if (character == '\\') + { + backslashes++; + continue; + } + if (character == '"') + { + quoted.Append('\\', (backslashes * 2) + 1); + quoted.Append(character); + backslashes = 0; + continue; + } + + quoted.Append('\\', backslashes); + backslashes = 0; + quoted.Append(character); + } + quoted.Append('\\', backslashes * 2); + quoted.Append('"'); + return quoted.ToString(); + } +} +'@ + $WrapperSourcePath = Join-Path $WrapperDir "lld-link-wrapper.cs" + $WrapperSource | Out-File -FilePath $WrapperSourcePath -Encoding utf8 + $Csc = Join-Path $InstallPath "MSBuild\Current\Bin\Roslyn\csc.exe" + if (-not (Test-Path $Csc)) { + throw "csc.exe not found at $Csc" + } + & $Csc /nologo /target:exe /out:$WrapperPath $WrapperSourcePath + if ($LASTEXITCODE -ne 0) { + throw "Failed to compile lld-link wrapper" + } + "MSVC_REAL_LINKER=$Linker" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + $Linker = $WrapperPath +} + +Write-Output "Using Windows linker: $Linker" +$CargoTarget = $Target.ToUpperInvariant().Replace("-", "_") +"CARGO_TARGET_${CargoTarget}_LINKER=$Linker" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append diff --git a/.github/scripts/setup-dev-drive.ps1 b/.github/scripts/setup-dev-drive.ps1 new file mode 100644 index 0000000000..2b94e1b66f --- /dev/null +++ b/.github/scripts/setup-dev-drive.ps1 @@ -0,0 +1,62 @@ +# Configure a fast drive for Windows CI jobs. +# +# GitHub-hosted Windows runners do not always expose a secondary D: volume. When +# they do not, try to create a Dev Drive VHD and fall back to C: if the runner +# image does not allow that provisioning path. + +function Use-FallbackDrive { + param([string]$Reason) + + Write-Warning "$Reason Falling back to C:" + return "C:" +} + +function Invoke-BestEffort { + param([scriptblock]$Script, [string]$Description) + + try { + & $Script + } catch { + Write-Warning "$Description failed: $($_.Exception.Message)" + } +} + +if (Test-Path "D:\") { + Write-Output "Using existing drive at D:" + $Drive = "D:" +} else { + try { + $VhdPath = Join-Path $env:RUNNER_TEMP "codex-dev-drive.vhdx" + $SizeBytes = 64GB + + if (Test-Path $VhdPath) { + Remove-Item -Path $VhdPath -Force + } + + New-VHD -Path $VhdPath -SizeBytes $SizeBytes -Dynamic -ErrorAction Stop | Out-Null + $Mounted = Mount-VHD -Path $VhdPath -Passthru -ErrorAction Stop + $Disk = $Mounted | Get-Disk -ErrorAction Stop + $Disk | Initialize-Disk -PartitionStyle GPT -ErrorAction Stop + $Partition = $Disk | New-Partition -AssignDriveLetter -UseMaximumSize -ErrorAction Stop + $Volume = $Partition | Format-Volume -FileSystem ReFS -NewFileSystemLabel "CodexDevDrive" -DevDrive -Confirm:$false -Force -ErrorAction Stop + + $Drive = "$($Volume.DriveLetter):" + + Invoke-BestEffort { fsutil devdrv trust $Drive } "Trusting Dev Drive $Drive" + Invoke-BestEffort { fsutil devdrv enable /disallowAv } "Disabling AV filter attachment for Dev Drives" + Invoke-BestEffort { fsutil devdrv query $Drive } "Querying Dev Drive $Drive" + + Write-Output "Using Dev Drive at $Drive" + } catch { + $Drive = Use-FallbackDrive "Failed to create Dev Drive: $($_.Exception.Message)" + } +} + +$Tmp = "$Drive\codex-tmp" +New-Item -Path $Tmp -ItemType Directory -Force | Out-Null + +@( + "DEV_DRIVE=$Drive" + "TMP=$Tmp" + "TEMP=$Tmp" +) | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append diff --git a/.github/workflows/README.md b/.github/workflows/README.md index d14817f002..b2403b749c 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -21,7 +21,8 @@ The workflows in this directory are split so that pull requests get fast, review - `rust-ci-full.yml` is the full Cargo-native verification workflow. It keeps the heavier checks off the PR path while still validating them after merge: - the full Cargo `clippy` matrix - - the full Cargo `nextest` matrix + - the full Cargo `nextest` matrix via per-platform archive-backed shards + - Windows ARM64 nextest archives cross-compiled on Windows x64, then replayed on native Windows ARM64 shards - release-profile Cargo builds - cross-platform `argument-comment-lint` - Linux remote-env tests diff --git a/.github/workflows/rust-ci-full-nextest-platform.yml b/.github/workflows/rust-ci-full-nextest-platform.yml new file mode 100644 index 0000000000..7dc39d33ed --- /dev/null +++ b/.github/workflows/rust-ci-full-nextest-platform.yml @@ -0,0 +1,464 @@ +name: rust-ci-full nextest platform + +on: + workflow_call: + inputs: + runner: + required: true + type: string + runner_group: + required: false + default: "" + type: string + runner_labels: + required: false + default: "" + type: string + archive_runner: + required: false + default: "" + type: string + archive_runner_group: + required: false + default: "" + type: string + archive_runner_labels: + required: false + default: "" + type: string + target: + required: true + type: string + profile: + required: true + type: string + artifact_id: + required: true + type: string + remote_env: + required: false + default: false + type: boolean + test_threads: + required: false + default: 0 + type: number + use_sccache: + required: false + default: false + type: boolean + +# Caller workflow-level env does not flow through workflow_call, so keep the +# Cargo git transport hardening on the archive and shard jobs directly here. +env: + CARGO_NET_GIT_FETCH_WITH_CLI: "true" + +jobs: + archive: + name: Build nextest archive + runs-on: ${{ inputs.archive_runner_group != '' && fromJSON(format('{{"group":"{0}","labels":"{1}"}}', inputs.archive_runner_group, inputs.archive_runner_labels)) || inputs.archive_runner != '' && inputs.archive_runner || inputs.runner_group != '' && fromJSON(format('{{"group":"{0}","labels":"{1}"}}', inputs.runner_group, inputs.runner_labels)) || inputs.runner }} + timeout-minutes: 60 + defaults: + run: + working-directory: codex-rs + env: + # Windows ARM64 archives are built on Windows x64, while their shards run + # on native Windows ARM64. Key producer-side caches by the archive runner + # so the cross-compile build reuses the Windows x64 cache lineage. + ARCHIVE_CACHE_RUNNER: ${{ inputs.archive_runner != '' && inputs.archive_runner || inputs.runner }} + USE_SCCACHE: ${{ inputs.use_sccache && 'true' || 'false' }} + CARGO_INCREMENTAL: "0" + SCCACHE_CACHE_SIZE: 10G + NEXTEST_ARCHIVE_FILE: nextest-${{ inputs.artifact_id }}.tar.zst + TEST_HELPERS_ARTIFACT: nextest-test-helpers-${{ inputs.artifact_id }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Configure Dev Drive (Windows) + if: ${{ runner.os == 'Windows' }} + shell: pwsh + run: ../.github/scripts/setup-dev-drive.ps1 + + - 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 bubblewrap + fi + + - name: Install DotSlash + uses: facebook/install-dotslash@1e4e7b3e07eaca387acb98f1d4720e0bee8dbb6a # v2 + + - uses: dtolnay/rust-toolchain@a0b273b48ed29de4470960879e8381ff45632f26 # 1.93.0 + with: + targets: ${{ inputs.target }} + + - name: Expose MSVC SDK environment (Windows) + if: ${{ runner.os == 'Windows' && inputs.target == 'aarch64-pc-windows-msvc' }} + uses: ./.github/actions/setup-msvc-env + with: + target: ${{ inputs.target }} + + - name: Compute lockfile hash + id: lockhash + 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: cargo-home-${{ env.ARCHIVE_CACHE_RUNNER }}-${{ inputs.target }}-${{ inputs.profile }}-${{ steps.lockhash.outputs.hash }}-${{ steps.lockhash.outputs.toolchain_hash }} + restore-keys: | + cargo-home-${{ env.ARCHIVE_CACHE_RUNNER }}-${{ inputs.target }}-${{ inputs.profile }}- + + - name: Install sccache + if: ${{ env.USE_SCCACHE == 'true' }} + uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2.62.49 + 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" + if [[ -n "${DEV_DRIVE:-}" ]]; then + echo "SCCACHE_DIR=${DEV_DRIVE}\\.sccache" >> "$GITHUB_ENV" + else + echo "SCCACHE_DIR=${{ github.workspace }}/.sccache" >> "$GITHUB_ENV" + fi + echo "Using sccache local disk + actions/cache fallback" + fi + + - name: Enable sccache wrapper + if: ${{ env.USE_SCCACHE == 'true' }} + shell: bash + run: | + set -euo pipefail + wrapper="$(command -v sccache)" + if [[ "${RUNNER_OS}" == "Windows" ]] && command -v cygpath >/dev/null 2>&1; then + wrapper="$(cygpath -w "${wrapper}")" + fi + echo "RUSTC_WRAPPER=${wrapper}" >> "$GITHUB_ENV" + echo "CARGO_BUILD_RUSTC_WRAPPER=${wrapper}" >> "$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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: ${{ env.SCCACHE_DIR }} + key: sccache-${{ env.ARCHIVE_CACHE_RUNNER }}-${{ inputs.target }}-${{ inputs.profile }}-${{ steps.lockhash.outputs.hash }}-${{ github.run_id }} + restore-keys: | + sccache-${{ env.ARCHIVE_CACHE_RUNNER }}-${{ inputs.target }}-${{ inputs.profile }}-${{ steps.lockhash.outputs.hash }}- + sccache-${{ env.ARCHIVE_CACHE_RUNNER }}-${{ inputs.target }}-${{ inputs.profile }}- + + - uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2.62.49 + with: + tool: nextest + version: 0.9.103 + + - name: Enable unprivileged user namespaces (Linux) + if: runner.os == 'Linux' + run: | + sudo sysctl -w kernel.unprivileged_userns_clone=1 + 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: Build nextest archive + shell: bash + run: | + set -euo pipefail + archive_dir="${RUNNER_TEMP}/nextest-archive" + mkdir -p "${archive_dir}" + cargo nextest archive \ + --target ${{ inputs.target }} \ + --cargo-profile ${{ inputs.profile }} \ + --timings \ + --archive-file "${archive_dir}/${NEXTEST_ARCHIVE_FILE}" + + - name: Build runtime test helpers + if: ${{ runner.os == 'Linux' || runner.os == 'Windows' }} + shell: bash + run: | + set -euo pipefail + helper_dir="${RUNNER_TEMP}/${TEST_HELPERS_ARTIFACT}" + mkdir -p "${helper_dir}" + + if [[ "${RUNNER_OS}" == "Linux" ]]; then + cargo build \ + --target ${{ inputs.target }} \ + --profile ${{ inputs.profile }} \ + -p codex-linux-sandbox \ + --bin codex-linux-sandbox + cp "target/${{ inputs.target }}/${{ inputs.profile }}/codex-linux-sandbox" "${helper_dir}/" + else + cargo build \ + --target ${{ inputs.target }} \ + --profile ${{ inputs.profile }} \ + -p codex-windows-sandbox \ + --bin codex-windows-sandbox-setup \ + --bin codex-command-runner + cp "target/${{ inputs.target }}/${{ inputs.profile }}/codex-windows-sandbox-setup.exe" "${helper_dir}/" + cp "target/${{ inputs.target }}/${{ inputs.profile }}/codex-command-runner.exe" "${helper_dir}/" + fi + + - name: Upload Cargo timings (nextest) + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: cargo-timings-rust-ci-nextest-${{ inputs.target }}-${{ inputs.profile }} + path: codex-rs/target/**/cargo-timings/cargo-timing.html + if-no-files-found: warn + + - name: Upload nextest archive + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: nextest-archive-${{ inputs.artifact_id }} + path: ${{ runner.temp }}/nextest-archive/${{ env.NEXTEST_ARCHIVE_FILE }} + if-no-files-found: error + retention-days: 1 + + - name: Upload runtime test helpers + if: ${{ runner.os == 'Linux' || runner.os == 'Windows' }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: ${{ env.TEST_HELPERS_ARTIFACT }} + path: ${{ runner.temp }}/${{ env.TEST_HELPERS_ARTIFACT }}/* + if-no-files-found: error + retention-days: 1 + + - 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: cargo-home-${{ env.ARCHIVE_CACHE_RUNNER }}-${{ inputs.target }}-${{ inputs.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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: ${{ env.SCCACHE_DIR }} + key: sccache-${{ env.ARCHIVE_CACHE_RUNNER }}-${{ inputs.target }}-${{ inputs.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 — ${{ inputs.target }} (tests)"; + echo; + echo '```'; + sccache --show-stats || true; + echo '```'; + } >> "$GITHUB_STEP_SUMMARY" + + shard: + name: Tests shard ${{ matrix.shard }}/4 + needs: archive + runs-on: ${{ inputs.runner_group != '' && fromJSON(format('{{"group":"{0}","labels":"{1}"}}', inputs.runner_group, inputs.runner_labels)) || inputs.runner }} + timeout-minutes: 60 + defaults: + run: + working-directory: codex-rs + env: + NEXTEST_ARCHIVE_FILE: nextest-${{ inputs.artifact_id }}.tar.zst + TEST_HELPERS_ARTIFACT: nextest-test-helpers-${{ inputs.artifact_id }} + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - 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 bubblewrap + fi + + - name: Install DotSlash + uses: facebook/install-dotslash@1e4e7b3e07eaca387acb98f1d4720e0bee8dbb6a # v2 + + - uses: dtolnay/rust-toolchain@a0b273b48ed29de4470960879e8381ff45632f26 # 1.93.0 + with: + targets: ${{ inputs.target }} + + - uses: taiki-e/install-action@44c6d64aa62cd779e873306675c7a58e86d6d532 # v2.62.49 + with: + tool: nextest + version: 0.9.103 + + - name: Enable unprivileged user namespaces (Linux) + if: runner.os == 'Linux' + run: | + sudo sysctl -w kernel.unprivileged_userns_clone=1 + 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' && inputs.remote_env }} + shell: bash + run: | + set -euo pipefail + export CODEX_TEST_REMOTE_ENV_CONTAINER_NAME="codex-remote-test-env-${{ github.run_id }}-${{ matrix.shard }}" + source "${GITHUB_WORKSPACE}/scripts/test-remote-env.sh" + echo "CODEX_TEST_REMOTE_ENV=${CODEX_TEST_REMOTE_ENV}" >> "$GITHUB_ENV" + echo "CODEX_TEST_REMOTE_EXEC_SERVER_URL=${CODEX_TEST_REMOTE_EXEC_SERVER_URL}" >> "$GITHUB_ENV" + + - name: Download nextest archive + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: nextest-archive-${{ inputs.artifact_id }} + path: ${{ runner.temp }}/nextest-archive + + - name: Download runtime test helpers + if: ${{ runner.os == 'Linux' || runner.os == 'Windows' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ env.TEST_HELPERS_ARTIFACT }} + path: ${{ runner.temp }}/${{ env.TEST_HELPERS_ARTIFACT }} + + - name: tests + id: test + shell: bash + run: | + set -euo pipefail + archive_file="${RUNNER_TEMP}/nextest-archive/${NEXTEST_ARCHIVE_FILE}" + workspace_root="$(pwd)" + + if [[ "${RUNNER_OS}" == "Windows" ]]; then + archive_file="$(cygpath -w "${archive_file}")" + workspace_root="$(cygpath -w "${workspace_root}")" + fi + + if [[ "${RUNNER_OS}" == "Linux" ]]; then + helper_dir="${RUNNER_TEMP}/${TEST_HELPERS_ARTIFACT}" + helper_target_dir="$(pwd)/target/${{ inputs.target }}/${{ inputs.profile }}" + mkdir -p "${helper_target_dir}" + cp "${helper_dir}/codex-linux-sandbox" "${helper_target_dir}/" + chmod +x "${helper_target_dir}/codex-linux-sandbox" + elif [[ "${RUNNER_OS}" == "Windows" ]]; then + helper_dir="${RUNNER_TEMP}/${TEST_HELPERS_ARTIFACT}" + helper_target_dir="$(pwd)/target/${{ inputs.target }}/${{ inputs.profile }}" + mkdir -p "${helper_target_dir}" + cp "${helper_dir}/codex-windows-sandbox-setup.exe" "${helper_target_dir}/" + cp "${helper_dir}/codex-command-runner.exe" "${helper_target_dir}/" + fi + + nextest_args=( + run + --no-fail-fast + --archive-file "${archive_file}" + --workspace-remap "${workspace_root}" + --partition "hash:${{ matrix.shard }}/4" + ) + if [[ "${{ inputs.test_threads }}" != "0" ]]; then + nextest_args+=(--test-threads "${{ inputs.test_threads }}") + fi + + test_command=(cargo nextest "${nextest_args[@]}") + if [[ "${RUNNER_OS}" == "Linux" ]]; then + sandbox_helper="${helper_target_dir}/codex-linux-sandbox" + test_command=( + env + "CARGO_BIN_EXE_codex-linux-sandbox=${sandbox_helper}" + "CARGO_BIN_EXE_codex_linux_sandbox=${sandbox_helper}" + cargo nextest "${nextest_args[@]}" + ) + elif [[ "${RUNNER_OS}" == "Windows" ]]; then + setup_helper="$(cygpath -w "${helper_target_dir}/codex-windows-sandbox-setup.exe")" + command_runner="$(cygpath -w "${helper_target_dir}/codex-command-runner.exe")" + test_command=( + env + "CARGO_BIN_EXE_codex_windows_sandbox_setup=${setup_helper}" + "CARGO_BIN_EXE_codex_command_runner=${command_runner}" + cargo nextest "${nextest_args[@]}" + ) + fi + + "${test_command[@]}" + env: + RUST_BACKTRACE: 1 + RUST_MIN_STACK: "8388608" # 8 MiB + NEXTEST_STATUS_LEVEL: leak + + - name: Upload nextest JUnit report + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: nextest-junit-rust-ci-${{ inputs.artifact_id }}-shard-${{ matrix.shard }} + path: codex-rs/target/nextest/default/junit.xml + if-no-files-found: warn + + - name: Tear down remote test env + if: ${{ always() && runner.os == 'Linux' && inputs.remote_env }} + shell: bash + run: | + set +e + if [[ "${STEPS_TEST_OUTCOME}" != "success" ]]; then + docker logs "${CODEX_TEST_REMOTE_ENV}" || true + fi + docker rm -f "${CODEX_TEST_REMOTE_ENV}" >/dev/null 2>&1 || true + env: + STEPS_TEST_OUTCOME: ${{ steps.test.outcome }} + + - name: verify tests passed + if: steps.test.outcome == 'failure' + run: | + echo "Tests failed. See logs for details." + exit 1 + + result: + name: Platform result + needs: shard + if: always() + runs-on: ubuntu-24.04 + steps: + - name: Confirm test shards passed + shell: bash + run: | + if [[ "${{ needs.shard.result }}" != "success" ]]; then + echo "Nextest shards finished with result: ${{ needs.shard.result }}" >&2 + exit 1 + fi diff --git a/.github/workflows/rust-ci-full.yml b/.github/workflows/rust-ci-full.yml index b3c25b3f03..08e0709e17 100644 --- a/.github/workflows/rust-ci-full.yml +++ b/.github/workflows/rust-ci-full.yml @@ -521,242 +521,73 @@ jobs: /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 }} - # Windows ARM64 is the long pole here, and nextest retries plus targeted - # Windows timeout headroom need more than 45m to finish reliably. - timeout-minutes: 60 - 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 + tests_macos_aarch64: + name: Tests — macos-15-xlarge - aarch64-apple-darwin + uses: ./.github/workflows/rust-ci-full-nextest-platform.yml + with: + runner: macos-15-xlarge + target: aarch64-apple-darwin + profile: ci-test + artifact_id: macos-aarch64 + use_sccache: true + secrets: inherit - 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 + tests_linux_x64_remote: + name: Tests — ubuntu-24.04 - x86_64-unknown-linux-gnu (remote) + uses: ./.github/workflows/rust-ci-full-nextest-platform.yml + with: + runner: ubuntu-24.04 + runner_group: codex-runners + runner_labels: codex-linux-x64 + target: x86_64-unknown-linux-gnu + profile: ci-test + artifact_id: linux-x64-remote + remote_env: true + use_sccache: true + secrets: inherit - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - 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 bubblewrap - fi + tests_linux_arm64: + name: Tests — ubuntu-24.04-arm - aarch64-unknown-linux-gnu + uses: ./.github/workflows/rust-ci-full-nextest-platform.yml + with: + runner: ubuntu-24.04-arm + runner_group: codex-runners + runner_labels: codex-linux-arm64 + target: aarch64-unknown-linux-gnu + profile: ci-test + artifact_id: linux-arm64 + use_sccache: true + secrets: inherit - # Some integration tests rely on DotSlash being installed. - # See https://github.com/openai/codex/pull/7617. - - name: Install DotSlash - uses: facebook/install-dotslash@1e4e7b3e07eaca387acb98f1d4720e0bee8dbb6a # v2 + tests_windows_x64: + name: Tests — windows-x64 - x86_64-pc-windows-msvc + uses: ./.github/workflows/rust-ci-full-nextest-platform.yml + with: + runner: windows-x64 + runner_group: codex-runners + runner_labels: codex-windows-x64 + target: x86_64-pc-windows-msvc + profile: ci-test + artifact_id: windows-x64 + test_threads: 8 + secrets: inherit - - uses: dtolnay/rust-toolchain@a0b273b48ed29de4470960879e8381ff45632f26 # 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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.62.49 - 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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.62.49 - 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" - echo "CODEX_TEST_REMOTE_EXEC_SERVER_URL=${CODEX_TEST_REMOTE_EXEC_SERVER_URL}" >> "$GITHUB_ENV" - - - name: tests - id: test - run: cargo nextest run --no-fail-fast --target ${{ matrix.target }} --cargo-profile ci-test --timings - env: - RUST_BACKTRACE: 1 - RUST_MIN_STACK: "8388608" # 8 MiB - NEXTEST_STATUS_LEVEL: leak - - - name: Upload nextest JUnit report - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: nextest-junit-rust-ci-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }} - path: codex-rs/target/nextest/default/junit.xml - if-no-files-found: warn - - - name: Upload Cargo timings (nextest) - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 - 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 - env: - STEPS_TEST_OUTCOME: ${{ steps.test.outcome }} - - - name: verify tests passed - if: steps.test.outcome == 'failure' - run: | - echo "Tests failed. See logs for details." - exit 1 + tests_windows_arm64: + name: Tests — windows-arm64 - aarch64-pc-windows-msvc + uses: ./.github/workflows/rust-ci-full-nextest-platform.yml + with: + runner: windows-arm64 + runner_group: codex-runners + runner_labels: codex-windows-arm64 + archive_runner: windows-x64 + archive_runner_group: codex-runners + archive_runner_labels: codex-windows-x64 + target: aarch64-pc-windows-msvc + profile: ci-test + artifact_id: windows-arm64 + test_threads: 8 + use_sccache: true + secrets: inherit # --- Gatherer job for the full post-merge workflow -------------------------- results: @@ -768,7 +599,11 @@ jobs: argument_comment_lint_package, argument_comment_lint_prebuilt, lint_build, - tests, + tests_macos_aarch64, + tests_linux_x64_remote, + tests_linux_arm64, + tests_windows_x64, + tests_windows_arm64, ] if: always() runs-on: ubuntu-24.04 @@ -781,13 +616,21 @@ jobs: echo "general: ${{ needs.general.result }}" echo "shear : ${{ needs.cargo_shear.result }}" echo "lint : ${{ needs.lint_build.result }}" - echo "tests : ${{ needs.tests.result }}" + echo "test macos : ${{ needs.tests_macos_aarch64.result }}" + echo "test linux : ${{ needs.tests_linux_x64_remote.result }}" + echo "test arm64 : ${{ needs.tests_linux_arm64.result }}" + echo "test winx64: ${{ needs.tests_windows_x64.result }}" + echo "test winarm: ${{ needs.tests_windows_arm64.result }}" [[ '${{ needs.argument_comment_lint_package.result }}' == 'success' ]] || { echo 'argument_comment_lint_package failed'; exit 1; } [[ '${{ needs.argument_comment_lint_prebuilt.result }}' == 'success' ]] || { echo 'argument_comment_lint_prebuilt failed'; exit 1; } [[ '${{ 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; } + [[ '${{ needs.tests_macos_aarch64.result }}' == 'success' ]] || { echo 'tests_macos_aarch64 failed'; exit 1; } + [[ '${{ needs.tests_linux_x64_remote.result }}' == 'success' ]] || { echo 'tests_linux_x64_remote failed'; exit 1; } + [[ '${{ needs.tests_linux_arm64.result }}' == 'success' ]] || { echo 'tests_linux_arm64 failed'; exit 1; } + [[ '${{ needs.tests_windows_x64.result }}' == 'success' ]] || { echo 'tests_windows_x64 failed'; exit 1; } + [[ '${{ needs.tests_windows_arm64.result }}' == 'success' ]] || { echo 'tests_windows_arm64 failed'; exit 1; } - name: sccache summary note if: always() diff --git a/codex-rs/.config/nextest.toml b/codex-rs/.config/nextest.toml index 399caae16a..01f4a98dc8 100644 --- a/codex-rs/.config/nextest.toml +++ b/codex-rs/.config/nextest.toml @@ -1,6 +1,8 @@ [profile.default] # Retry once so one transient failure does not fail full-CI outright. -slow-timeout = { period = "15s", terminate-after = 2 } +# Fanout keeps the full-CI shards moving without treating every >30s test as +# stuck. Keep this aligned with the broader timeout budget we give sharded CI. +slow-timeout = { period = "30s", terminate-after = 2 } retries = 1 [profile.default.junit]