name: CI
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
permissions:
contents: read
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
prefix-key: lint
- name: Check formatting
run: cargo fmt --check
- name: Clippy (default features)
run: cargo clippy -- -D warnings
- name: Clippy (builtin-embeddings)
run: cargo clippy --features builtin-embeddings -- -D warnings
- name: Clippy (sync)
run: cargo clippy --features sync -- -D warnings
- name: Clippy (sync-http)
run: cargo clippy --features sync-http -- -D warnings
test:
name: Test (${{ matrix.name }})
needs: lint
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
features: ""
name: Linux / default
- os: ubuntu-latest
features: "--features builtin-embeddings"
name: Linux / builtin-embeddings
- os: ubuntu-latest
features: "--features sync"
name: Linux / sync
- os: ubuntu-latest
features: "--features sync-http"
name: Linux / sync-http
- os: macos-latest
features: ""
name: macOS / default
- os: macos-latest
features: "--features builtin-embeddings"
name: macOS / builtin-embeddings
- os: windows-latest
features: ""
name: Windows / default
- os: windows-latest
features: "--features builtin-embeddings"
name: Windows / builtin-embeddings
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
prefix-key: "test-${{ matrix.os }}"
- name: Build
run: cargo build ${{ matrix.features }}
- name: Run tests
run: cargo test ${{ matrix.features }}
fault-injection:
name: Crash recovery (fault-injection)
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
prefix-key: fault-injection
- name: Run kill-at-boundary crash-recovery tests
run: cargo test --features fault-injection --test storage_migration_fault_injection
test-msrv:
name: MSRV (Rust 1.89)
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.89"
- uses: Swatinem/rust-cache@v2
with:
prefix-key: msrv
- name: Build (default features)
run: cargo build
- name: Test (default features)
run: cargo test
- name: Build (builtin-embeddings)
run: cargo build --features builtin-embeddings
- name: Test (builtin-embeddings)
run: cargo test --features builtin-embeddings
coverage:
name: Coverage
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
prefix-key: coverage
- name: Install cargo-tarpaulin
uses: taiki-e/install-action@cargo-tarpaulin
- name: Generate coverage
run: cargo tarpaulin --fail-under 80 --out xml --out html
- name: Upload coverage report
uses: actions/upload-artifact@v7
with:
name: coverage-report
path: |
cobertura.xml
tarpaulin-report.html
if: always()
security:
name: Security Audit
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Install cargo-audit
uses: taiki-e/install-action@cargo-audit
- name: Run audit
run: cargo audit
cargo-deny:
name: Dependency Policy (cargo-deny)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe with:
command: check advisories bans sources
bench:
name: Benchmarks
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
prefix-key: bench
- name: Install critcmp
run: cargo install critcmp
- name: Restore baseline
if: github.event_name == 'pull_request'
uses: actions/cache/restore@v5
with:
path: target/criterion-baseline/
key: criterion-baseline-main
- name: Run benchmarks
env:
NFR018_N: "2000"
NFR018_WARMUP: "20"
NFR018_SAMPLES: "200"
run: cargo bench
- name: Compare with baseline (10% threshold)
if: github.event_name == 'pull_request'
continue-on-error: true
run: |
if [ -d target/criterion-baseline ]; then
critcmp target/criterion-baseline target/criterion --threshold 10
else
echo "No baseline found — skipping comparison"
fi
- name: Save baseline
if: github.ref == 'refs/heads/main'
run: |
rm -rf target/criterion-baseline
cp -r target/criterion target/criterion-baseline
- name: Cache baseline
if: github.ref == 'refs/heads/main'
uses: actions/cache/save@v5
with:
path: target/criterion-baseline/
key: criterion-baseline-main
- name: Upload benchmark results
uses: actions/upload-artifact@v7
with:
name: benchmark-results
path: target/criterion/
publish:
name: Publish to crates.io
if: startsWith(github.ref, 'refs/tags/v')
needs: [lint, test, test-msrv, coverage, security, cargo-deny]
runs-on: ubuntu-latest
environment: crates-io
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- name: Verify version matches tag
run: |
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
TAG_VERSION=${GITHUB_REF#refs/tags/v}
if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
echo "ERROR: Cargo.toml version ($CARGO_VERSION) does not match tag (v$TAG_VERSION)"
exit 1
fi
echo "Version verified: $CARGO_VERSION"
- name: Publish
run: cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }}
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true