crapkit 0.5.0__tar.gz → 0.5.1__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.
- {crapkit-0.5.0/src/crapkit.egg-info → crapkit-0.5.1}/PKG-INFO +20 -5
- {crapkit-0.5.0 → crapkit-0.5.1}/README.md +19 -4
- {crapkit-0.5.0 → crapkit-0.5.1}/pyproject.toml +1 -1
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/__init__.py +1 -1
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/verifying.py +28 -4
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/verify.py +17 -0
- {crapkit-0.5.0 → crapkit-0.5.1/src/crapkit.egg-info}/PKG-INFO +20 -5
- {crapkit-0.5.0 → crapkit-0.5.1}/LICENSE +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/setup.cfg +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/__main__.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/_pygdefer.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/analyze.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cache.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/churn.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/churn_cache.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/churn_log.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/__init__.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/_shared.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/admin.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/analyses.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/claude_hook.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/parser.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/queue.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/ratchet_cmds.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/reports.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/cli/scoring.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/config.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/coupling.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/coupling_cache.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/coverage_istanbul.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/coverage_py.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/covstream.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/diffparse.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/digest.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/discover.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/doctor.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/dup.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/errors.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/gitio.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/hook.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/invocation.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/junitparse.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/keys.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/lanes.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/lizardcognitive.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/lizardpowershell.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/lizardrust.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/lizardshell.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/mcp_server.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/merge.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/mutate.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/mutate_pool.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/override.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/packet.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/procs.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/ratchet.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/ratchet_report.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/report.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/repotext.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/rootfind.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/sarif.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/sarifio.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/scaffold.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/score.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/snapshot.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/store.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/uncovered.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/universe.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/watch.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit/worklist.py +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit.egg-info/SOURCES.txt +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit.egg-info/dependency_links.txt +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit.egg-info/entry_points.txt +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/src/crapkit.egg-info/requires.txt +0 -0
- {crapkit-0.5.0 → crapkit-0.5.1}/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.5.
|
|
3
|
+
Version: 0.5.1
|
|
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
|
|
@@ -73,6 +73,16 @@ half-executed straight-line function never reads as fully covered.
|
|
|
73
73
|
function at ccn 7 with 100% coverage still scores 7 and still fails the gate. The only
|
|
74
74
|
move that clears it is splitting the function.
|
|
75
75
|
|
|
76
|
+
**Why 6 and not 30.** crap4j's conventional threshold of 30 is a CRAP score: it lets an
|
|
77
|
+
untested `ccn 5` through (25 + 5 = 30) and a fully covered `ccn 30` too. crapkit's default
|
|
78
|
+
is a complexity ceiling, because coverage can at best collapse CRAP to `ccn`, and a
|
|
79
|
+
function you cannot cover past `ccn 6` is one you decompose. Set `target = 30` in
|
|
80
|
+
`crapkit.toml` if you want the crap4j number. A repo with existing debt does not need to:
|
|
81
|
+
`ratchet seed` marks today's over-ceiling functions at today's score, the gate then judges
|
|
82
|
+
only the functions a change touches, and marks may only fall, so adoption never starts with
|
|
83
|
+
a wall of red. Next to crap4py, radon, xenon, wily and SonarQube:
|
|
84
|
+
[docs/comparison.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/comparison.md).
|
|
85
|
+
|
|
76
86
|
crapkit scores **git-tracked files only**. Source you have not `git add`ed is invisible to
|
|
77
87
|
it.
|
|
78
88
|
|
|
@@ -171,7 +181,7 @@ leaves the box
|
|
|
171
181
|
|
|
172
182
|
```
|
|
173
183
|
$ crapkit --version
|
|
174
|
-
crapkit 0.5.
|
|
184
|
+
crapkit 0.5.1
|
|
175
185
|
```
|
|
176
186
|
|
|
177
187
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -415,7 +425,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
415
425
|
repos:
|
|
416
426
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
417
427
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
418
|
-
rev: v0.5.
|
|
428
|
+
rev: v0.5.1
|
|
419
429
|
hooks:
|
|
420
430
|
- id: crapkit-gate
|
|
421
431
|
```
|
|
@@ -523,7 +533,7 @@ to a workflow, and every input has a default:
|
|
|
523
533
|
- uses: actions/checkout@v4
|
|
524
534
|
with:
|
|
525
535
|
fetch-depth: 0
|
|
526
|
-
- uses: JeanFrancoisGagne/crapkit@v0.5.
|
|
536
|
+
- uses: JeanFrancoisGagne/crapkit@v0.5.1
|
|
527
537
|
```
|
|
528
538
|
|
|
529
539
|
The whole job those four lines sit in:
|
|
@@ -543,7 +553,7 @@ jobs:
|
|
|
543
553
|
with:
|
|
544
554
|
python-version: "3.12" # the interpreter the install below lands in
|
|
545
555
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
546
|
-
- uses: JeanFrancoisGagne/crapkit@v0.5.
|
|
556
|
+
- uses: JeanFrancoisGagne/crapkit@v0.5.1
|
|
547
557
|
with:
|
|
548
558
|
gate: "false"
|
|
549
559
|
```
|
|
@@ -1285,6 +1295,11 @@ dropped it once `classify` scored under the ceiling, rewriting the tracked
|
|
|
1285
1295
|
A verify may also print `warning: N changed line(s) have no coverage` above its verdict;
|
|
1286
1296
|
that block is advisory unless `diff_uncovered_max` is set
|
|
1287
1297
|
([docs/configuration.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/configuration.md)).
|
|
1298
|
+
It prints `warning: N function(s) over the ceiling carry no ratchet mark` when the tree
|
|
1299
|
+
holds debt `ratchet seed` never signed: the gate judges touched functions only and the
|
|
1300
|
+
ratchet check compares marks only, so coverage loss on such a function would pass unseen.
|
|
1301
|
+
The count is `unmarked_over_target` in `--json`, fires no exit code, and is zero on a repo
|
|
1302
|
+
with no debt.
|
|
1288
1303
|
|
|
1289
1304
|
## Documentation
|
|
1290
1305
|
|
|
@@ -34,6 +34,16 @@ half-executed straight-line function never reads as fully covered.
|
|
|
34
34
|
function at ccn 7 with 100% coverage still scores 7 and still fails the gate. The only
|
|
35
35
|
move that clears it is splitting the function.
|
|
36
36
|
|
|
37
|
+
**Why 6 and not 30.** crap4j's conventional threshold of 30 is a CRAP score: it lets an
|
|
38
|
+
untested `ccn 5` through (25 + 5 = 30) and a fully covered `ccn 30` too. crapkit's default
|
|
39
|
+
is a complexity ceiling, because coverage can at best collapse CRAP to `ccn`, and a
|
|
40
|
+
function you cannot cover past `ccn 6` is one you decompose. Set `target = 30` in
|
|
41
|
+
`crapkit.toml` if you want the crap4j number. A repo with existing debt does not need to:
|
|
42
|
+
`ratchet seed` marks today's over-ceiling functions at today's score, the gate then judges
|
|
43
|
+
only the functions a change touches, and marks may only fall, so adoption never starts with
|
|
44
|
+
a wall of red. Next to crap4py, radon, xenon, wily and SonarQube:
|
|
45
|
+
[docs/comparison.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/comparison.md).
|
|
46
|
+
|
|
37
47
|
crapkit scores **git-tracked files only**. Source you have not `git add`ed is invisible to
|
|
38
48
|
it.
|
|
39
49
|
|
|
@@ -132,7 +142,7 @@ leaves the box
|
|
|
132
142
|
|
|
133
143
|
```
|
|
134
144
|
$ crapkit --version
|
|
135
|
-
crapkit 0.5.
|
|
145
|
+
crapkit 0.5.1
|
|
136
146
|
```
|
|
137
147
|
|
|
138
148
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -376,7 +386,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
376
386
|
repos:
|
|
377
387
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
378
388
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
379
|
-
rev: v0.5.
|
|
389
|
+
rev: v0.5.1
|
|
380
390
|
hooks:
|
|
381
391
|
- id: crapkit-gate
|
|
382
392
|
```
|
|
@@ -484,7 +494,7 @@ to a workflow, and every input has a default:
|
|
|
484
494
|
- uses: actions/checkout@v4
|
|
485
495
|
with:
|
|
486
496
|
fetch-depth: 0
|
|
487
|
-
- uses: JeanFrancoisGagne/crapkit@v0.5.
|
|
497
|
+
- uses: JeanFrancoisGagne/crapkit@v0.5.1
|
|
488
498
|
```
|
|
489
499
|
|
|
490
500
|
The whole job those four lines sit in:
|
|
@@ -504,7 +514,7 @@ jobs:
|
|
|
504
514
|
with:
|
|
505
515
|
python-version: "3.12" # the interpreter the install below lands in
|
|
506
516
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
507
|
-
- uses: JeanFrancoisGagne/crapkit@v0.5.
|
|
517
|
+
- uses: JeanFrancoisGagne/crapkit@v0.5.1
|
|
508
518
|
with:
|
|
509
519
|
gate: "false"
|
|
510
520
|
```
|
|
@@ -1246,6 +1256,11 @@ dropped it once `classify` scored under the ceiling, rewriting the tracked
|
|
|
1246
1256
|
A verify may also print `warning: N changed line(s) have no coverage` above its verdict;
|
|
1247
1257
|
that block is advisory unless `diff_uncovered_max` is set
|
|
1248
1258
|
([docs/configuration.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/configuration.md)).
|
|
1259
|
+
It prints `warning: N function(s) over the ceiling carry no ratchet mark` when the tree
|
|
1260
|
+
holds debt `ratchet seed` never signed: the gate judges touched functions only and the
|
|
1261
|
+
ratchet check compares marks only, so coverage loss on such a function would pass unseen.
|
|
1262
|
+
The count is `unmarked_over_target` in `--json`, fires no exit code, and is zero on a repo
|
|
1263
|
+
with no debt.
|
|
1249
1264
|
|
|
1250
1265
|
## Documentation
|
|
1251
1266
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "crapkit"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.1"
|
|
8
8
|
description = "Scores every function on complexity times uncovered risk, ranks the worst, and blocks commits that add more."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""crapkit: deterministic CRAP-score framework."""
|
|
2
|
-
__version__ = "0.5.
|
|
2
|
+
__version__ = "0.5.1"
|
|
@@ -483,9 +483,13 @@ def _verify_attribution(verdict) -> dict:
|
|
|
483
483
|
|
|
484
484
|
|
|
485
485
|
def _verify_result(verdict, overridden, run_id: int, baseline: dict, commit: str, ranges,
|
|
486
|
-
uncovered: list, diff_uncovered_max: int | None
|
|
486
|
+
uncovered: list, diff_uncovered_max: int | None,
|
|
487
|
+
unmarked_over_target: int) -> dict:
|
|
487
488
|
"""`diff_uncovered_max` travels with the count it judges: a reader of exit 9
|
|
488
|
-
(the Action's comment) can say which ceiling the lines went over.
|
|
489
|
+
(the Action's comment) can say which ceiling the lines went over.
|
|
490
|
+
`unmarked_over_target` is the standing debt no mark covers (see
|
|
491
|
+
`_warn_standing_debt`); it fires no exit code and is the one number that
|
|
492
|
+
says how much of the tree the ratchet is not holding."""
|
|
489
493
|
return {
|
|
490
494
|
"ok": verdict.ok,
|
|
491
495
|
"run_id": run_id,
|
|
@@ -500,10 +504,28 @@ def _verify_result(verdict, overridden, run_id: int, baseline: dict, commit: str
|
|
|
500
504
|
"diff_uncovered_count": len(uncovered),
|
|
501
505
|
"diff_uncovered": [{"path": p, "line": ln} for p, ln in uncovered[:50]],
|
|
502
506
|
"diff_uncovered_max": diff_uncovered_max,
|
|
507
|
+
"unmarked_over_target": unmarked_over_target,
|
|
503
508
|
**_verify_attribution(verdict),
|
|
504
509
|
}
|
|
505
510
|
|
|
506
511
|
|
|
512
|
+
def _warn_standing_debt(unmarked: list) -> None:
|
|
513
|
+
"""One stderr line for the over-ceiling functions no mark covers.
|
|
514
|
+
|
|
515
|
+
The gate never looks at an untouched function and the ratchet check compares
|
|
516
|
+
marks only, so a rise on these (coverage loss included) reaches no finding;
|
|
517
|
+
docs/ratchet.md says "seed once, early" for exactly this, and a header-only
|
|
518
|
+
marks file cannot say whether seed ever ran. stderr, because
|
|
519
|
+
`--json` prints one object on stdout. Silent at zero, which is the state
|
|
520
|
+
of a repo with no debt and of one seeded in full.
|
|
521
|
+
"""
|
|
522
|
+
if not unmarked:
|
|
523
|
+
return
|
|
524
|
+
print(f"warning: {len(unmarked)} function(s) over the ceiling carry no ratchet mark, so a "
|
|
525
|
+
f"rise on them (coverage loss included) passes unseen; record them with "
|
|
526
|
+
f"`{_self()} ratchet seed`", file=sys.stderr)
|
|
527
|
+
|
|
528
|
+
|
|
507
529
|
def _warn_diff_uncovered(uncovered: list) -> None:
|
|
508
530
|
if not uncovered:
|
|
509
531
|
return
|
|
@@ -576,7 +598,7 @@ def cmd_verify(args: argparse.Namespace) -> int:
|
|
|
576
598
|
from ..diffparse import changed_ranges
|
|
577
599
|
from ..gitio import GitFacts, diff_since
|
|
578
600
|
from ..uncovered import missing_by_path
|
|
579
|
-
from ..verify import diff_uncovered, evaluate
|
|
601
|
+
from ..verify import diff_uncovered, evaluate, unmarked_over_ceiling
|
|
580
602
|
|
|
581
603
|
root = _command_root(args.repo)
|
|
582
604
|
cfg = _load_repo_config(root)
|
|
@@ -616,6 +638,8 @@ def cmd_verify(args: argparse.Namespace) -> int:
|
|
|
616
638
|
# the whole cost of the post-commit verify on an unchanged tree.
|
|
617
639
|
uncovered = diff_uncovered(ranges, missing_by_path(root, cfg)) if ranges else []
|
|
618
640
|
_warn_diff_uncovered(uncovered)
|
|
641
|
+
unmarked = unmarked_over_ceiling(scored, ratchet, cfg.target, cfg.scope_targets)
|
|
642
|
+
_warn_standing_debt(unmarked)
|
|
619
643
|
breach = _diff_cover_breach(cfg, uncovered)
|
|
620
644
|
if breach:
|
|
621
645
|
verdict = verdict._replace(ok=False) # a breached run never advances the baseline
|
|
@@ -629,7 +653,7 @@ def cmd_verify(args: argparse.Namespace) -> int:
|
|
|
629
653
|
|
|
630
654
|
_report_verify(args.json,
|
|
631
655
|
{**_verify_result(verdict, overridden, run_id, baseline, commit, ranges,
|
|
632
|
-
uncovered, cfg.diff_uncovered_max),
|
|
656
|
+
uncovered, cfg.diff_uncovered_max, len(unmarked)),
|
|
633
657
|
**_receipt(tool_versions, ratchet_sha256, changes)},
|
|
634
658
|
verdict, overridden, cfg.ratchet_file)
|
|
635
659
|
_refuse_override(verdict, args.override)
|
|
@@ -206,6 +206,23 @@ def _ratchet_regressions(fresh, ratchet, dirty) -> list[RatchetRegression]:
|
|
|
206
206
|
return regressions
|
|
207
207
|
|
|
208
208
|
|
|
209
|
+
def unmarked_over_ceiling(fresh: list[ScoredRow], ratchet: list[RatchetEntry], target: int,
|
|
210
|
+
scope_targets: dict[str, int] | None = None) -> list[ScoredRow]:
|
|
211
|
+
"""Standing debt nothing guards: the worst row per ratchet key that sits over
|
|
212
|
+
its ceiling with no mark under that key, worst first.
|
|
213
|
+
|
|
214
|
+
The gate judges touched functions only and the ratchet check compares marks
|
|
215
|
+
only, so a rise on one of these (coverage loss included) reaches no finding.
|
|
216
|
+
A marked function that rose is a regression already; this is the debt
|
|
217
|
+
`ratchet seed` was never run on.
|
|
218
|
+
"""
|
|
219
|
+
marks = _marks_of(ratchet)
|
|
220
|
+
rows = [row for key, row in rows_by_key(fresh).items()
|
|
221
|
+
if row.crap > _ceiling(row, target, scope_targets) and key not in marks]
|
|
222
|
+
rows.sort(key=lambda r: (-r.crap, r.path, r.start))
|
|
223
|
+
return rows
|
|
224
|
+
|
|
225
|
+
|
|
209
226
|
def evaluate(
|
|
210
227
|
*,
|
|
211
228
|
fresh: list[ScoredRow],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crapkit
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
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
|
|
@@ -73,6 +73,16 @@ half-executed straight-line function never reads as fully covered.
|
|
|
73
73
|
function at ccn 7 with 100% coverage still scores 7 and still fails the gate. The only
|
|
74
74
|
move that clears it is splitting the function.
|
|
75
75
|
|
|
76
|
+
**Why 6 and not 30.** crap4j's conventional threshold of 30 is a CRAP score: it lets an
|
|
77
|
+
untested `ccn 5` through (25 + 5 = 30) and a fully covered `ccn 30` too. crapkit's default
|
|
78
|
+
is a complexity ceiling, because coverage can at best collapse CRAP to `ccn`, and a
|
|
79
|
+
function you cannot cover past `ccn 6` is one you decompose. Set `target = 30` in
|
|
80
|
+
`crapkit.toml` if you want the crap4j number. A repo with existing debt does not need to:
|
|
81
|
+
`ratchet seed` marks today's over-ceiling functions at today's score, the gate then judges
|
|
82
|
+
only the functions a change touches, and marks may only fall, so adoption never starts with
|
|
83
|
+
a wall of red. Next to crap4py, radon, xenon, wily and SonarQube:
|
|
84
|
+
[docs/comparison.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/comparison.md).
|
|
85
|
+
|
|
76
86
|
crapkit scores **git-tracked files only**. Source you have not `git add`ed is invisible to
|
|
77
87
|
it.
|
|
78
88
|
|
|
@@ -171,7 +181,7 @@ leaves the box
|
|
|
171
181
|
|
|
172
182
|
```
|
|
173
183
|
$ crapkit --version
|
|
174
|
-
crapkit 0.5.
|
|
184
|
+
crapkit 0.5.1
|
|
175
185
|
```
|
|
176
186
|
|
|
177
187
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -415,7 +425,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
415
425
|
repos:
|
|
416
426
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
417
427
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
418
|
-
rev: v0.5.
|
|
428
|
+
rev: v0.5.1
|
|
419
429
|
hooks:
|
|
420
430
|
- id: crapkit-gate
|
|
421
431
|
```
|
|
@@ -523,7 +533,7 @@ to a workflow, and every input has a default:
|
|
|
523
533
|
- uses: actions/checkout@v4
|
|
524
534
|
with:
|
|
525
535
|
fetch-depth: 0
|
|
526
|
-
- uses: JeanFrancoisGagne/crapkit@v0.5.
|
|
536
|
+
- uses: JeanFrancoisGagne/crapkit@v0.5.1
|
|
527
537
|
```
|
|
528
538
|
|
|
529
539
|
The whole job those four lines sit in:
|
|
@@ -543,7 +553,7 @@ jobs:
|
|
|
543
553
|
with:
|
|
544
554
|
python-version: "3.12" # the interpreter the install below lands in
|
|
545
555
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
546
|
-
- uses: JeanFrancoisGagne/crapkit@v0.5.
|
|
556
|
+
- uses: JeanFrancoisGagne/crapkit@v0.5.1
|
|
547
557
|
with:
|
|
548
558
|
gate: "false"
|
|
549
559
|
```
|
|
@@ -1285,6 +1295,11 @@ dropped it once `classify` scored under the ceiling, rewriting the tracked
|
|
|
1285
1295
|
A verify may also print `warning: N changed line(s) have no coverage` above its verdict;
|
|
1286
1296
|
that block is advisory unless `diff_uncovered_max` is set
|
|
1287
1297
|
([docs/configuration.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/configuration.md)).
|
|
1298
|
+
It prints `warning: N function(s) over the ceiling carry no ratchet mark` when the tree
|
|
1299
|
+
holds debt `ratchet seed` never signed: the gate judges touched functions only and the
|
|
1300
|
+
ratchet check compares marks only, so coverage loss on such a function would pass unseen.
|
|
1301
|
+
The count is `unmarked_over_target` in `--json`, fires no exit code, and is zero on a repo
|
|
1302
|
+
with no debt.
|
|
1288
1303
|
|
|
1289
1304
|
## Documentation
|
|
1290
1305
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|