name: Quality gates
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
quality:
name: Format, lint, test, docs, package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.13"
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy,rustfmt
- uses: taiki-e/install-action@cargo-llvm-cov
- uses: taiki-e/install-action@cargo-deny
- name: Run enforced quality gate
run: ./scripts/quality_gates.sh
platforms:
name: Test ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --workspace --all-features
msrv:
name: Rust 1.90 MSRV
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@1.90.0
- run: cargo check --workspace --all-features
dependency-policy:
name: Dependency and license policy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: EmbarkStudios/cargo-deny-action@v2
with:
rust-version: "1.90.0"
arguments: --all-features
semver:
name: Public API compatibility
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: "3.13"
- name: Prepare API baseline
env:
BASELINE_REF: ${{ github.event.pull_request.base.sha || 'HEAD^' }}
run: |
mkdir .semver-baseline
git archive "${BASELINE_REF}" | tar -x -C .semver-baseline
python3 scripts/prepare_semver_baseline.py .semver-baseline
- name: Prepare exact compatibility contract
id: compatibility
run: |
current=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
baseline=$(sed -n 's/^version = "\([^"]*\)"/\1/p' .semver-baseline/Cargo.toml | head -1)
if [ "${baseline}" = "1.0.0" ] && [ "${current}" = "1.1.0" ]; then
cp -R .semver-baseline .semver-authorized
python3 scripts/prepare_machine_1_1_semver_baseline.py .semver-authorized
echo "baseline_root=.semver-authorized" >> "${GITHUB_OUTPUT}"
echo "machine_exception=true" >> "${GITHUB_OUTPUT}"
else
echo "baseline_root=.semver-baseline" >> "${GITHUB_OUTPUT}"
echo "machine_exception=false" >> "${GITHUB_OUTPUT}"
fi
- name: Enforce compatibility outside the exact Machine exception
uses: obi1kenobi/cargo-semver-checks-action@v2
with:
package: stateforward-sml
feature-group: all-features
baseline-root: ${{ steps.compatibility.outputs.baseline_root }}
release-type: patch
- name: Prepare unrelated-break negative control
if: steps.compatibility.outputs.machine_exception == 'true'
run: |
mkdir .semver-negative
git archive HEAD | tar -x -C .semver-negative
python3 scripts/prepare_semver_negative_control.py .semver-negative
- name: Prove unrelated breaking changes still fail
if: steps.compatibility.outputs.machine_exception == 'true'
id: negative_control
continue-on-error: true
uses: obi1kenobi/cargo-semver-checks-action@v2
with:
manifest-path: .semver-negative/Cargo.toml
package: stateforward-sml
feature-group: all-features
baseline-root: .semver-authorized
release-type: patch
- name: Require the negative control to fail
if: steps.compatibility.outputs.machine_exception == 'true'
env:
NEGATIVE_OUTCOME: ${{ steps.negative_control.outcome }}
run: test "${NEGATIVE_OUTCOME}" = failure
links:
name: Documentation links
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: lycheeverse/lychee-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: >-
--no-progress
--exclude-path target
--exclude-path fuzz/corpus
'./**/*.md'