CRAP score calculator for Go projects. Calculates the CRAP score (cyclomatic complexity × coverage) for every function in a Go module. Inspired by cargo-crap for Rust.
go install github.com/padiazg/go-crap@latestOr build from source:
git clone https://github.com/padiazg/go-crap.git
cd go-crap
go build -o go-crap .Or use Brew:
brew tap padiazg/go-crap
brew install go-crapgo-crap scan [path] [flags]Scans the Go module at the given path (defaults to .) and outputs a ranked table of functions by CRAP score.
# Scan current module
go-crap scan
# Scan a specific directory
go-crap scan ./internal/score
# Show only the 10 worst offenders
go-crap scan --top 10
# Fail CI if any function exceeds threshold
go-crap scan --fail-above --threshold 30
# Exclude test files and protobuf
go-crap scan --exclude '.*_test\.go' --exclude 'pb/.*\.go'| Flag | Short | Description | Default |
|---|---|---|---|
--threshold |
-t |
Score above which a function is marked as problematic | 30.0 |
--fail-above |
Exit with code 1 if any function exceeds the threshold | false |
|
--format |
-f |
Output format: table, json, github, sarif, or pr-comment |
table |
--top |
Show only the N worst offenders (0 = all) | 0 |
|
--min |
Hide entries below this score | 0 |
|
--missing |
Policy for functions without coverage: pessimistic, optimistic, or skip |
pessimistic |
|
--exclude |
Exclude files matching this regex (repeatable). Use .* for any path depth. e.g. .*_test\.go to exclude all test files, pb/.*\.go to exclude protobuf files |
none | |
--verbose |
Enable verbose (debug-level) logging | false |
|
--output |
-o |
Output file path (default: stdout) | stdout |
--mutation-report |
Path to gremlins JSON mutation report to validate coverage reliability | "" |
|
--detailed |
Include mutation failure details (original code, replacement, line) in report output | false |
|
--timeout |
Timeout for the full scan (e.g. 30s, 5m, 1h30m) |
10m0s |
|
--help |
-h |
Help for scan | — |
| Format | Description |
|---|---|
table |
Human-readable terminal output with status symbols and coverage bars |
json |
Structured output with $schema URL, suitable for CI pipelines |
github |
GitHub Actions workflow annotations (::warning) |
sarif |
SARIF 2.1.0 compliant JSON for static analysis tools |
pr-comment |
Markdown table formatted for pull request comments |
When a Go module fails to build or run tests, its coverage data is unavailable. go-crap detects this and reports it in all output formats:
table— coverage column showsN/A ‼with a footer listing unavailable modulesjson—coverageisnullandcoverage_warningcontains the error messagegithub—::warningannotation with the module errorsarif— result withRuleID: "go-crap/coverage-unavailable"pr-comment— separate "Coverage Unavailable" section
go-crap scan --format sarif > crap.sarifgo-crap scan --format pr-comment > pr-comment.mdgo-crap scan --mutation-report gremlins-report.jsonWhen a function has lived mutants (mutations that survived because tests didn't catch them), go-crap marks the coverage as unreliable (⚠) and recalculates the CRAP score assuming 0% coverage. This catches functions that appear well-tested but have blind spots.
go-crap scan --mutation-report gremlins-report.json --format json --detailedThe --detailed flag includes full mutation failure details in the output: type, line, original_code, and replacement_code for each survived mutant. In json format, these appear as a mutation_details array per entry. In sarif and pr-comment formats, survived mutations with code snippets are appended to the warning messages.
CRAP = Cyclomatic Readability And Predictability. It measures how expensive a function is to test.
A function with high cyclomatic complexity and low coverage scores the worst. A simple, fully tested function scores the best.
| CRAP Range | Meaning |
|---|---|
| 0 – 10 | Well-tested, simple function |
| 10 – 30 | Moderate complexity, should be tested |
| 30 – 50 | High CRAP — refactoring or more tests needed |
| 50+ | Critical — likely hard to test, complex logic |
go-crap scan
│
├── scan.Scan() — unified pipeline, discovers modules, filters, and ranks
│ ├── coverage.Scan() — discover Go modules, run go test -cover
│ ├── complexity.Analyze() — walk AST, compute cyclomatic complexity
│ ├── merge.Merge() — join by (filepath, funcname), propagate coverage warnings
│ ├── score.Score() — apply CRAP formula + missing policy
│ ├── mutation.Annotate() — validate coverage with mutation testing (optional)
│ └── report.Format() — table / json / github / sarif / pr-comment
│
└── pkg/utils/ — regex helpers for --exclude patterns
internal/scan— unified pipeline orchestrating the full scan flow (coverage → complexity → merge → score → filter → output)internal/complexity— AST walking to compute cyclomatic complexity (adapted from gocyclo, BSD-3-Clause)internal/coverage— module discovery +go test -coverprofiling (adapted from test-finder, MIT)internal/merge— double-index join of coverage and complexity data, propagates coverage-unavailable warnings from errored modulesinternal/score— CRAP formula + missing coverage policy +EntryListwrapperinternal/mutation— parses gremlins JSON mutation reports and annotates CRAP entries with coverage reliabilityinternal/report— output formatters (table, JSON, GitHub, SARIF, PR comment)pkg/logger— Logger interface and configuration typespkg/slogger— slog-backed Logger implementationpkg/utils— regex helper functions for exclude patterns
# .github/workflows/crap.yml
- run: go-crap scan --fail-above --threshold 30 --format github--fail-aboveexits with code 1 when any function exceeds the threshold--format githubemits::warningannotations that render as PR comments--format sarifoutputs SARIF 2.1.0 for integration with code scanning tools--format pr-commentgenerates a markdown table for pull request comments--output -owrites results to a file instead of stdout--mutation-reportvalidates coverage reliability against mutation testing results--detailedincludes mutation failure details (code, line, type) in report output- Coverage-unavailable warnings are emitted for modules where
go testfails
Add a status badge to your README.md to show the latest master analysis:
[](https://github.com/YOUR_ORG/YOUR_REPO/actions/workflows/crap.yml)Requires the workflow to trigger on push: branches: [master] (not branches-ignore).
- Savoia, A. & Evans, B. (2007). The CRAP Metric.
- Crap4j — the original Java implementation.
- cargo-crap — Inspiration for this project
This project is licensed under the MIT License.
For a complete guide covering all flags, examples, and the CRAP formula in detail, see the documentation site.