outfit 2.1.0

Orbit determination toolkit in Rust. Provides astrometric parsing, observer management, and initial orbit determination (Gauss method) with JPL ephemeris support.
Documentation
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    name: Test Outfit
    runs-on: ubuntu-latest

    strategy:
      matrix:
        include:
          - name: Default features
            features: ""
          - name: With jpl-download feature
            features: "--features jpl-download"
          - name: With parallel feature
            features: '--features "parallel"'
            rayon_threads: "2"
          - name: With parallel + progress
            features: '--features "parallel progress"'
            rayon_threads: "2"

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: Run tests (${{ matrix.name }})
        env:
          # Cap Rayon threads only when provided in the matrix (no effect otherwise)
          RAYON_NUM_THREADS: ${{ matrix.rayon_threads }}
        run: |
          echo "Running cargo test with features: '${{ matrix.features }}'"
          cargo test --locked --all-targets ${{ matrix.features }}

  fmt:
    name: Check formatting
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Install Rust with rustfmt
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt
      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - name: Run cargo fmt
        run: cargo fmt --all -- --check

  clippy:
    name: Clippy lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Install Rust with clippy
        uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy
      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - name: check version
        run: |
          rustc --version
          cargo clippy --version
      - name: Run cargo clippy (all features)
        run: cargo clippy --all-targets --all-features -- -D warnings

  coverage:
    name: Coverage (stable, cargo-llvm-cov → Codecov)
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Install Rust stable + llvm-tools
        uses: dtolnay/rust-toolchain@stable
        with:
          components: llvm-tools-preview

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-llvmcov-${{ hashFiles('**/Cargo.lock') }}

      - name: Install cargo-llvm-cov
        run: cargo install cargo-llvm-cov

      - name: Clean coverage artifacts
        run: cargo llvm-cov clean --workspace

      - name: Generate coverage (lcov, all features incl. parallel)
        env:
          # Tame thread count for reproducible & stable coverage
          RAYON_NUM_THREADS: 2
        run: |
          cargo llvm-cov \
            --workspace \
            --all-features \
            --lcov --output-path lcov.info

      - name: Upload to Codecov
        uses: codecov/codecov-action@v4
        with:
          files: lcov.info
          flags: rust
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}

  semver-pr:
    name: SemVer (PR vs base)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        # IMPORTANT: full history so the base SHA exists locally
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          fetch-tags: true
          ref: ${{ github.event.pull_request.head.sha }}

      - name: Check semver (baseline = PR base)
        uses: obi1kenobi/cargo-semver-checks-action@v2
        with:
          feature-group: all-features
          baseline-rev: ${{ github.event.pull_request.base.sha }}