| 1 | name: Release parity |
| 2 | |
| 3 | # The one parity gate. release-candidate.yml and release.yml both call this, |
| 4 | # so the SHA an RC validates has passed exactly the gate that publish runs. |
| 5 | # Before this was shared, the RC skipped parity: RC 35707500620 was green on |
| 6 | # 3e8bf29946, Release 35728585975 then failed parity on that SHA, and v0.10.0 |
| 7 | # was re-pointed to 1be1a703b, which docs/RELEASE_RUNBOOK.md forbids. |
| 8 | # |
| 9 | # Checks out the caller's GITHUB_SHA. Callers must verify that SHA first. |
| 10 | on: |
| 11 | workflow_call: |
| 12 | |
| 13 | permissions: |
| 14 | contents: read |
| 15 | |
| 16 | env: |
| 17 | CARGO_TERM_COLOR: always |
| 18 | CARGO_INCREMENTAL: 0 |
| 19 | RUSTFLAGS: -Dwarnings |
| 20 | |
| 21 | jobs: |
| 22 | parity: |
| 23 | name: Workspace parity |
| 24 | timeout-minutes: 45 |
| 25 | runs-on: ubuntu-latest |
| 26 | steps: |
| 27 | # Every caller's resolve job already proved GITHUB_SHA equals the |
| 28 | # candidate or tag commit. Do not interpolate a SHA into checkout or |
| 29 | # cache keys — |
| 30 | # CodeQL treats a *sha* ref as an untrusted checkout on workflow_dispatch |
| 31 | # (default-branch cache write). |
| 32 | - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 |
| 33 | - uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master 2026-07-18 |
| 34 | with: |
| 35 | toolchain: stable |
| 36 | components: clippy, rustfmt |
| 37 | - uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 |
| 38 | id: sccache |
| 39 | continue-on-error: true |
| 40 | - name: Enable sccache |
| 41 | if: steps.sccache.outcome == 'success' |
| 42 | shell: bash |
| 43 | run: | |
| 44 | { |
| 45 | echo "SCCACHE_GHA_ENABLED=true" |
| 46 | echo "RUSTC_WRAPPER=sccache" |
| 47 | echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" |
| 48 | } >> "${GITHUB_ENV}" |
| 49 | - name: Install Linux system dependencies |
| 50 | run: | |
| 51 | for i in 1 2 3 4 5; do |
| 52 | sudo apt-get update && break |
| 53 | echo "apt-get update failed (attempt $i); retrying in 15s" |
| 54 | sleep 15 |
| 55 | done |
| 56 | sudo apt-get install -y libdbus-1-dev pkg-config |
| 57 | # Restore after the trusted lockfile is on disk. Key is OS + arch + |
| 58 | # explicit stable toolchain + rust-cache's Cargo.lock / rust-toolchain |
| 59 | # hash. Never interpolate github.event, github.ref, github.sha, or inputs. |
| 60 | - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 |
| 61 | with: |
| 62 | cache-bin: false |
| 63 | prefix-key: v1-${{ runner.os }}-${{ runner.arch }}-stable |
| 64 | - uses: taiki-e/install-action@e88e69ecdb9658bd172693dcdc2c84e7f0ab6a11 # nextest |
| 65 | with: |
| 66 | tool: nextest |
| 67 | - name: Format check |
| 68 | run: cargo fmt --all -- --check |
| 69 | - name: Compile check |
| 70 | run: cargo check --workspace --all-targets --locked |
| 71 | - name: OHOS dependency graph |
| 72 | run: ./scripts/release/check-ohos-deps.sh |
| 73 | - name: Clippy |
| 74 | # Same lint set as ci.yml's "Run clippy": collapsible_if and |
| 75 | # assertions_on_constants were removed there on purpose, so allowing |
| 76 | # them here made the release gate weaker than the merge gate. |
| 77 | run: | |
| 78 | cargo clippy --workspace --all-targets --all-features --locked -- \ |
| 79 | -D warnings \ |
| 80 | -A clippy::uninlined_format_args \ |
| 81 | -A clippy::too_many_arguments \ |
| 82 | -A clippy::unnecessary_map_or |
| 83 | - name: Build headroom |
| 84 | # Same fixed ephemeral-runner provisioning as CI Safety, Lint, and Test. |
| 85 | # Resource headroom is preventive; a shutdown alone does not prove OOM. |
| 86 | shell: bash |
| 87 | run: bash scripts/prepare-ubuntu-build-headroom.sh |
| 88 | - name: Build canonical executable for acceptance tests |
| 89 | run: cargo build -p codewhale-cli --bin codewhale --all-features --locked |
| 90 | - name: Workspace tests |
| 91 | # Same test binaries as `cargo test`, run by cargo-nextest: one process |
| 92 | # per test. This gate used libtest, where every test shares one process, |
| 93 | # so a test that mutates process-global state leaks into its neighbours. |
| 94 | # It failed on five such tests — deterministically, and on a different |
| 95 | # set on different machines — while CI's nextest lanes were green on the |
| 96 | # same source, and every one of them passes in isolation. Match the lane |
| 97 | # that gates every merge; doctests are the next step, because nextest |
| 98 | # does not run them. |
| 99 | # The runner has been shut down during this step's build on several |
| 100 | # candidates (exit 143, no test result). The same headroom trace as |
| 101 | # ci.yml's test step records whether memory or disk ran out, starting |
| 102 | # with what the earlier check and clippy steps left behind. |
| 103 | shell: bash |
| 104 | run: | |
| 105 | echo "[headroom] before tests: $(free -m | awk '/^Mem:/{print "mem used " $3 "/" $2 " MiB"} /^Swap:/{print "swap used " $3 "/" $2 " MiB"}' | paste -sd ' ') disk free $(df -h / | awk 'NR==2{print $4}') target $(du -sh target 2>/dev/null | cut -f1)" |
| 106 | ( while sleep 30; do |
| 107 | echo "[headroom] $(free -m | awk '/^Mem:/{print "mem used " $3 "/" $2 " MiB"} /^Swap:/{print "swap used " $3 "/" $2 " MiB"}' | paste -sd ' ') disk free $(df -h / | awk 'NR==2{print $4}')" |
| 108 | done ) & |
| 109 | monitor=$! |
| 110 | status=0 |
| 111 | sh scripts/with-hermetic-test-home.sh cargo nextest run --workspace --all-features --locked --profile ci || status=$? |
| 112 | kill "$monitor" 2>/dev/null || true |
| 113 | exit "$status" |
| 114 | env: |
| 115 | # Match the CI test lane: test threads get the same stack the product |
| 116 | # gives itself (main.rs CODEWHALE_MAIN_STACK_BYTES). See the note in |
| 117 | # ci.yml's "Run tests" step. Without it this gate runs the deep |
| 118 | # engine/runtime futures on a stack that never ships. |
| 119 | RUST_MIN_STACK: '16777216' |
| 120 | - name: Workspace doctests |
| 121 | run: sh scripts/with-hermetic-test-home.sh cargo test --workspace --all-features --locked --doc |
| 122 | env: |
| 123 | RUST_MIN_STACK: '16777216' |
| 124 | - name: Protocol schema parity |
| 125 | run: sh scripts/with-hermetic-test-home.sh cargo test -p codewhale-protocol --test parity_protocol --locked |
| 126 | - name: State persistence parity |
| 127 | run: sh scripts/with-hermetic-test-home.sh cargo test -p codewhale-state --test parity_state --locked |
| 128 | - name: Lockfile drift guard |
| 129 | run: git diff --exit-code -- Cargo.lock |
| 130 |