diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e04542..877b8c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,10 +2,12 @@ name: CI on: push: - # `dev` is where work lands and where CI must be green. `main` only ever - # moves at release time, to the tagged commit, so a push to it is the - # release validation run rather than day-to-day feedback. - branches: [main, dev] + # 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: @@ -27,7 +29,7 @@ jobs: - uses: actions/checkout@v5 with: repository: freemkv/freemkv-unlock - ref: dev + ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}" path: freemkv-unlock - uses: dtolnay/rust-toolchain@1.97.0 with: @@ -65,7 +67,7 @@ jobs: - uses: actions/checkout@v5 with: repository: freemkv/freemkv-unlock - ref: dev + ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}" path: freemkv-unlock - uses: dtolnay/rust-toolchain@1.97.0 - uses: Swatinem/rust-cache@v2 @@ -92,7 +94,7 @@ jobs: - uses: actions/checkout@v5 with: repository: freemkv/freemkv-unlock - ref: dev + ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}" path: freemkv-unlock - uses: dtolnay/rust-toolchain@1.97.0 - uses: Swatinem/rust-cache@v2 @@ -119,7 +121,7 @@ jobs: - uses: actions/checkout@v5 with: repository: freemkv/freemkv-unlock - ref: dev + ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}" path: freemkv-unlock - uses: dtolnay/rust-toolchain@1.97.0 - uses: Swatinem/rust-cache@v2 @@ -150,19 +152,19 @@ jobs: - uses: actions/checkout@v5 with: { path: libfreemkv } - uses: actions/checkout@v5 - with: { repository: freemkv/freemkv-unlock, ref: dev, path: freemkv-unlock } + 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: dev, path: freemkv-keysources } + 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: dev, path: freemkv-engine } + 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: dev, path: freemkv-i18n } + with: { repository: freemkv/freemkv-i18n, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: freemkv-i18n } - uses: actions/checkout@v5 - with: { repository: freemkv/freemkv, ref: dev, path: freemkv } + with: { repository: freemkv/freemkv, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: freemkv } - uses: actions/checkout@v5 - with: { repository: freemkv/autorip, ref: dev, path: autorip } + with: { repository: freemkv/autorip, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: autorip } - uses: actions/checkout@v5 - with: { repository: freemkv/bdemu, ref: dev, path: bdemu } + with: { repository: freemkv/bdemu, ref: "${{ github.ref_name == 'qa' && 'qa' || 'dev' }}", path: bdemu } - name: Point every dependent at THIS libfreemkv commit shell: bash run: | diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml new file mode 100644 index 0000000..502f540 --- /dev/null +++ b/.github/workflows/qa.yml @@ -0,0 +1,75 @@ +name: qa + +# ── The qa gate: "is this production worth?" ──────────────────────────────── +# +# dev -> qa -> main. +# +# `dev` is for committing often. ci.yml answers "is it green" in minutes with +# fmt, clippy and the unit suite, so a mistake surfaces while it is still cheap +# to fix. `qa` is the release-candidate branch, and THIS workflow is the claim +# that a commit is production worth: everything expensive that can run without +# physical media. `main` only ever receives a qa that went green here. +# +# Sibling repos are checked out at `qa`, NOT `dev`. A qa run that resolved its +# dependencies from dev tips would be validating a combination that is not the +# one being released, which is the exact failure this branch exists to prevent. +# +# What this gate CANNOT cover: `disc://` and real `iso://` need physical media, +# and no hosted runner has an optical drive or the image hoard. Those run on a +# self-hosted runner (see the media job at the end) and are the one leg that +# stays on hardware. +on: + push: + branches: [qa] + workflow_dispatch: + +jobs: + # The debug suite runs on every dev push. Release is a DIFFERENT build: + # overflow checks are off, debug_assert! is compiled out, and inlining + # changes what the optimiser can prove. A test that only passes in debug is + # a test that never guarded the binary anyone actually ships. + release-tests: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v5 + with: + path: libfreemkv + - uses: actions/checkout@v5 + with: + repository: freemkv/freemkv-unlock + ref: qa + path: freemkv-unlock + - uses: dtolnay/rust-toolchain@1.97.0 + - uses: Swatinem/rust-cache@v2 + with: + workspaces: libfreemkv + - run: cargo test --release --tests + working-directory: libfreemkv + + # clippy's output is target-dependent: cfg-gated code only gets linted on + # the target it compiles for. Linting solely on the dev machine's host + # target is how a lint that CI rejects reaches a push. + cross-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + path: libfreemkv + - uses: actions/checkout@v5 + with: + repository: freemkv/freemkv-unlock + ref: qa + path: freemkv-unlock + - uses: dtolnay/rust-toolchain@1.97.0 + with: + components: clippy + - uses: Swatinem/rust-cache@v2 + with: + workspaces: libfreemkv + - run: rustup target add x86_64-unknown-linux-gnu + - run: cargo clippy --all-targets --target x86_64-unknown-linux-gnu -- -D warnings + working-directory: libfreemkv