name: Rust CI
on:
push:
branches: [ "main", "development" ]
pull_request:
branches: [ "main", "development" ]
schedule:
- cron: '0 0 * * *'
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
fmt:
name: Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
clippy:
name: Clippy Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Cache cargo dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-clippy-
${{ runner.os }}-cargo-
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
build-and-test:
name: Build & Test - ${{ matrix.os }} / ${{ matrix.rust }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: [stable, beta]
include:
- os: ubuntu-latest
rust: nightly
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Cache cargo dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-${{ matrix.rust }}-
${{ runner.os }}-cargo-
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- name: Build release
run: cargo build --release --verbose
- name: Run doc tests
run: cargo test --doc --verbose
- name: Build documentation
run: cargo doc --no-deps --all-features
feature-tests:
name: Feature Tests
runs-on: ubuntu-latest
strategy:
matrix:
features:
- "" - "--no-default-features --features std"
- "--all-features"
steps:
- uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-features-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-features-
${{ runner.os }}-cargo-
- name: Build with features ${{ matrix.features }}
run: cargo build ${{ matrix.features }} --verbose
- name: Test with features ${{ matrix.features }}
run: cargo test ${{ matrix.features }} --verbose
security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run cargo-audit
uses: rustsec/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
sast:
name: SAST Security Scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-deny
run: cargo install cargo-deny --locked
- name: Create deny.toml
run: |
cat > deny.toml << 'EOF'
[graph]
targets = []
[licenses]
version = 2
allow = ["MIT", "Apache-2.0", "BSD-3-Clause", "ISC", "Unicode-3.0"]
[bans]
multiple-versions = "warn"
wildcards = "allow"
[advisories]
version = 2
db-path = "~/.cargo/advisory-db"
db-urls = ["https://github.com/rustsec/advisory-db"]
[sources]
unknown-registry = "warn"
unknown-git = "warn"
EOF
- name: Run cargo-deny check
run: cargo deny check
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/rust
p/security-audit
p/secrets
if: github.event_name == 'pull_request'
coverage:
name: Code Coverage
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- name: Install grcov
run: cargo install grcov --locked
- name: Build with coverage
env:
CARGO_INCREMENTAL: '0'
RUSTFLAGS: '-Cinstrument-coverage'
LLVM_PROFILE_FILE: 'cargo-test-%p-%m.profraw'
run: cargo build --verbose
- name: Run tests with coverage
env:
CARGO_INCREMENTAL: '0'
RUSTFLAGS: '-Cinstrument-coverage'
LLVM_PROFILE_FILE: 'cargo-test-%p-%m.profraw'
run: cargo test --verbose
- name: Generate coverage report
run: |
grcov . --binary-path ./target/debug/deps/ -s . -t lcov --branch --ignore-not-existing --ignore '../*' --ignore "/*" -o coverage.lcov
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage.lcov
flags: unittests
name: codecov-umbrella
continue-on-error: true
msrv:
name: MSRV Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust toolchain (1.75.0)
uses: dtolnay/rust-toolchain@1.75.0
- name: Check MSRV
run: cargo check --all-features