crapkit 0.4.7__tar.gz → 0.4.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. {crapkit-0.4.7 → crapkit-0.4.9}/PKG-INFO +150 -3
  2. crapkit-0.4.7/src/crapkit.egg-info/PKG-INFO → crapkit-0.4.9/README.md +1147 -1039
  3. {crapkit-0.4.7 → crapkit-0.4.9}/pyproject.toml +1 -1
  4. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/__init__.py +1 -1
  5. crapkit-0.4.7/README.md → crapkit-0.4.9/src/crapkit.egg-info/PKG-INFO +1186 -1000
  6. {crapkit-0.4.7 → crapkit-0.4.9}/LICENSE +0 -0
  7. {crapkit-0.4.7 → crapkit-0.4.9}/setup.cfg +0 -0
  8. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/__main__.py +0 -0
  9. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/_pygdefer.py +0 -0
  10. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/analyze.py +0 -0
  11. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cache.py +0 -0
  12. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/churn.py +0 -0
  13. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/churn_cache.py +0 -0
  14. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/churn_log.py +0 -0
  15. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/__init__.py +0 -0
  16. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/_shared.py +0 -0
  17. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/admin.py +0 -0
  18. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/analyses.py +0 -0
  19. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/claude_hook.py +0 -0
  20. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/parser.py +0 -0
  21. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/queue.py +0 -0
  22. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/ratchet_cmds.py +0 -0
  23. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/reports.py +0 -0
  24. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/scoring.py +0 -0
  25. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/cli/verifying.py +0 -0
  26. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/config.py +0 -0
  27. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/coupling.py +0 -0
  28. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/coupling_cache.py +0 -0
  29. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/coverage_istanbul.py +0 -0
  30. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/coverage_py.py +0 -0
  31. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/covstream.py +0 -0
  32. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/diffparse.py +0 -0
  33. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/digest.py +0 -0
  34. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/discover.py +0 -0
  35. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/doctor.py +0 -0
  36. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/dup.py +0 -0
  37. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/errors.py +0 -0
  38. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/gitio.py +0 -0
  39. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/hook.py +0 -0
  40. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/junitparse.py +0 -0
  41. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/keys.py +0 -0
  42. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/lanes.py +0 -0
  43. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/lizardcognitive.py +0 -0
  44. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/lizardpowershell.py +0 -0
  45. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/lizardrust.py +0 -0
  46. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/lizardshell.py +0 -0
  47. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/mcp_server.py +0 -0
  48. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/merge.py +0 -0
  49. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/mutate.py +0 -0
  50. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/mutate_pool.py +0 -0
  51. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/override.py +0 -0
  52. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/packet.py +0 -0
  53. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/procs.py +0 -0
  54. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/ratchet.py +0 -0
  55. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/ratchet_report.py +0 -0
  56. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/report.py +0 -0
  57. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/sarif.py +0 -0
  58. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/sarifio.py +0 -0
  59. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/scaffold.py +0 -0
  60. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/score.py +0 -0
  61. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/snapshot.py +0 -0
  62. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/store.py +0 -0
  63. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/uncovered.py +0 -0
  64. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/universe.py +0 -0
  65. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/verify.py +0 -0
  66. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/watch.py +0 -0
  67. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit/worklist.py +0 -0
  68. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit.egg-info/SOURCES.txt +0 -0
  69. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit.egg-info/dependency_links.txt +0 -0
  70. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit.egg-info/entry_points.txt +0 -0
  71. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit.egg-info/requires.txt +0 -0
  72. {crapkit-0.4.7 → crapkit-0.4.9}/src/crapkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crapkit
3
- Version: 0.4.7
3
+ Version: 0.4.9
4
4
  Summary: Scores every function on complexity times uncovered risk, ranks the worst, and blocks commits that add more.
5
5
  Author: Jean-Francois Gagne
6
6
  License: MIT
