crapkit 0.7.4__tar.gz → 0.7.5__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.7.4/src/crapkit.egg-info → crapkit-0.7.5}/PKG-INFO +5 -5
- {crapkit-0.7.4 → crapkit-0.7.5}/README.md +4 -4
- {crapkit-0.7.4 → crapkit-0.7.5}/pyproject.toml +1 -1
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/__init__.py +1 -1
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/scoring.py +43 -2
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/score.py +63 -14
- {crapkit-0.7.4 → crapkit-0.7.5/src/crapkit.egg-info}/PKG-INFO +5 -5
- {crapkit-0.7.4 → crapkit-0.7.5}/LICENSE +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/setup.cfg +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/__main__.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/_analysis_pool.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/_mcp_stdio.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/_process_family.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/_process_owner.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/_pygdefer.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/_windows_job.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/analyze.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cache.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/churn.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/churn_cache.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/churn_log.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/__init__.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/_shared.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/admin.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/analyses.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/claude_hook.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/maintenance.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/parser.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/queue.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/ratchet_cmds.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/reports.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/cli/verifying.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/config.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/config_contract.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/coupling.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/coupling_cache.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/coverage_istanbul.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/coverage_py.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/covstream.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/diffparse.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/digest.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/doctor.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/dup.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/errors.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/gitio.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/gitpaths.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/hook.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/invocation.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/junitparse.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/keys.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/lanes.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/lizardcognitive.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/lizardpowershell.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/lizardpython.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/lizardrust.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/lizardshell.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/lizardtypescript.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/locks.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/logs.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/mcp_server.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/merge.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/mutate.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/mutate_pool.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/override.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/packet.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/procs.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/ratchet.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/ratchet_report.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/ratchetfile.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/records.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/report.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/repotext.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/resources.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/retention.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/rootfind.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/sarif.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/sarifio.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/scaffold.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/snapshot.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/store.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/uncovered.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/universe.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/verify.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/watch.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit/worklist.py +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit.egg-info/SOURCES.txt +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit.egg-info/dependency_links.txt +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit.egg-info/entry_points.txt +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/src/crapkit.egg-info/requires.txt +0 -0
- {crapkit-0.7.4 → crapkit-0.7.5}/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.7.
|
|
3
|
+
Version: 0.7.5
|
|
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
|
|
@@ -199,7 +199,7 @@ files. Review those commands before running Crapkit in a repository you do not t
|
|
|
199
199
|
|
|
200
200
|
```
|
|
201
201
|
$ crapkit --version
|
|
202
|
-
crapkit 0.7.
|
|
202
|
+
crapkit 0.7.5
|
|
203
203
|
```
|
|
204
204
|
|
|
205
205
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -455,7 +455,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
455
455
|
repos:
|
|
456
456
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
457
457
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
458
|
-
rev: v0.7.
|
|
458
|
+
rev: v0.7.5
|
|
459
459
|
hooks:
|
|
460
460
|
- id: crapkit-gate
|
|
461
461
|
```
|
|
@@ -563,7 +563,7 @@ to a workflow, and every input has a default:
|
|
|
563
563
|
- uses: actions/checkout@v4
|
|
564
564
|
with:
|
|
565
565
|
fetch-depth: 0
|
|
566
|
-
- uses: JeanFrancoisGagne/crapkit@v0.7.
|
|
566
|
+
- uses: JeanFrancoisGagne/crapkit@v0.7.5
|
|
567
567
|
```
|
|
568
568
|
|
|
569
569
|
The whole job those four lines sit in:
|
|
@@ -583,7 +583,7 @@ jobs:
|
|
|
583
583
|
with:
|
|
584
584
|
python-version: "3.12" # the interpreter the install below lands in
|
|
585
585
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
586
|
-
- uses: JeanFrancoisGagne/crapkit@v0.7.
|
|
586
|
+
- uses: JeanFrancoisGagne/crapkit@v0.7.5
|
|
587
587
|
with:
|
|
588
588
|
gate: "false"
|
|
589
589
|
```
|
|
@@ -158,7 +158,7 @@ files. Review those commands before running Crapkit in a repository you do not t
|
|
|
158
158
|
|
|
159
159
|
```
|
|
160
160
|
$ crapkit --version
|
|
161
|
-
crapkit 0.7.
|
|
161
|
+
crapkit 0.7.5
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -414,7 +414,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
414
414
|
repos:
|
|
415
415
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
416
416
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
417
|
-
rev: v0.7.
|
|
417
|
+
rev: v0.7.5
|
|
418
418
|
hooks:
|
|
419
419
|
- id: crapkit-gate
|
|
420
420
|
```
|
|
@@ -522,7 +522,7 @@ to a workflow, and every input has a default:
|
|
|
522
522
|
- uses: actions/checkout@v4
|
|
523
523
|
with:
|
|
524
524
|
fetch-depth: 0
|
|
525
|
-
- uses: JeanFrancoisGagne/crapkit@v0.7.
|
|
525
|
+
- uses: JeanFrancoisGagne/crapkit@v0.7.5
|
|
526
526
|
```
|
|
527
527
|
|
|
528
528
|
The whole job those four lines sit in:
|
|
@@ -542,7 +542,7 @@ jobs:
|
|
|
542
542
|
with:
|
|
543
543
|
python-version: "3.12" # the interpreter the install below lands in
|
|
544
544
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
545
|
-
- uses: JeanFrancoisGagne/crapkit@v0.7.
|
|
545
|
+
- uses: JeanFrancoisGagne/crapkit@v0.7.5
|
|
546
546
|
with:
|
|
547
547
|
gate: "false"
|
|
548
548
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "crapkit"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.5"
|
|
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.7.
|
|
2
|
+
__version__ = "0.7.5"
|
|
@@ -281,7 +281,7 @@ def _scored_run(root: Path, cfg, lanes, *, reuse_artifacts: bool, reuse_unchange
|
|
|
281
281
|
`git` is the caller's GitFacts when it already has one — verify asks for the
|
|
282
282
|
dirty set before this runs, and that answer is the one the lanes must see too.
|
|
283
283
|
"""
|
|
284
|
-
from ..score import score_rows
|
|
284
|
+
from ..score import SharedSpanFold, score_rows
|
|
285
285
|
|
|
286
286
|
git = git or GitFacts(root)
|
|
287
287
|
commit, rows, corpus, cache_hits, tool_versions = _build_inventory(root, cfg, git)
|
|
@@ -294,14 +294,55 @@ def _scored_run(root: Path, cfg, lanes, *, reuse_artifacts: bool, reuse_unchange
|
|
|
294
294
|
# Only scopes a SUCCESSFUL lane covers count as measured; a failed lane's
|
|
295
295
|
# scopes fall back to no-lane flags rather than reading as untested code.
|
|
296
296
|
lane_scopes = {s for lane in succeeded for s in lane.scopes}
|
|
297
|
+
shared_spans = SharedSpanFold()
|
|
297
298
|
scored = score_rows(rows, coverage_by_path, lane_scopes=lane_scopes, target=cfg.target,
|
|
298
299
|
scope_targets=cfg.scope_targets,
|
|
299
|
-
cc_only_scopes=cfg.coverage_optional_scopes
|
|
300
|
+
cc_only_scopes=cfg.coverage_optional_scopes,
|
|
301
|
+
shared_spans=shared_spans)
|
|
302
|
+
_note_shared_spans(shared_spans, cfg)
|
|
300
303
|
test_failures = {f for prov in provenance.values() for f in prov.get("failures", ())}
|
|
301
304
|
return _ScoredRun(commit, scored, provenance, lane_errors, test_failures, tool_versions,
|
|
302
305
|
corpus, cache_hits, dead_lines)
|
|
303
306
|
|
|
304
307
|
|
|
308
|
+
_SPANS_NAMED = 3
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _over_target_at_zero(members, cfg):
|
|
312
|
+
"""The worst function on each shared span that its ceiling can fail.
|
|
313
|
+
|
|
314
|
+
Every function on a shared span scores as uncovered, and a function of
|
|
315
|
+
complexity 2 scores 6 at zero coverage, so no ceiling of 6 can fail it.
|
|
316
|
+
The count carries those; the named lines are the ones worth splitting.
|
|
317
|
+
"""
|
|
318
|
+
from ..score import crap
|
|
319
|
+
|
|
320
|
+
for span in members:
|
|
321
|
+
worst = max(span, key=lambda row: row.ccn)
|
|
322
|
+
if crap(worst.ccn, 0.0) > cfg.ceiling_of(worst.scope):
|
|
323
|
+
yield worst
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _note_shared_spans(fold, cfg) -> None:
|
|
327
|
+
"""Name the source line spans more than one function declares.
|
|
328
|
+
|
|
329
|
+
Loud but not fatal, the shape `_note_unanalyzable` settled for unreadable
|
|
330
|
+
files: the join cannot tell whose coverage is whose on such a span, and
|
|
331
|
+
ending the run over it left the consumer repo with no coverage run at all.
|
|
332
|
+
"""
|
|
333
|
+
if not fold.sites:
|
|
334
|
+
return
|
|
335
|
+
over = sorted(_over_target_at_zero(fold.sites, cfg), key=lambda row: (-row.ccn, row.path))
|
|
336
|
+
tail = f"; {len(over)} of them hold a function over its target:" if over else ""
|
|
337
|
+
print(f"crapkit: {len(fold.sites)} source line span(s) hold more than one function; "
|
|
338
|
+
"coverage cannot say whose is whose, so those functions score as uncovered, and "
|
|
339
|
+
f"splitting the definitions onto separate lines measures them{tail}", file=sys.stderr)
|
|
340
|
+
for row in over[:_SPANS_NAMED]:
|
|
341
|
+
print(f"crapkit: {row.path}:{row.start} (complexity {row.ccn})", file=sys.stderr)
|
|
342
|
+
if len(over) > _SPANS_NAMED:
|
|
343
|
+
print(f"crapkit: ... and {len(over) - _SPANS_NAMED} more", file=sys.stderr)
|
|
344
|
+
|
|
345
|
+
|
|
305
346
|
def _run_kind(lanes, cfg, failures) -> str:
|
|
306
347
|
"""A --lane subset or a run with failed lanes must never serve as the
|
|
307
348
|
verify baseline: its lane set differs from what verify runs, so every
|
|
@@ -285,27 +285,71 @@ def overlay_stale_coverage(
|
|
|
285
285
|
return scored
|
|
286
286
|
|
|
287
287
|
|
|
288
|
+
class SharedSpanFold:
|
|
289
|
+
"""The source line spans more than one function declares in one run.
|
|
290
|
+
|
|
291
|
+
The join cannot tell whose coverage is whose there, so each such function
|
|
292
|
+
scores as uncovered and the run names the spans instead of ending. Filled
|
|
293
|
+
while scoring; the caller reports it once.
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
def __init__(self) -> None:
|
|
297
|
+
self.sites: list[list[InventoryRow]] = []
|
|
298
|
+
|
|
299
|
+
def add(self, members: list[InventoryRow]) -> None:
|
|
300
|
+
self.sites.append(members)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _identity(row) -> tuple:
|
|
304
|
+
"""What separates two functions on one span: the name, and the occurrence
|
|
305
|
+
that tells sibling callbacks on a line apart."""
|
|
306
|
+
return row.long_name, row.occurrence
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _join_member(members: list, row) -> None:
|
|
310
|
+
"""A third function on the span joins its members; another copy of one that
|
|
311
|
+
is already there (the same function in a second scope) does not."""
|
|
312
|
+
if all(_identity(member) != _identity(row) for member in members):
|
|
313
|
+
members.append(row)
|
|
314
|
+
|
|
315
|
+
|
|
288
316
|
def _shared_source_spans(rows, lane_scopes: set, cc_only_scopes) -> dict:
|
|
289
|
-
|
|
317
|
+
"""span -> the distinct functions declaring it, for spans more than one does."""
|
|
318
|
+
first, collisions = {}, {}
|
|
290
319
|
for row in rows:
|
|
291
320
|
if _cov_without_join(row, lane_scopes, cc_only_scopes) is not None:
|
|
292
321
|
continue
|
|
293
322
|
span = row.path, row.start, row.end
|
|
294
|
-
|
|
295
|
-
if seen
|
|
296
|
-
collisions[
|
|
323
|
+
seen = first.setdefault(span, row)
|
|
324
|
+
if _identity(seen) != _identity(row):
|
|
325
|
+
_join_member(collisions.setdefault(span, [seen]), row)
|
|
297
326
|
return collisions
|
|
298
327
|
|
|
299
328
|
|
|
300
|
-
def
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
329
|
+
def _ambiguous_spans(rows, coverage_by_path: dict, start_index: dict,
|
|
330
|
+
lane_scopes: set, cc_only_scopes) -> dict:
|
|
331
|
+
"""The shared spans a measurement would speak about, so the join would hand
|
|
332
|
+
every function on the span one function's number.
|
|
333
|
+
|
|
334
|
+
Through 0.7.4 this raised and ended the run. One consumer repo holds 591
|
|
335
|
+
shared spans, 459 of them measured, so a run died on the first one it met
|
|
336
|
+
and the repo never finished a coverage run at all. Refusing the ambiguous
|
|
337
|
+
number is the specified behaviour; ending the run over it was not, the
|
|
338
|
+
shape _note_unanalyzable settled for unreadable files.
|
|
339
|
+
"""
|
|
340
|
+
ambiguous = {}
|
|
341
|
+
for span, members in _shared_source_spans(rows, lane_scopes, cc_only_scopes).items():
|
|
342
|
+
if _span_join_cov(members[0], coverage_by_path, start_index)[1] == "measured":
|
|
343
|
+
ambiguous[span] = members
|
|
344
|
+
return ambiguous
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _ambiguous_cov(row, ambiguous: dict) -> tuple[float, str] | None:
|
|
348
|
+
"""Uncovered, never the neighbour's number: the honest floor for a function
|
|
349
|
+
whose measurement cannot be told from another's."""
|
|
350
|
+
if (row.path, row.start, row.end) in ambiguous:
|
|
351
|
+
return 0.0, "untested"
|
|
352
|
+
return None
|
|
309
353
|
|
|
310
354
|
|
|
311
355
|
def score_rows(
|
|
@@ -316,12 +360,17 @@ def score_rows(
|
|
|
316
360
|
target: int = 6,
|
|
317
361
|
scope_targets: dict[str, int] | None = None,
|
|
318
362
|
cc_only_scopes: frozenset[str] = frozenset(),
|
|
363
|
+
shared_spans: SharedSpanFold | None = None,
|
|
319
364
|
) -> list[ScoredRow]:
|
|
320
365
|
start_index = _start_index(coverage_by_path)
|
|
321
|
-
|
|
366
|
+
ambiguous = _ambiguous_spans(rows, coverage_by_path, start_index, lane_scopes, cc_only_scopes)
|
|
367
|
+
for members in ambiguous.values():
|
|
368
|
+
if shared_spans is not None:
|
|
369
|
+
shared_spans.add(members)
|
|
322
370
|
scored = []
|
|
323
371
|
for r in rows:
|
|
324
372
|
cov, flag = (_cov_without_join(r, lane_scopes, cc_only_scopes)
|
|
373
|
+
or _ambiguous_cov(r, ambiguous)
|
|
325
374
|
or _span_join_cov(r, coverage_by_path, start_index))
|
|
326
375
|
scored.append(_finish(r, cov, flag, target=target, scope_targets=scope_targets))
|
|
327
376
|
return scored
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crapkit
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5
|
|
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
|
|
@@ -199,7 +199,7 @@ files. Review those commands before running Crapkit in a repository you do not t
|
|
|
199
199
|
|
|
200
200
|
```
|
|
201
201
|
$ crapkit --version
|
|
202
|
-
crapkit 0.7.
|
|
202
|
+
crapkit 0.7.5
|
|
203
203
|
```
|
|
204
204
|
|
|
205
205
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -455,7 +455,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
455
455
|
repos:
|
|
456
456
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
457
457
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
458
|
-
rev: v0.7.
|
|
458
|
+
rev: v0.7.5
|
|
459
459
|
hooks:
|
|
460
460
|
- id: crapkit-gate
|
|
461
461
|
```
|
|
@@ -563,7 +563,7 @@ to a workflow, and every input has a default:
|
|
|
563
563
|
- uses: actions/checkout@v4
|
|
564
564
|
with:
|
|
565
565
|
fetch-depth: 0
|
|
566
|
-
- uses: JeanFrancoisGagne/crapkit@v0.7.
|
|
566
|
+
- uses: JeanFrancoisGagne/crapkit@v0.7.5
|
|
567
567
|
```
|
|
568
568
|
|
|
569
569
|
The whole job those four lines sit in:
|
|
@@ -583,7 +583,7 @@ jobs:
|
|
|
583
583
|
with:
|
|
584
584
|
python-version: "3.12" # the interpreter the install below lands in
|
|
585
585
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
586
|
-
- uses: JeanFrancoisGagne/crapkit@v0.7.
|
|
586
|
+
- uses: JeanFrancoisGagne/crapkit@v0.7.5
|
|
587
587
|
with:
|
|
588
588
|
gate: "false"
|
|
589
589
|
```
|
|
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
|
|
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
|