crapkit 0.4.8
A composite action that comments the worklist and the verdict on a pull request
action.yml at the repository root makes crapkit four lines in a consumer's workflow:
- uses: JeanFrancoisGagne/crapkit@v0.4.8
with:
gate: "false"The action sets up python, installs crapkit, and runs crapkit coverage --json,
crapkit verify --json --reuse-artifacts and crapkit worklist --json in the consumer's
checkout. The three payloads become one comment: what the run measured, the verdict line
with verify's own exit code, and the ranked worklist rows for the files the pull request
changed. A hidden <!-- crapkit-action --> line lets the next push find that comment
through the API and edit it, so a fifteen-push branch carries one comment and not fifteen.
A push event has no pull request to carry one, and the same text goes to the job log
instead.
The install reads $GITHUB_ACTION_PATH, the action's own checkout, rather than
pip install crapkit: the crapkit that scores a tree is the one in the ref the consumer
pinned in uses:, so @v0.4.8 cannot drift to whatever released last.
gate decides the exit code. false, the default, exits 0 whatever verify found and
leaves the comment as the whole output, which is how a team adopts the action before it
has decided which findings should stop a merge. true exits with verify's code, so a
finding fails the check. top caps the rendered rows at 5 by default and
python-version picks the interpreter. Posting the comment needs pull-requests: write
and nothing else.
What the verdict covers is worth reading once. The baseline is the coverage run the same
job wrote a step earlier, so on a clean checkout verify judges an empty diff and reports
the tree's own health rather than the pull request's delta. README's
The GitHub Action says so in the same words and names the
portable baseline that makes it judge the diff instead.
crapkit's own dogfood job runs the action on crapkit with uses: ./, on every push and
every pull request. action.yml is read by the runner and never imported, so that job is
the only thing that executes its steps; tests/unit/test_action_contract.py covers what a
unit test can, which is that the file parses, that every step names its shell, that every
crapkit call in it exists on the parser with the flags it passes, and that the marker
the builder writes is the one the action greps for.
The README and the handbook open with a generated demo
docs/demo.gif and docs/demo.svg show a 90-second terminal session: init sniffing a
small Python repo, coverage scoring it, worklist --top 5 ranking it, a shell heredoc
appending a function at ccn 7 while the per-edit advisory reports it and exits 2, and the
commit gate refusing the staged file with exit 6. The README embeds the GIF under its
badges and the handbook shows it on its first screen.
Nothing in the frames is written by hand. python tools/demo/generate.py builds a git
repo from the fixture under tools/demo/fixture/, replays its commit plan so the
worklist has real churn to rank, runs those five commands against this checkout's crapkit
and renders what they printed. Every captured line goes through a redaction pass that
strips the temp repo's path, wall-clock stamps and durations, and the generator refuses
to write an image if a machine path survived it. Two runs on an unchanged tree write
byte-identical files, which tests/unit/test_demo_generator.py holds them to, so
regenerating the demo for a release is a no-op unless the output actually moved.
The handbook's lanes section also links a new note on pytest-cov 7 and subprocess
coverage, beside the lane rules it belongs to.
A note on the Pages site: what pytest-cov 7 stopped measuring
docs/notes/pytest-cov-7-subprocess-coverage.html writes up the trap that made crapkit
floor coverage>=7.10.6 and set [tool.coverage.run] patch = ["subprocess"] in the first
place, for readers who will never install crapkit. pytest-cov 7.0.0 (2025-09-09) dropped
its own subprocess measurement, so any suite that drives a CLI through subprocess.run
loses the coverage of every entry point on upgrade, with nothing printed and the tests
still green.
The numbers on the page are not remembered, they are produced.
tools/notes/pytest_cov7_repro.py builds one virtualenv per pytest-cov pin, installs
crapkit editable into each, and runs tests/e2e/test_init_doctor_e2e.py four times: two
pins times the patch key present and absent. It toggles the key through
COVERAGE_RCFILE, so the tree under measurement is never edited, and writes the executed
and total statement counts for src/crapkit/cli/admin.py to
tools/notes/pytest_cov7_repro.json. Committed run: 324/521 statements under pytest-cov
6.3.0 with or without the key, 324/521 under 7.1.0 with it, and 0/521 under 7.1.0 without
it. All four runs exited 0.
tests/unit/test_notes_contract.py joins the two. Every measurement row on the page has
to match the JSON on the pin, the coverage version, the state of the key and the count, so
a number edited by hand fails the suite.