Files
codex/.github/workflows/sdk.yml
Michael Bolin 2ffb32db98 ci: run SDK tests with a Bazel-built codex (#16046)
## Why

Before this change, the SDK CI job built `codex` with Cargo before
running the TypeScript package tests. That step has been getting more
expensive as the Rust workspace grows, while the repo already has a
Bazel-backed build path for the CLI.

The SDK tests also need a normal executable path they can spawn
repeatedly. Moving the job to Bazel exposed an extra CI detail: a plain
`bazel-bin/...` lookup is not reliable under the Linux config because
top-level outputs may stay remote and the wrapper emits status lines
around `cquery` output.

## What Changed

- taught `sdk/typescript/tests/testCodex.ts` to honor `CODEX_EXEC_PATH`
before falling back to the local Cargo-style `target/debug/codex` path
- added `--remote-download-toplevel` to
`.github/scripts/run-bazel-ci.sh` so workflows can force Bazel to
materialize top-level outputs on disk after a build
- switched `.github/workflows/sdk.yml` from `cargo build --bin codex` to
the shared Bazel CI setup and `//codex-rs/cli:codex` build target
- changed the SDK workflow to resolve the built CLI with wrapper-backed
`cquery --output=files`, stage the binary into
`${GITHUB_WORKSPACE}/.tmp/sdk-ci/codex`, and point the SDK tests at that
path via `CODEX_EXEC_PATH`
- kept the warm-up step before Jest and the Bazel repository-cache save
step

## Verification

- `bash -n .github/scripts/run-bazel-ci.sh`
- `./.github/scripts/run-bazel-ci.sh -- cquery --output=files --
//codex-rs/cli:codex | grep -E '^(/|bazel-out/)' | tail -n 1`
- `./.github/scripts/run-bazel-ci.sh --remote-download-toplevel -- build
--build_metadata=TAG_job=sdk -- //codex-rs/cli:codex`
- `CODEX_EXEC_PATH="$PWD/.tmp/sdk-ci/codex" pnpm --dir sdk/typescript
test --runInBand`
- `pnpm --dir sdk/typescript lint`
2026-03-27 17:17:22 -07:00

123 lines
4.2 KiB
YAML

name: sdk
on:
push:
branches: [main]
pull_request: {}
jobs:
sdks:
runs-on:
group: codex-runners
labels: codex-linux-x64
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install Linux bwrap build dependencies
shell: bash
run: |
set -euo pipefail
sudo apt-get update -y
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends pkg-config libcap-dev
- name: Setup pnpm
uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: 22
cache: pnpm
- name: Set up Bazel CI
id: setup_bazel
uses: ./.github/actions/setup-bazel-ci
with:
target: x86_64-unknown-linux-gnu
- name: Build codex with Bazel
env:
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
shell: bash
run: |
set -euo pipefail
# Use the shared CI wrapper so fork PRs fall back cleanly when
# BuildBuddy credentials are unavailable. This workflow needs the
# built `codex` binary on disk afterwards, so ask the wrapper to
# override CI's default remote_download_minimal behavior.
./.github/scripts/run-bazel-ci.sh \
--remote-download-toplevel \
-- \
build \
--build_metadata=COMMIT_SHA=${GITHUB_SHA} \
--build_metadata=TAG_job=sdk \
-- \
//codex-rs/cli:codex
# Resolve the exact output file using the same wrapper/config path as
# the build instead of guessing which Bazel convenience symlink is
# available on the runner.
cquery_output="$(
./.github/scripts/run-bazel-ci.sh \
-- \
cquery \
--output=files \
-- \
//codex-rs/cli:codex \
| grep -E '^(/|bazel-out/)' \
| tail -n 1
)"
if [[ "${cquery_output}" = /* ]]; then
codex_bazel_output_path="${cquery_output}"
else
codex_bazel_output_path="${GITHUB_WORKSPACE}/${cquery_output}"
fi
if [[ -z "${codex_bazel_output_path}" ]]; then
echo "Bazel did not report an output path for //codex-rs/cli:codex." >&2
exit 1
fi
if [[ ! -e "${codex_bazel_output_path}" ]]; then
echo "Unable to locate the Bazel-built codex binary at ${codex_bazel_output_path}." >&2
exit 1
fi
# Stage the binary into the workspace and point the SDK tests at that
# stable path. The tests spawn `codex` directly many times, so using a
# normal executable path is more reliable than invoking Bazel for each
# test process.
install_dir="${GITHUB_WORKSPACE}/.tmp/sdk-ci"
mkdir -p "${install_dir}"
install -m 755 "${codex_bazel_output_path}" "${install_dir}/codex"
echo "CODEX_EXEC_PATH=${install_dir}/codex" >> "$GITHUB_ENV"
- name: Warm up Bazel-built codex
shell: bash
run: |
set -euo pipefail
"${CODEX_EXEC_PATH}" --version
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build SDK packages
run: pnpm -r --filter ./sdk/typescript run build
- name: Lint SDK packages
run: pnpm -r --filter ./sdk/typescript run lint
- name: Test SDK packages
run: pnpm -r --filter ./sdk/typescript run test
- name: Save bazel repository cache
if: always() && !cancelled() && steps.setup_bazel.outputs.cache-hit != 'true'
continue-on-error: true
uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
with:
path: |
~/.cache/bazel-repo-cache
key: bazel-cache-x86_64-unknown-linux-gnu-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }}