icarus 0.5.8

Build MCP (Model Context Protocol) servers that run as Internet Computer canisters
Documentation
name: CI

# Optimized CI with path filtering, smart caching, and maximum parallelization
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:

# Cancel in-progress runs when a new run is triggered
concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  CARGO_INCREMENTAL: 0
  RUSTFLAGS: "-D warnings"


jobs:
  # Determine what tests to run based on changed files
  changes:
    name: Detect Changes
    runs-on: ubuntu-latest
    outputs:
      rust: ${{ steps.filter.outputs.rust }}
      cli: ${{ steps.filter.outputs.cli }}
      docs: ${{ steps.filter.outputs.docs }}
      workflows: ${{ steps.filter.outputs.workflows }}
    steps:
    - uses: actions/checkout@v4
    - uses: dorny/paths-filter@v3
      id: filter
      with:
        filters: |
          rust:
            - '**/*.rs'
            - '**/Cargo.toml'
            - '**/Cargo.lock'
          cli:
            - 'cli/**'
            - 'examples/**'
          docs:
            - '**/*.md'
            - 'docs/**'
          workflows:
            - '.github/workflows/**'

  # Quick validation checks that should fail fast
  validation:
    name: Quick Validation
    runs-on: ubuntu-latest
    needs: changes
    if: needs.changes.outputs.rust == 'true' || needs.changes.outputs.workflows == 'true'
    timeout-minutes: 3
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust toolchain
      uses: dtolnay/rust-toolchain@stable
      with:
        components: rustfmt, clippy
    
    # Optimized cache - dependencies only
    - name: Cache cargo dependencies
      uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/registry/index
          ~/.cargo/registry/cache
          ~/.cargo/git/db
        key: ${{ runner.os }}-cargo-deps-${{ hashFiles('**/Cargo.lock') }}
        restore-keys: |
          ${{ runner.os }}-cargo-deps-
    
    - name: Check formatting
      run: cargo fmt --all -- --check
    
    - name: Check version consistency
      run: |
        chmod +x scripts/check-versions.sh
        ./scripts/check-versions.sh
    
    - name: Run clippy
      run: cargo clippy --all-targets --all-features -- -D warnings

  # Build shared artifacts once
  build-artifacts:
    name: Build Artifacts
    runs-on: ubuntu-latest
    needs: [changes, validation]
    if: needs.changes.outputs.rust == 'true' || needs.changes.outputs.workflows == 'true'
    timeout-minutes: 10
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust toolchain
      uses: dtolnay/rust-toolchain@stable
      with:
        targets: wasm32-unknown-unknown
    
    # Tiered caching strategy
    - name: Cache cargo dependencies
      uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/registry/index
          ~/.cargo/registry/cache
          ~/.cargo/git/db
        key: ${{ runner.os }}-cargo-deps-${{ hashFiles('**/Cargo.lock') }}
        restore-keys: |
          ${{ runner.os }}-cargo-deps-
    
    - name: Cache incremental build
      uses: actions/cache@v4
      with:
        path: target
        key: ${{ runner.os }}-incremental-${{ hashFiles('**/Cargo.lock') }}-${{ github.sha }}
        restore-keys: |
          ${{ runner.os }}-incremental-${{ hashFiles('**/Cargo.lock') }}-
          ${{ runner.os }}-incremental-
    
    - name: Cache ic-wasm binary
      uses: actions/cache@v4
      id: ic-wasm-cache
      with:
        path: ~/.cargo/bin/ic-wasm
        key: ${{ runner.os }}-ic-wasm-0.7.1
    
    - name: Install ic-wasm if not cached
      if: steps.ic-wasm-cache.outputs.cache-hit != 'true'
      run: cargo install ic-wasm --version 0.7.1 --locked
    
    - name: Build all targets
      run: |
        cargo build --package icarus-cli --bin icarus --release
        cargo build --target wasm32-unknown-unknown --release
    
    # Compress artifacts before upload
    - name: Compress CLI binary
      run: |
        tar -czf cli-binary.tar.gz -C target/release icarus
    
    - name: Upload compressed CLI binary
      uses: actions/upload-artifact@v4
      with:
        name: cli-binary
        path: cli-binary.tar.gz
        retention-days: 1
        compression-level: 0  # Already compressed
    
    - name: Upload WASM artifacts (if changed)
      if: needs.changes.outputs.cli == 'true'
      uses: actions/upload-artifact@v4
      with:
        name: wasm-artifacts
        path: target/wasm32-unknown-unknown/release/*.wasm
        retention-days: 1

  # Parallel test matrix for unit, integration, and doc tests
  test-matrix:
    name: Test ${{ matrix.test_type }}
    runs-on: ubuntu-latest
    needs: [changes, build-artifacts]
    if: needs.changes.outputs.rust == 'true' || needs.changes.outputs.workflows == 'true'
    timeout-minutes: 5
    strategy:
      fail-fast: false
      matrix:
        test_type: [unit, integration, doc]
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust toolchain
      uses: dtolnay/rust-toolchain@stable
    
    - name: Restore cargo dependencies cache
      uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/registry/index
          ~/.cargo/registry/cache
          ~/.cargo/git/db
        key: ${{ runner.os }}-cargo-deps-${{ hashFiles('**/Cargo.lock') }}
        restore-keys: |
          ${{ runner.os }}-cargo-deps-
    
    - name: Restore incremental build cache
      uses: actions/cache@v4
      with:
        path: target
        key: ${{ runner.os }}-incremental-${{ hashFiles('**/Cargo.lock') }}-${{ github.sha }}
        restore-keys: |
          ${{ runner.os }}-incremental-${{ hashFiles('**/Cargo.lock') }}-
    
    - name: Run ${{ matrix.test_type }} tests
      run: |
        case "${{ matrix.test_type }}" in
          unit)
            cargo test --lib --all-features --release
            ;;
          integration)
            cargo test --test '*' --all-features --release
            ;;
          doc)
            cargo test --doc --all-features
            ;;
        esac

  # Note: E2E tests are run in local pre-push hooks to ensure quality
  # They are excluded from CI to improve pipeline performance
  # Developers must pass all tests locally before pushing

  # Documentation build (only if docs changed)
  docs:
    name: Build Documentation
    runs-on: ubuntu-latest
    needs: [changes, validation]
    if: needs.changes.outputs.rust == 'true' || needs.changes.outputs.docs == 'true'
    timeout-minutes: 3
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust toolchain
      uses: dtolnay/rust-toolchain@stable
    
    - name: Cache cargo dependencies
      uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/registry/index
          ~/.cargo/registry/cache
          ~/.cargo/git/db
        key: ${{ runner.os }}-cargo-deps-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Build documentation
      run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features

  # Final status check
  ci-success:
    name: CI Success
    runs-on: ubuntu-latest
    needs: [validation, build-artifacts, test-matrix, docs]
    if: always()
    steps:
    - name: Check CI Status
      run: |
        # Check if any required jobs were skipped
        if [[ "${{ contains(needs.*.result, 'skipped') }}" == "false" ]]; then
          # All jobs ran, check for failures
          if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then
            echo "❌ CI failed - one or more jobs failed"
            exit 1
          elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
            echo "⚠️ CI cancelled"
            exit 1
          else
            echo "✅ All CI checks passed!"
          fi
        else
          # Some jobs were skipped (path filtering)
          echo "✅ CI passed (some jobs skipped due to path filtering)"
        fi
        
        echo "Optimization Summary:"
        echo "• Path-based test filtering active"
        echo "• E2E tests run locally in pre-push hooks"
        echo "• Smart caching reduces build times"
        echo "• Artifacts compressed for faster transfer"