yolop 0.3.0

Yolop — a terminal coding agent built on everruns-runtime
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
    types: [opened, reopened, synchronize]

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

permissions:
  contents: read

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  CARGO_INCREMENTAL: 0

jobs:
  lint:
    name: Format + Clippy
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v5

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - name: Cache Rust
        uses: Swatinem/rust-cache@v2
        with:
          shared-key: "debug"

      - name: Format check
        run: cargo fmt --all -- --check

      - name: Clippy
        run: cargo clippy --all-targets --all-features -- -D warnings

  test:
    name: Build + Tests + Offline Smoke
    runs-on: ubuntu-latest
    timeout-minutes: 25
    steps:
      - uses: actions/checkout@v5

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust
        uses: Swatinem/rust-cache@v2
        with:
          shared-key: "debug"

      - name: Install cargo-llvm-cov
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-llvm-cov

      - name: Build
        run: cargo build --locked --all-targets

      - name: Unit and integration tests with coverage
        # The live provider tests skip themselves here (no API keys and
        # YOLOP_REQUIRE_LIVE_TESTS unset); they run in the `live-smoke` job below.
        run: |
          cargo llvm-cov --no-report --all-features --workspace
          cargo llvm-cov report --lcov --output-path lcov.info
          cargo llvm-cov report --summary-only

      - name: Upload coverage to Codecov
        if: always()
        uses: codecov/codecov-action@v4
        with:
          files: lcov.info
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}

      - name: Upload coverage artifact
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: lcov-coverage
          path: lcov.info
          if-no-files-found: error

  live-smoke:
    name: Live Provider Smoke (Doppler)
    runs-on: ubuntu-latest
    timeout-minutes: 15
    # Gate this job out entirely on fork PRs where DOPPLER_TOKEN is not
    # exposed. When the job does run, it must actually run the tests —
    # YOLOP_REQUIRE_LIVE_TESTS=1 (below) turns a missing provider key into a
    # hard failure so the live check can't report green without exercising
    # anything.
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
    needs: [lint, test]
    env:
      DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }}
    steps:
      - uses: actions/checkout@v5

      - name: Verify DOPPLER_TOKEN is set
        run: |
          if [ -z "${DOPPLER_TOKEN}" ]; then
            echo "::error::DOPPLER_TOKEN is required for the live smoke job but is not set. Configure the repo secret or update the job's outer 'if:' to skip this environment."
            exit 1
          fi

      - name: Install Doppler CLI
        uses: dopplerhq/cli-action@v3

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust
        uses: Swatinem/rust-cache@v2
        with:
          shared-key: "debug"

      - name: Build the test binary (offline)
        run: cargo test --no-run --test integration

      - name: Live provider smoke tests
        env:
          YOLOP_REQUIRE_LIVE_TESTS: "1"
        run: doppler run -- cargo test --test integration -- --nocapture