name: sdk

on:
  push:
    branches: [main]
  pull_request: {}

jobs:
  python-sdk:
    runs-on:
      group: codex-runners
      labels: codex-linux-x64
    timeout-minutes: 10
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
          persist-credentials: false

      - name: Test Python SDK
        shell: bash
        run: |
          set -euo pipefail

          # Run inside Alpine so dependency resolution exercises the pinned
          # runtime wheel on the same Linux wheel family that CI installs.
          docker run --rm \
            --user "$(id -u):$(id -g)" \
            -e HOME=/tmp/codex-python-sdk-home \
            -e UV_LINK_MODE=copy \
            -v "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}" \
            -w "${GITHUB_WORKSPACE}/sdk/python" \
            python:3.12-alpine \
            sh -euxc '
              python -m venv /tmp/uv
              /tmp/uv/bin/python -m pip install uv==0.11.3
              /tmp/uv/bin/uv sync --extra dev --frozen
              /tmp/uv/bin/uv run --extra dev ruff check --output-format=github .
              /tmp/uv/bin/uv run --extra dev ruff format --check .
              /tmp/uv/bin/uv run --extra dev pytest
            '

  sdks:
    runs-on:
      group: codex-runners
      labels: codex-linux-x64
    timeout-minutes: 10
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
          persist-credentials: false

      - 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.3.0
        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.0.4
        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') }}
