name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
RUST_BACKTRACE: 1
CARGO_INCREMENTAL: 0
SCCACHE_VERSION: "0.8.0"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-registry-
- name: Clippy
run: cargo clippy -- -D warnings
- name: Formatting check
run: cargo fmt -- --check
security:
name: Security
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: security-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: security-cargo-registry-
- name: Cache cargo-audit binary
id: cache-cargo-audit
uses: actions/cache@v4
with:
path: ~/.cargo/bin/cargo-audit
key: cargo-audit-bin-v1
- name: Install cargo-audit
if: steps.cache-cargo-audit.outputs.cache-hit != 'true'
run: cargo install cargo-audit --locked
- name: Run security audit
run: cargo audit
env:
ADVISORY_DB_CACHE_DIR: /tmp/advisory-db
- name: Cache cargo-deny binary
id: cache-cargo-deny
uses: actions/cache@v4
with:
path: ~/.cargo/bin/cargo-deny
key: cargo-deny-bin-v1
- name: Install cargo-deny
if: steps.cache-cargo-deny.outputs.cache-hit != 'true'
run: cargo install cargo-deny --locked
- name: Run cargo deny
run: cargo deny --all-features check bans licenses sources
docs:
name: Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: docs-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: docs-cargo-registry-
- name: Build documentation
run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
coverage:
name: Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: coverage-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: coverage-cargo-registry-
- name: Cache cargo-tarpaulin binary
id: cache-tarpaulin
uses: actions/cache@v4
with:
path: ~/.cargo/bin/cargo-tarpaulin
key: cargo-tarpaulin-bin-v1
- name: Install cargo-tarpaulin
if: steps.cache-tarpaulin.outputs.cache-hit != 'true'
run: cargo install cargo-tarpaulin --locked
- name: Generate coverage report
run: |
mkdir -p coverage
cargo tarpaulin \
--out Json \
--output-dir ./coverage \
--fail-under 54
- name: Upload coverage reports
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
continue-on-error: true
- name: Generate summary
run: |
echo "## Code Coverage" >> $GITHUB_STEP_SUMMARY
REPORT=$(find coverage -name "*.json" -type f | head -1)
if [ -z "$REPORT" ]; then
echo "No coverage report found" >> $GITHUB_STEP_SUMMARY
else
python3 - "$REPORT" <<'PYEOF' >> $GITHUB_STEP_SUMMARY || echo "Failed to parse coverage report" >> $GITHUB_STEP_SUMMARY
import json, sys
with open(sys.argv[1]) as f:
d = json.load(f)
covered = d.get('covered', 0)
coverable = d.get('coverable', 1)
pct = covered / coverable * 100
print(f'**Coverage: {pct:.1f}%** ({covered}/{coverable} lines)')
PYEOF
fi
test:
name: Test (${{ matrix.target }})
needs: [lint, security, docs]
if: github.event_name != 'pull_request'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
sccache-arch: x86_64-unknown-linux-musl
- os: macos-latest
target: aarch64-apple-darwin
sccache-arch: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
sccache-arch: x86_64-pc-windows-msvc
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
sccache-arch: x86_64-unknown-linux-musl
use-cross: true
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install sccache (Linux / macOS)
if: runner.os != 'Windows'
shell: bash
run: |
URL="https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/sccache-v${SCCACHE_VERSION}-${{ matrix.sccache-arch }}.tar.gz"
curl -sSL "$URL" | tar -xz
mkdir -p "$CARGO_HOME/bin"
mv "sccache-v${SCCACHE_VERSION}-${{ matrix.sccache-arch }}/sccache" "$CARGO_HOME/bin/"
chmod +x "$CARGO_HOME/bin/sccache"
echo "RUSTC_WRAPPER=$CARGO_HOME/bin/sccache" >> "$GITHUB_ENV"
"$CARGO_HOME/bin/sccache" --start-server
- name: Install sccache (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$url = "https://github.com/mozilla/sccache/releases/download/v$env:SCCACHE_VERSION/sccache-v$env:SCCACHE_VERSION-${{ matrix.sccache-arch }}.tar.gz"
Invoke-WebRequest $url -OutFile sccache.tar.gz
tar -xzf sccache.tar.gz
$dest = "$env:CARGO_HOME\bin"
New-Item -ItemType Directory -Force -Path $dest | Out-Null
Move-Item "sccache-v$env:SCCACHE_VERSION-${{ matrix.sccache-arch }}\sccache.exe" "$dest\sccache.exe"
Add-Content $env:GITHUB_ENV "RUSTC_WRAPPER=$dest\sccache.exe"
& "$dest\sccache.exe" --start-server
- name: Cache sccache storage
uses: actions/cache@v4
with:
path: |
~/.cache/sccache
~/AppData/Local/Mozilla/sccache
key: ${{ runner.os }}-sccache-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-sccache-${{ matrix.target }}-
${{ runner.os }}-sccache-
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-registry-
- name: Cache build artifacts
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-${{ matrix.target }}-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-${{ matrix.target }}-target-
- name: Cache cross binary
if: matrix.use-cross == true
id: cache-cross
uses: actions/cache@v4
with:
path: ~/.cargo/bin/cross
key: cross-bin-v1
- name: Install cross
if: matrix.use-cross == true && steps.cache-cross.outputs.cache-hit != 'true'
run: cargo install cross --locked
- name: Build
shell: bash
run: |
if [ "${{ matrix.use-cross }}" = "true" ]; then
cross build --target ${{ matrix.target }}
else
cargo build --target ${{ matrix.target }}
fi
- name: Run tests
shell: bash
run: |
if [ "${{ matrix.use-cross }}" = "true" ]; then
cross test --target ${{ matrix.target }}
else
cargo test --target ${{ matrix.target }}
fi
- name: Test CLI
if: matrix.use-cross != true
shell: bash
run: |
cargo run -- -- tests/fixtures/github/valid.yml
cargo run -- tests/fixtures/github/circular.yml || true
- name: Print sccache stats
if: always() && runner.os != 'Windows'
shell: bash
run: $CARGO_HOME/bin/sccache --show-stats
continue-on-error: true
test-pr:
name: Test PR (${{ matrix.target }})
needs: [lint, security, docs]
if: github.event_name == 'pull_request'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
sccache-arch: x86_64-unknown-linux-musl
- os: macos-latest
target: aarch64-apple-darwin
sccache-arch: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
sccache-arch: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install sccache (Linux / macOS)
if: runner.os != 'Windows'
shell: bash
run: |
URL="https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/sccache-v${SCCACHE_VERSION}-${{ matrix.sccache-arch }}.tar.gz"
curl -sSL "$URL" | tar -xz
mkdir -p "$CARGO_HOME/bin"
mv "sccache-v${SCCACHE_VERSION}-${{ matrix.sccache-arch }}/sccache" "$CARGO_HOME/bin/"
chmod +x "$CARGO_HOME/bin/sccache"
echo "RUSTC_WRAPPER=$CARGO_HOME/bin/sccache" >> "$GITHUB_ENV"
"$CARGO_HOME/bin/sccache" --start-server
- name: Install sccache (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$url = "https://github.com/mozilla/sccache/releases/download/v$env:SCCACHE_VERSION/sccache-v$env:SCCACHE_VERSION-${{ matrix.sccache-arch }}.tar.gz"
Invoke-WebRequest $url -OutFile sccache.tar.gz
tar -xzf sccache.tar.gz
$dest = "$env:CARGO_HOME\bin"
New-Item -ItemType Directory -Force -Path $dest | Out-Null
Move-Item "sccache-v$env:SCCACHE_VERSION-${{ matrix.sccache-arch }}\sccache.exe" "$dest\sccache.exe"
Add-Content $env:GITHUB_ENV "RUSTC_WRAPPER=$dest\sccache.exe"
& "$dest\sccache.exe" --start-server
- name: Cache sccache storage
uses: actions/cache@v4
with:
path: |
~/.cache/sccache
~/AppData/Local/Mozilla/sccache
key: ${{ runner.os }}-sccache-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-sccache-${{ matrix.target }}-
${{ runner.os }}-sccache-
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-registry-
- name: Cache build artifacts
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-${{ matrix.target }}-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-${{ matrix.target }}-target-
- name: Build
shell: bash
run: cargo build --target ${{ matrix.target }}
- name: Run tests
shell: bash
run: cargo test --target ${{ matrix.target }}
- name: Test CLI
shell: bash
run: |
cargo run -- -- tests/fixtures/github/valid.yml
cargo run -- tests/fixtures/github/circular.yml || true
- name: Print sccache stats
if: always() && runner.os != 'Windows'
shell: bash
run: $CARGO_HOME/bin/sccache --show-stats
continue-on-error: true