dev -> qa -> main, across every public repo. dev is where work lands and is meant to be pushed to often, so ci.yml stays the fast answer: fmt, clippy, unit tests, leak-guard. qa is the release candidate, and qa.yml is the claim that a commit is production worth — release-profile tests on all three platforms, and the Linux cross-target clippy that the local precommit gate has always run but CI never did. Release profile matters as its own gate: overflow checks are off, debug_assert is compiled out, and inlining changes what the optimiser can prove. A test that only passes in debug never guarded the binary anyone ships. qa.yml checks siblings out at qa rather than dev. This is not a monorepo, and a qa run resolving its dependencies from unreleased dev tips would go green on a combination that is not the one shipping — the exact mismatch the branch model exists to prevent. ci.yml now tracks whichever branch triggered it for the same reason, since it also fires on qa. The consequence is that repos move to qa together, in dependency order. qa is backfilled from main so an unchanged crate still presents working code to the crates built on it.
200 lines
8.8 KiB
YAML
200 lines
8.8 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
# dev -> qa -> main. `dev` is where work lands and is meant to be pushed
|
|
# to often: these are the FAST checks, so a mistake surfaces in minutes.
|
|
# `qa` is the release candidate — it runs these too, plus the expensive
|
|
# suite in qa.yml. `main` only ever moves at release time, to a tagged
|
|
# commit that was already green on qa.
|
|
branches: [main, dev, qa]
|
|
pull_request:
|
|
|
|
jobs:
|
|
lint:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
path: libfreemkv
|
|
# libfreemkv path-deps ../freemkv-unlock on the BRANCH tip (release.sh
|
|
# swaps it to a git tag only inside the tagged commit, then restores the
|
|
# path dep). CI checks out one repo, so the branch tip has never been
|
|
# buildable here — every green run you have ever seen was a tag build,
|
|
# and Windows/Linux were first compiled at release time.
|
|
#
|
|
# Both repos go into subdirectories because actions/checkout refuses a
|
|
# `path:` outside $GITHUB_WORKSPACE, and `../freemkv-unlock` is outside.
|
|
# With this layout the path dep resolves exactly as it does locally.
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
repository: freemkv/freemkv-unlock
|
|
ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}"
|
|
path: freemkv-unlock
|
|
- uses: dtolnay/rust-toolchain@1.97.0
|
|
with:
|
|
components: clippy, rustfmt
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: libfreemkv
|
|
- run: cargo fmt --check
|
|
working-directory: libfreemkv
|
|
# libfreemkv is a library — Cargo.lock is gitignored. --locked
|
|
# would always fail on a fresh runner because there's no committed
|
|
# lockfile to lock against. The binary crates (freemkv, autorip,
|
|
# bdemu) track Cargo.lock and DO use --locked.
|
|
# --all-targets so TEST code is linted too. Without it this crate — the
|
|
# reference implementation for the other seven — was the only one whose
|
|
# tests had never been linted at all, and it was hiding 74 findings.
|
|
- run: cargo clippy --all-targets -- -D warnings
|
|
working-directory: libfreemkv
|
|
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
path: libfreemkv
|
|
# libfreemkv path-deps ../freemkv-unlock on the BRANCH tip (release.sh
|
|
# swaps it to a git tag only inside the tagged commit, then restores the
|
|
# path dep). CI checks out one repo, so the branch tip has never been
|
|
# buildable here — every green run you have ever seen was a tag build,
|
|
# and Windows/Linux were first compiled at release time.
|
|
#
|
|
# Both repos go into subdirectories because actions/checkout refuses a
|
|
# `path:` outside $GITHUB_WORKSPACE, and `../freemkv-unlock` is outside.
|
|
# With this layout the path dep resolves exactly as it does locally.
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
repository: freemkv/freemkv-unlock
|
|
ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}"
|
|
path: freemkv-unlock
|
|
- uses: dtolnay/rust-toolchain@1.97.0
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: libfreemkv
|
|
- run: cargo test --tests
|
|
working-directory: libfreemkv
|
|
|
|
check-macos:
|
|
runs-on: macos-latest
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
path: libfreemkv
|
|
# libfreemkv path-deps ../freemkv-unlock on the BRANCH tip (release.sh
|
|
# swaps it to a git tag only inside the tagged commit, then restores the
|
|
# path dep). CI checks out one repo, so the branch tip has never been
|
|
# buildable here — every green run you have ever seen was a tag build,
|
|
# and Windows/Linux were first compiled at release time.
|
|
#
|
|
# Both repos go into subdirectories because actions/checkout refuses a
|
|
# `path:` outside $GITHUB_WORKSPACE, and `../freemkv-unlock` is outside.
|
|
# With this layout the path dep resolves exactly as it does locally.
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
repository: freemkv/freemkv-unlock
|
|
ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}"
|
|
path: freemkv-unlock
|
|
- uses: dtolnay/rust-toolchain@1.97.0
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: libfreemkv
|
|
- run: cargo check
|
|
working-directory: libfreemkv
|
|
|
|
check-windows:
|
|
runs-on: windows-latest
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
path: libfreemkv
|
|
# libfreemkv path-deps ../freemkv-unlock on the BRANCH tip (release.sh
|
|
# swaps it to a git tag only inside the tagged commit, then restores the
|
|
# path dep). CI checks out one repo, so the branch tip has never been
|
|
# buildable here — every green run you have ever seen was a tag build,
|
|
# and Windows/Linux were first compiled at release time.
|
|
#
|
|
# Both repos go into subdirectories because actions/checkout refuses a
|
|
# `path:` outside $GITHUB_WORKSPACE, and `../freemkv-unlock` is outside.
|
|
# With this layout the path dep resolves exactly as it does locally.
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
repository: freemkv/freemkv-unlock
|
|
ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}"
|
|
path: freemkv-unlock
|
|
- uses: dtolnay/rust-toolchain@1.97.0
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: libfreemkv
|
|
# Build the tests (not just `cargo check`): catches errors in test
|
|
# code and forces full codegen of the Windows-only SPTI transport
|
|
# (src/scsi/windows.rs), which never compiles on the Linux/macOS dev
|
|
# hosts. We don't `cargo test` here — the suite needs no drive but the
|
|
# extra build is the value; running tests is covered by the Linux job.
|
|
- run: cargo build --tests
|
|
working-directory: libfreemkv
|
|
|
|
# ── Did this change break anything downstream? ──────────────────────────────
|
|
#
|
|
# Every job above proves libfreemkv builds. None proved its DEPENDENTS do,
|
|
# and that gap is real: an engine signature change broke autorip today and
|
|
# went unnoticed because consumer CI only fires on a push to that consumer.
|
|
# libfreemkv sits below all five of them, so a break here is worth strictly
|
|
# more than a break anywhere else in the project.
|
|
#
|
|
# `cargo check --all-targets` only — each dependent owns its own behaviour
|
|
# and has its own suite. The question here is just "does everything built on
|
|
# me still compile against this commit".
|
|
consumers:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with: { path: libfreemkv }
|
|
- uses: actions/checkout@v5
|
|
with: { repository: freemkv/freemkv-unlock, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: freemkv-unlock }
|
|
- uses: actions/checkout@v5
|
|
with: { repository: freemkv/freemkv-keysources, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: freemkv-keysources }
|
|
- uses: actions/checkout@v5
|
|
with: { repository: freemkv/freemkv-engine, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: freemkv-engine }
|
|
- uses: actions/checkout@v5
|
|
with: { repository: freemkv/freemkv-i18n, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: freemkv-i18n }
|
|
- uses: actions/checkout@v5
|
|
with: { repository: freemkv/freemkv, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: freemkv }
|
|
- uses: actions/checkout@v5
|
|
with: { repository: freemkv/autorip, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: autorip }
|
|
- uses: actions/checkout@v5
|
|
with: { repository: freemkv/bdemu, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: bdemu }
|
|
- name: Point every dependent at THIS libfreemkv commit
|
|
shell: bash
|
|
run: |
|
|
for c in freemkv-keysources freemkv-engine freemkv autorip bdemu; do
|
|
mkdir -p "$c/.cargo"
|
|
cat > "$c/.cargo/config.toml" <<'EOF'
|
|
[patch.crates-io]
|
|
libfreemkv = { path = "../libfreemkv" }
|
|
freemkv-keysources = { path = "../freemkv-keysources" }
|
|
freemkv-engine = { path = "../freemkv-engine" }
|
|
freemkv-i18n = { path = "../freemkv-i18n" }
|
|
EOF
|
|
done
|
|
- uses: dtolnay/rust-toolchain@1.97.0
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: |
|
|
freemkv-keysources
|
|
freemkv-engine
|
|
freemkv
|
|
autorip
|
|
bdemu
|
|
- run: cargo check --all-targets
|
|
working-directory: freemkv-keysources
|
|
- run: cargo check --all-targets
|
|
working-directory: freemkv-engine
|
|
- run: cargo check --all-targets
|
|
working-directory: freemkv
|
|
- run: cargo check --all-targets
|
|
working-directory: autorip
|
|
- run: cargo check --all-targets
|
|
working-directory: bdemu
|