Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 100 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ env:
# every GitHub Actions “stable” bump. Bump intentionally with the toolchain.
#
# Each gate is its own check. Short ubuntu gates share one runner so
# concurrent-job slots stay free for clippy, test, and future cargo-mutants
# shards (mutants.yml):
# concurrent-job slots stay free for clippy, test, coverage, and the PR
# mutants shards:
# fmt → deny → ast-grep → nixos-module-eval
# Later gates use !cancelled() so a red earlier gate still reports its own
# check (a skip would hide required deny / ast-grep).
# clippy, test, windows, and macos start immediately. clippy stays parallel:
# coverage waits on it, and a cold rust-cache is a full workspace compile.
# coverage waits for fmt / clippy / test.
# coverage and the advisory mutants shards wait for fmt / clippy / test.
# Weekly full mutants sweep stays mutants.yml.
# nixos-module-runtime is a labeled job (nixos-module-runtime.yml), not this file.
# Operator binaries are GitHub Releases (release.yml), not this workflow.
#
Expand Down Expand Up @@ -204,6 +205,102 @@ jobs:
- name: store + node smoke
run: ./scripts/ci-os-smoke.sh

# Crates, Cargo manifest/lock, or these workflow files. Docs-only PRs
# skip the four shard runners. Starts immediately; shards still wait for test.
mutants-diff:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
rust: ${{ steps.d.outputs.rust }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: rust or workflow diff
id: d
env:
BASE_REF: ${{ github.base_ref }}
run: |
set -euo pipefail
git diff "origin/${BASE_REF}".. --unified=0 -- \
crates Cargo.toml Cargo.lock \
.github/workflows/ci.yml .github/workflows/mutants.yml \
> git.diff
if [[ -s git.diff ]]; then
echo "rust=true" >> "$GITHUB_OUTPUT"
else
echo "rust=false" >> "$GITHUB_OUTPUT"
fi

# PR in-diff, four shards, same window as coverage. Advisory: a missed
# mutant does not fail the job. One ~300-mutant diff at -j 2 is ~50m and
# was canceled at 30m. Weekly sweep stays mutants.yml. Owner: TESTING.md.
mutants:
name: mutants (${{ matrix.shard }}/4)
needs: [fmt, clippy, test, mutants-diff]
if: >-
github.event_name == 'pull_request'
&& needs.fmt.result == 'success'
&& needs.clippy.result == 'success'
&& needs.test.result == 'success'
&& needs.mutants-diff.result == 'success'
&& needs.mutants-diff.outputs.rust == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2, 3]
env:
# Workflow env disables incremental for rust-cache and denies warnings.
# cargo-mutants rebuilds one mutant at a time; incremental is the point.
# Weekly mutants.yml does not pass -D warnings. A warning-only build
# failure would look caught here and missed on Sunday.
CARGO_INCREMENTAL: "1"
CARGO_TERM_COLOR: never
RUSTFLAGS: ""
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@a5f673d0ba8626c3977bb416a1612774bc82181b # rustc 1.95.0
- uses: taiki-e/install-action@9534c84618278caac52cb373bb164ed464dbd8af # v2.87.11
with:
tool: cargo-mutants@27.1.0
- name: in-diff shard
id: run
continue-on-error: true
env:
BASE_REF: ${{ github.base_ref }}
run: |
set -euo pipefail
git diff "origin/${BASE_REF}".. --unified=0 > git.diff
set +e
cargo mutants --workspace --in-diff git.diff \
--shard "${{ matrix.shard }}/4" --sharding slice -j 2 \
> mutants-shard.log 2>&1
ec=$?
set -e
missed=$(grep -c '^MISSED' mutants-shard.log || true)
echo "missed=${missed}" >> "$GITHUB_OUTPUT"
cat mutants-shard.log
exit "$ec"
- name: summary
if: always()
run: |
{
echo "### mutants ${{ matrix.shard }}/4"
echo "Advisory (not a merge gate). Outcome: ${{ steps.run.outcome }}. Missed: ${{ steps.run.outputs.missed }}."
} >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: mutants-pr-${{ matrix.shard }}
path: mutants.out
if-no-files-found: ignore
retention-days: 5

# Line-coverage 92% floor + CRAP --fail-above 30 (allowlist in .cargo-crap.toml).
# Slow; waits for the fast gates so a red fmt/clippy/test does not start
# this job. Required. Job+step timeouts so a hung llvm-cov test binary
Expand Down
31 changes: 2 additions & 29 deletions .github/workflows/mutants.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Weekly cargo-mutants + PR in-diff advisory. Not a required PR check.
# Weekly cargo-mutants. Not a required check.
# PR in-diff shards are ci.yml job `mutants` (parallel with coverage).
# Must pass --workspace: default-members is rbitcoin-node only.
# Owner: TESTING.md (Mutation testing). Snapshot lists: docs/mutants/.

Expand All @@ -7,40 +8,12 @@ on:
schedule:
- cron: "0 3 * * 0"
workflow_dispatch:
pull_request:
paths:
- "Cargo.toml"
- "Cargo.lock"
- "crates/**"
- ".github/workflows/mutants.yml"

permissions:
contents: read

