name: CI
on:
push:
branches: [main]
pull_request:
merge_group:
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
RUST_BACKTRACE: short
RUSTFLAGS: "-D warnings"
jobs:
typos:
name: Spell Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crate-ci/typos@v1.45.0
preflight:
name: Pre-flight Checks
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check if code changed
id: check
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
echo "should_run=true" >> $GITHUB_OUTPUT
elif git diff --name-only HEAD^ HEAD | grep -qE '\.(rs|cpp|h|hpp|toml|cmake)$|CMakeLists\.txt'; then
echo "should_run=true" >> $GITHUB_OUTPUT
else
echo "should_run=false" >> $GITHUB_OUTPUT
fi
security:
name: Security Audit
runs-on: ubuntu-latest
needs: preflight
if: needs.preflight.outputs.should_run == 'true'
steps:
- uses: actions/checkout@v4
- name: Generate Cargo.lock
run: cargo generate-lockfile
- name: Run cargo-audit
uses: rustsec/audit-check@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install cargo-deny
uses: taiki-e/install-action@v2
with:
tool: cargo-deny
- name: Check licenses and advisories
run: cargo deny check licenses advisories sources bans
lint:
name: Format and Lint
runs-on: ubuntu-latest
needs: preflight
if: needs.preflight.outputs.should_run == 'true'
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo tools
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --all-targets -- -D warnings
- name: Check documentation
run: cargo doc --no-deps
env:
RUSTDOCFLAGS: "-D warnings"
machete:
name: Check Unused Dependencies
runs-on: ubuntu-latest
needs: preflight
if: needs.preflight.outputs.should_run == 'true'
steps:
- uses: actions/checkout@v4
- name: Install cargo-machete
uses: taiki-e/install-action@v2
with:
tool: cargo-machete
- name: Check for unused dependencies
run: cargo machete
publish-check:
name: Publish Check
runs-on: ubuntu-latest
needs: preflight
if: needs.preflight.outputs.should_run == 'true'
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Publish check
run: cargo publish --dry-run
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
needs: [preflight]
if: needs.preflight.outputs.should_run == 'true'
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}
cache-on-failure: true
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
cpp-tests:
name: C++ Binding Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
needs: [preflight]
if: needs.preflight.outputs.should_run == 'true'
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cbindgen
uses: taiki-e/install-action@v2
with:
tool: cbindgen
- name: Install cmake
uses: lukka/get-cmake@latest
- name: Install boost
uses: MarkusJx/install-boost@v2.4.1
id: install-boost
with:
boost_version: 1.81.0
- name: Configure and build
env:
BOOST_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }}
run: |
mkdir build
cd build
cmake \
-DRust_TOOLCHAIN=stable \
-DRust_COMPILER="$(which rustc)" \
-DRust_CARGO="$(which cargo)" \
-DBUILD_TESTING=yes \
-DBUILD_C_BINDINGS=yes \
..
cmake --build .
- name: Run ctest
run: |
cd build
ctest -C Debug -V
semver:
name: Semver Compatibility
runs-on: ubuntu-latest
needs: [preflight]
if: github.event_name == 'pull_request' && needs.preflight.outputs.should_run == 'true'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install cargo-semver-checks
uses: taiki-e/install-action@v2
with:
tool: cargo-semver-checks
- name: Check semver compatibility
run: cargo semver-checks --baseline-rev origin/${{ github.base_ref }}
ci-success:
name: CI Success
runs-on: ubuntu-latest
needs: [typos, security, lint, machete, publish-check, test, cpp-tests]
if: always()
steps:
- name: Report status
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: exit 1
- name: All checks passed
run: echo "All CI checks passed!"