name: rust-ci
on:
  pull_request: {}
  workflow_dispatch:

jobs:
  # --- Detect what changed so the fast PR workflow only runs relevant jobs ----
  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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 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"
            mapfile -t files < <(git diff --name-only --no-renames "$BASE_SHA" "$HEAD_SHA")
          else
            # On manual runs, default to the full fast-PR bundle.
            files=("codex-rs/force" "tools/argument-comment-lint/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 == defs.bzl || $f == workspace_root_test_launcher.sh.tpl || $f == workspace_root_test_launcher.bat.tpl ]] && argument_comment_lint=true
            [[ $f == tools/argument-comment-lint/* || $f == .github/workflows/rust-ci.yml || $f == .github/workflows/rust-ci-full.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"

  # --- Fast Cargo-native PR checks -------------------------------------------
  general:
    name: Format / etc
    runs-on: ubuntu-24.04
    needs: changed
    if: ${{ needs.changed.outputs.codex == 'true' || needs.changed.outputs.workflows == 'true' }}
    defaults:
      run:
        working-directory: codex-rs
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: dtolnay/rust-toolchain@a0b273b48ed29de4470960879e8381ff45632f26 # 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' }}
    defaults:
      run:
        working-directory: codex-rs
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: dtolnay/rust-toolchain@a0b273b48ed29de4470960879e8381ff45632f26 # 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' }}
    env:
      CARGO_DYLINT_VERSION: 5.0.0
      DYLINT_LINK_VERSION: 5.0.0
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: dtolnay/rust-toolchain@a0b273b48ed29de4470960879e8381ff45632f26 # 1.93.0
      - name: Install nightly argument-comment-lint toolchain
        shell: bash
        run: |
          rustup toolchain install nightly-2025-09-18 \
            --profile minimal \
            --component llvm-tools-preview \
            --component rustc-dev \
            --component rust-src \
            --no-self-update
          rustup default nightly-2025-09-18
      - name: Cache cargo-dylint tooling
        id: cargo_dylint_cache
        uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # 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 }}-${{ env.CARGO_DYLINT_VERSION }}-${{ env.DYLINT_LINK_VERSION }}-${{ hashFiles('tools/argument-comment-lint/Cargo.lock', 'tools/argument-comment-lint/rust-toolchain', '.github/workflows/rust-ci.yml', '.github/workflows/rust-ci-full.yml') }}
      - name: Install cargo-dylint tooling
        if: ${{ steps.cargo_dylint_cache.outputs.cache-hit != 'true' }}
        shell: bash
        run: |
          cargo install --locked cargo-dylint --version "$CARGO_DYLINT_VERSION"
          cargo install --locked dylint-link --version "$DYLINT_LINK_VERSION"
      - name: Check Python wrapper syntax
        run: python3 -m py_compile tools/argument-comment-lint/wrapper_common.py tools/argument-comment-lint/run.py tools/argument-comment-lint/run-prebuilt-linter.py tools/argument-comment-lint/test_wrapper_common.py
      - name: Test Python wrapper helpers
        run: python3 -m unittest discover -s tools/argument-comment-lint -p 'test_*.py'
      - name: Test argument comment lint package
        working-directory: tools/argument-comment-lint
        run: cargo test
        env:
          RUST_MIN_STACK: "8388608" # 8 MiB

  argument_comment_lint_prebuilt:
    name: Argument comment lint - ${{ matrix.name }}
    runs-on: ${{ matrix.runs_on || matrix.runner }}
    timeout-minutes: ${{ matrix.timeout_minutes }}
    needs: changed
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Linux
            runner: ubuntu-24.04
            timeout_minutes: 30
          - name: macOS
            runner: macos-15-xlarge
            timeout_minutes: 30
          - name: Windows
            runner: windows-x64
            timeout_minutes: 30
            runs_on:
              group: codex-runners
              labels: codex-windows-x64
    steps:
      - name: Check whether argument comment lint should run
        id: argument_comment_lint_gate
        shell: bash
        env:
          ARGUMENT_COMMENT_LINT: ${{ needs.changed.outputs.argument_comment_lint }}
          WORKFLOWS: ${{ needs.changed.outputs.workflows }}
        run: |
          if [[ "$ARGUMENT_COMMENT_LINT" == "true" || "$WORKFLOWS" == "true" ]]; then
            echo "run=true" >> "$GITHUB_OUTPUT"
            exit 0
          fi

          echo "No argument-comment-lint relevant changes."
          echo "run=false" >> "$GITHUB_OUTPUT"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        if: ${{ steps.argument_comment_lint_gate.outputs.run == 'true' }}
      - name: Run argument comment lint on codex-rs via Bazel
        if: ${{ steps.argument_comment_lint_gate.outputs.run == 'true' }}
        uses: ./.github/actions/run-argument-comment-lint
        with:
          target: ${{ runner.os }}
          buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }}

  # --- 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,
      ]
    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 }}"

          # 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' ]]; then
            echo 'No relevant changes -> CI not required.'
            exit 0
          fi

          if [[ '${{ needs.changed.outputs.argument_comment_lint_package }}' == 'true' ]]; 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' ]]; 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' ]]; then
            [[ '${{ needs.general.result }}' == 'success' ]] || { echo 'general failed'; exit 1; }
            [[ '${{ needs.cargo_shear.result }}' == 'success' ]] || { echo 'cargo_shear failed'; exit 1; }
          fi