@@ -44,6 +44,8 @@ Dynamic: license-file
44
44
  [![Python](https://img.shields.io/pypi/pyversions/crapkit)](https://pypi.org/project/crapkit/)
45
45
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
46
46
 
47
+ ![crapkit init, coverage and worklist --top 5 on a small Python repo, then a shell heredoc adding a function at ccn 7: the per-edit advisory reports it and exits 2, and the commit gate refuses the staged file with exit 6](https://raw.githubusercontent.com/JeanFrancoisGagne/crapkit/main/docs/demo.gif)
48
+
47
49
  crapkit scores every function in your repo on complexity times uncovered risk, ranks the
48
50
  worst ones by how often the file changes, and blocks commits that add more. It reads
49
51
  Python, TypeScript, TSX, JavaScript, Swift, Go, Rust, shell, PowerShell, C and C++,
@@ -145,7 +147,7 @@ changing crapkit.
145
147
 
146
148
  ```
147
149
  $ crapkit --version
148
- crapkit 0.4.7
150
+ crapkit 0.4.9
149
151
  ```
150
152
 
151
153
  `python -m crapkit` works identically to the console script and is what to use from a
@@ -373,7 +375,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
373
375
  repos:
374
376
  - repo: https://github.com/JeanFrancoisGagne/crapkit
375
377
  # crapkit's release step rewrites this line to the tag it just cut
376
- rev: v0.4.7
378
+ rev: v0.4.9
377
379
  hooks:
378
380
  - id: crapkit-gate
379
381
  ```
@@ -469,6 +471,151 @@ commit, and a row in the override log. All three land or nothing does, and an un
469
471
  `alert_command` refuses the override outright. See
470
472
  [docs/ratchet.md](docs/ratchet.md#overrides-and-the-audit-trail).
471
473
 
474
+ ## The GitHub Action
475
+
476
+ [action.yml](action.yml) at this repository's root is a composite action, so a reviewer
477
+ sees crapkit's numbers on the pull request without installing anything. Four lines add it
478
+ to a workflow, and every input has a default:
479
+
480
+ ```yaml
481
+ - uses: actions/checkout@v4
482
+ with:
483
+ fetch-depth: 0
484
+ - uses: JeanFrancoisGagne/crapkit@v0.4.8
485
+ ```
486
+
487
+ The whole job those four lines sit in:
488
+
489
+ ```yaml
490
+ on: pull_request
491
+ jobs:
492
+ crapkit:
493
+ runs-on: ubuntu-latest
494
+ permissions:
495
+ pull-requests: write # the comment, and nothing else
496
+ steps:
497
+ - uses: actions/checkout@v4
498
+ with:
499
+ fetch-depth: 0 # the diff, and verify's baseline commit
500
+ - run: pip install -e ".[dev]" # whatever your lanes need to run
501
+ - uses: JeanFrancoisGagne/crapkit@v0.4.8
502
+ with:
503
+ gate: "false"
504
+ ```
505
+
506
+ That `pip install` step is the one people leave out, and it is the same one Route 4 above
507
+ names: the action installs crapkit and nothing else, so your lanes still need whatever
508
+ your test command needs. Without it the lane writes no artifact and the comment says so.
509
+
510
+ `fetch-depth: 0` is the other one. `actions/checkout` clones a single commit; the action
511
+ reads the pull request's changed files out of git and `verify` reads the diff against the
512
+ baseline's commit. With a shallow clone the file list comes back empty and the comment
513
+ ranks the whole repository instead of the diff.
514
+
515
+ The action installs crapkit from `$GITHUB_ACTION_PATH`, which is its own checkout of the
516
+ ref you pinned in `uses:`. So `@v0.4.8` scores your tree with 0.4.8's crapkit rather than
517
+ with whatever released last, and pinning a tag is the whole version policy.
518
+
519
+ ### What the comment looks like
520
+
521
+ One comment per pull request, edited in place on every push. A hidden
522
+ `<!-- crapkit-action -->` line is how the next run finds it, so a fifteen-push branch
523
+ carries one comment and not fifteen. On a `push` event there is no pull request to carry
524
+ it, and the same text goes to the job log instead.
525
+
526
+ Rendered against this repository's own store, with a base commit fifteen back standing in
527
+ for a pull request:
528
+
529
+ ```markdown
530
+ <!-- crapkit-action -->
531
+
532
+ ## crapkit
533
+
534
+ 1333 functions in 61 files, 0 over target, CRAP load 3713.89, grade A+.
535
+
536
+ **verify passed.** Run 2 against baseline 1, 7 changed files.
537
+
538
+ ### Worklist: 39 changed files
539
+
540
+ | File | Function | ccn | risk | remedy |
541
+ |---|---|---:|---:|---|
542
+ | `src/crapkit/cli/admin.py:1026` | `_recorded_roots( recorded )` | 6 | 10.9908 | ok |
543
+ | `src/crapkit/lanes.py:646` | `build_retest_command( template : str , tests : set [ str ] )` | 6 | 10.8234 | ok |
544
+ | `src/crapkit/cli/admin.py:80` | `_next_step( scopes : dict , lanes : tuple )` | 5 | 9.159 | ok |
545
+ | `src/crapkit/cli/admin.py:239` | `_pytest_cov_probe( command : str )` | 5 | 9.159 | ok |
546
+ | `src/crapkit/cli/admin.py:505` | `_segment_problems( name : str , cwd : Path , tokens : list [ str ] )` | 5 | 9.159 | ok |
547
+ ```
548
+
549
+ The rows are the ranked worklist for the files the pull request changed, worst first,
550
+ `top` of them. `risk` is ccn times churn weight, the number `crapkit worklist` ranks on,
551
+ and `remedy` is the run's own verdict for that function: `decompose`, `add-tests` or `ok`.
552
+ A pull request that touches no ranked function gets the heading and no table.
553
+
554
+ The two file counts describe the same diff, counted twice. `39 changed files` is
555
+ `git diff --name-only base.sha...HEAD`, the branch's own commits, and it is what the
556
+ table is filtered to. The count on the verdict line is what `verify` measured from the
557
+ same fork point. With `delta: "false"` the second one is 0, because there is nothing
558
+ behind the checkout to measure from.
559
+
560
+ ### The inputs
561
+
562
+ | Input | Default | What it does |
563
+ |---|---|---|
564
+ | `gate` | `"false"` | `"true"` exits with `crapkit verify`'s own code, so a finding fails the check. Anything else exits 0 and the comment is the whole output |
565
+ | `delta` | `"true"` | scores the pull request's base commit first, so the verdict covers the commits the pull request adds. Costs a second lane run; `"false"` scores the checkout alone |
566
+ | `top` | `"5"` | worklist rows rendered in the table |
567
+ | `python-version` | `"3.12"` | the interpreter `actions/setup-python` installs crapkit into |
568
+
569
+ `gate: "false"` is the default on purpose. A team adopts the action before it has decided
570
+ which findings should stop a merge, and a check that fails on day one gets turned off on
571
+ day two.
572
+
573
+ ### What the verdict line covers
574
+
575
+ On a pull request, the commits the pull request adds. The action scores the fork point
576
+ first, then the checkout, then runs `crapkit verify --base <fork>`, which measures the
577
+ diff from there and takes the fork point's run as its baseline. So the gate judges the
578
+ functions in the diff a reviewer is reading, and a repository that was already over its
579
+ ceiling before the branch started does not fail every pull request that touches it.
580
+
581
+ The fork point is `git merge-base` of `base.sha` and HEAD, not `base.sha` itself.
582
+ `base.sha` is the base branch's tip when the event fired, so a base branch that moved
583
+ after the branch forked carries commits HEAD never saw, and a run there would be neither
584
+ the baseline verify wants nor a diff anyone is reviewing.
585
+
586
+ The base run happens in a detached worktree under `RUNNER_TEMP`, and its store is copied
587
+ over the checkout's so both runs sit in one place. The cost is **two lane runs on a pull
588
+ request**: your suite runs once at the fork point and once on the checkout. Set `delta:
589
+ "false"` to skip the base run, and the verdict falls back to the checkout against its own
590
+ run, which reports the tree's own health and judges no changed function.
591
+
592
+ Three things leave the base run unmade, and none of them fails the job: a shallow clone
593
+ that does not hold the fork point, a fork point older than your `crapkit.toml`, and a
594
+ lane that will not run against that tree. The step logs `crapkit base scoring exited N`
595
+ and the verdict falls back the same way `delta: "false"` does. A `push` event never makes
596
+ one, because there is no base commit and no pull request to comment on.
597
+
598
+ One requirement the base run adds: the lane has to measure the tree it runs in. A lane
599
+ that reaches an installed copy of your package instead of the checkout will measure the
600
+ pull request's code while standing on the base commit, and the two runs then describe the
601
+ same tree. `crapkit verify` refuses a run whose artifact names files outside the tree
602
+ (exit 5), which catches the loud version of this; a lane pinned to a path outside the
603
+ worktree is the quiet one. Point the lane at the tree, or set `delta: "false"`.
604
+
605
+ `--reuse-artifacts` is what keeps each of those runs to one pass of your suite. `coverage`
606
+ ran the lanes moments earlier on that tree, and verify parses those artifacts rather than
607
+ running the whole suite a second time for the same numbers.
608
+
609
+ The other gate that judges a delta is the portable baseline in [Route 4](#route-4-ci):
610
+ commit `crapkit-baseline.tsv` on the default branch and run `crapkit verify --baseline-tsv
611
+ crapkit-baseline.tsv` in a step of your own. It needs no second lane run, and it needs
612
+ someone to keep that file current.
613
+
614
+ The comment is posted with `gh api` and the job's own `GITHUB_TOKEN`, which needs
615
+ `pull-requests: write`. Two things it cannot do: a pull request from a fork gets a
616
+ read-only token, so the POST is a 403 there, and a self-hosted runner without the `gh` CLI
617
+ on PATH fails that step. Both leave the rendered text in the job log.
618
+
472
619
  ## Subcommands
473
620
 
474
621
  Every subcommand takes `--repo PATH` (default `.`), and the flag goes **after** the