jobs:
mutants-pr:
if: github.event_name == 'pull_request'
concurrency:
group: mutants-pr-${{ github.ref }}
cancel-in-progress: true
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: false
fetch-depth: 0
- uses: dtolnay/rust-toolchain@a5f673d0ba8626c3977bb416a1612774bc82181b # rustc 1.95.0
- uses: taiki-e/install-action@9534c84618278caac52cb373bb164ed464dbd8af # v2.87.11
with:
tool: cargo-mutants@27.1.0
- run: git diff origin/${{ github.base_ref }}.. --unified=0 > git.diff
- run: cargo mutants --workspace --in-diff git.diff -j 2
continue-on-error: true

mutants-weekly:
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 360
strategy:
Expand Down
18 changes: 12 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,21 @@ before 1.0).

### Changed

- **PR cargo-mutants is 4 in-diff shards:** `ci.yml` `mutants`, after
fmt/clippy/test, in parallel with coverage. Advisory
(`continue-on-error`), not a merge gate. One 30-minute job was canceled
on a ~300-mutant diff (`-j 2` is about 50 minutes). Weekly 8-shard sweep
is unchanged.

- **CI short gates share one runner:** `fmt` → `deny` → `ast-grep` →
`nixos-module-eval`. clippy, test, windows, and macos still start
immediately. Concurrent-job slots stay free for future cargo-mutants
shards.
immediately. Concurrent-job slots stay free for coverage and the PR
mutants shards.

- **Weekly cargo-mutants:** `mutants.yml` — PR `--workspace --in-diff`
advisory (`continue-on-error`); Sunday 8-shard `--workspace` sweep.
Must use `--workspace` (`default-members` is node). Snapshot lists:
[`docs/mutants/`](docs/mutants/). How to run: [`TESTING.md`](TESTING.md).
- **Weekly cargo-mutants:** `mutants.yml` — Sunday 8-shard `--workspace`
sweep. Must use `--workspace` (`default-members` is node). Snapshot
lists: [`docs/mutants/`](docs/mutants/). How to run:
[`TESTING.md`](TESTING.md).

- **Electrum/Esplora no longer require `--sh-index` to bind.** Address and
scripthash methods return `scripthash index disabled` (Electrum JSON-RPC
Expand Down
2 changes: 1 addition & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ matches scalar in default tests). Owner: [`docs/quality.md`](./docs/quality.md).
| **cargo-crap** | After LCOV, `./scripts/coverage.sh` calls `./scripts/coverage-crap.sh` (skip if `cargo-crap` missing). `--fail-above --threshold 30`; `.cargo-crap.toml` allowlists today's production CRAP>30 functions (remove a name when it scores ≤30). Dry-run: `CRAP_DRY_RUN=1 ./scripts/coverage-crap.sh`. Self-test: `./scripts/coverage-crap.test.sh` | Rides required `coverage`. No `--fail-regression` (llvm-cov coverage % jitters per function) |
| **coverage ignore / badge** | `./scripts/coverage.test.sh` (filename ignore, Tier A IBD not skipped, 92% floor, Shields JSON). Publish dry-run: `BADGE_DRY_RUN=1 ./scripts/publish-coverage-badge.sh` | `test` job self-test; `coverage` job writes `coverage/badge.json` and, on green `master`, pushes `badges/coverage.json` |
| **Miri** | `./scripts/miri.sh` → `cargo +nightly miri test -p rbitcoin-primitives`. Dry-run: `MIRI_DRY_RUN=1 ./scripts/miri.sh`. Self-test: `./scripts/miri.test.sh` | Nightly `miri.yml` (not required). Never `--workspace` |
| **cargo-mutants** | Must pass `--workspace` (`Cargo.toml` `default-members` is `rbitcoin-node` only; without `--workspace` the list is ~7 mutants). PR advisory: `git diff origin/<base>.. --unified=0 > git.diff` then `cargo mutants --workspace --in-diff git.diff -j 2`. Weekly: `cargo mutants --workspace --shard N/8 -j 2`. Snapshot of missed/timeouts: [`docs/mutants/`](docs/mutants/). | Weekly `mutants.yml` Sunday 03:00 UTC, 8 shards, 360min cap (not required). `workflow_dispatch`. PR job `mutants-pr` is `continue-on-error` (not a merge gate). First Sunday wall-clock is still a measurement. |
| **cargo-mutants** | Must pass `--workspace` (`Cargo.toml` `default-members` is `rbitcoin-node` only; without `--workspace` the list is ~7 mutants). PR: `git diff origin/<base>.. --unified=0 > git.diff` then `cargo mutants --workspace --in-diff git.diff --shard k/4 --sharding slice -j 2` (same flags on every shard). Weekly: `cargo mutants --workspace --shard N/8 -j 2`. Snapshot of missed/timeouts: [`docs/mutants/`](docs/mutants/). | PR: `ci.yml` `mutants`, 4 shards, needs fmt/clippy/test (same window as coverage). `continue-on-error` (not a merge gate). Skipped when the diff does not touch `crates/`, `Cargo.toml`, `Cargo.lock`, `ci.yml`, or `mutants.yml`. Weekly `mutants.yml` Sunday 03:00 UTC, 8 shards, 360min cap (not required). `workflow_dispatch`. First Sunday wall-clock is still a measurement. |

Artifact silos above are unchanged: ast-grep / Miri dry-run / crap dry-run do
not write `target/`. `mutants.out/` is gitignored.
Expand Down
Loading