name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
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:
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/**'
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
- 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-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
- 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
- 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
- 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
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
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
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"