cargo-impact 0.5.0

Blast-radius analysis and selective test execution for Rust workspaces
Documentation
name: CI

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

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  # Deny warnings in CI; locally devs can still warn-only.
  RUSTFLAGS: -D warnings
  RUSTDOCFLAGS: -D warnings

jobs:
  # Detect whether Rust code exists yet. The project is currently spec-only
  # (see README §11). Once Cargo.toml lands, all Rust jobs activate automatically.
  detect:
    runs-on: ubuntu-latest
    outputs:
      has_rust: ${{ steps.check.outputs.has_rust }}
    steps:
      - uses: actions/checkout@v6
      - id: check
        run: |
          if [ -f Cargo.toml ]; then
            echo "has_rust=true" >> "$GITHUB_OUTPUT"
          else
            echo "has_rust=false" >> "$GITHUB_OUTPUT"
            echo "::notice::No Cargo.toml found — Rust jobs will be skipped until implementation starts (see README §11)."
          fi

  fmt:
    needs: detect
    if: needs.detect.outputs.has_rust == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: stable
          components: rustfmt
      - run: cargo fmt --all --check

  clippy:
    needs: detect
    if: needs.detect.outputs.has_rust == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: stable
          components: clippy
      - run: cargo clippy --workspace --all-targets --all-features -- -D warnings

  test:
    needs: detect
    if: needs.detect.outputs.has_rust == 'true'
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        toolchain: [stable, beta]
        include:
          # Pin MSRV here. Update deliberately — do not let dependencies bump it.
          # History:
          #   1.82 → 1.85: clap_lex 1.1.0 requires edition2024 (stabilized 1.85).
          #   1.85 → 1.95: project-wide bump to current stable; no dep forcing.
          - os: ubuntu-latest
            toolchain: "1.95"
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: ${{ matrix.toolchain }}
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-nextest
      - name: Build
        run: cargo build --workspace --all-targets --all-features --locked
      - name: Test (nextest)
        run: cargo nextest run --workspace --all-features --locked
      - name: Doctests
        run: cargo test --workspace --doc --all-features --locked

  docs:
    needs: detect
    if: needs.detect.outputs.has_rust == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: stable
      - run: cargo doc --workspace --all-features --no-deps

  # Aggregate required check so branch protection has a single target to gate on.
  ci:
    if: always()
    needs: [detect, fmt, clippy, test, docs]
    runs-on: ubuntu-latest
    steps:
      - name: Verify all required jobs passed (or were skipped when spec-only)
        run: |
          has_rust='${{ needs.detect.outputs.has_rust }}'
          if [ "$has_rust" = "true" ]; then
            for job in fmt clippy test docs; do
              result=$(jq -r ".[\"$job\"].result" <<< '${{ toJSON(needs) }}')
              if [ "$result" != "success" ]; then
                echo "::error::$job failed: $result"
                exit 1
              fi
            done
          fi
          echo "All required checks passed."