Quality reports
Recipes for producing aggregated, human-readable Markdown reports.
Wiring reports into CI? See the CI integration recipe for runnable GitHub Actions and GitLab CI examples that post the Markdown report as a PR/MR comment and surface threshold violations through the platform's native code quality widgets.
Live example reports
big-code-analysis publishes the output of bca report -O markdown --vcs and bca report -O html --vcs against its own source tree on
every push to
main. Open either to see exactly what the recipes on this page produce
on a multi-language Rust + Python codebase:
- HTML hotspot report (sortable tables, per-language sections, plus a
"Change-history risk" section from
--vcs): https://dekobon.github.io/big-code-analysis/reports/index.html - Markdown PR/MR comment (paste-into-issue ready): https://dekobon.github.io/big-code-analysis/reports/report.md
- Change-history risk, full top-100 ranking as machine-readable JSON
(see
bca vcs): https://dekobon.github.io/big-code-analysis/reports/vcs-report.json
The wiring that produces them lives in
.github/workflows/pages.yml.
The same workflow runs the threshold gate; see
CI integration for the full pipeline
shape.
Generate a project-wide quality report
Run from the project root and write the report to a file:
bca report \
--paths "$PWD" \
-O markdown \
--top 20 \
--strip-prefix "$PWD/" \
--output report.md
--strip-prefixkeeps the file paths short and stable across machines — without it every row carries the absolute path of the current checkout.--topcontrols how many rows appear in each hotspot table. 20 is a good default for a PR comment; drop to 5 for a dashboard tile, or pass0to list every row.--jobsdefaults to the effective CPU count (cgroup-/cpuset-aware on Linux); pass--jobs 1only to force serial mode for debugging.
Limit the report to specific languages
bca infers language from extension, so the
include/exclude globs do the filtering:
bca report \
--include "*.rs" --include "*.py" \
--paths "$PWD" \
-O markdown --output report.md
To exclude vendored or generated trees, layer in --exclude:
bca report \
--include "*.rs" \
--exclude "**/target/**" --exclude "**/vendor/**" \
--paths "$PWD" \
-O markdown
Flag arity.
--includeand--excludetake exactly one glob per occurrence; repeat the flag for additional patterns. The=form works the same way:--include="*.rs" --exclude="**/target/**".Leading
./is optional. A bare-relative pattern and its./-prefixed spelling are equivalent:--exclude "vendor/**"matches exactly what--exclude "./vendor/**"does. This holds for every glob surface —--include,--exclude,--exclude-from,.bcaignore, and the[check.exclude]gate-exemption set.
For a stable repo-wide deny-set, keep the patterns in a file at the
repo root (a .bcaignore by convention) and load it with
--exclude-from. Patterns are unioned with any inline --exclude
values; blank lines and #-prefixed comments are skipped:
bca report \
--paths . \
--exclude-from .bcaignore \
-O markdown --output report.md
Show only the worst offenders
For a quick triage view that highlights the top three problems per section:
bca report -p src/ -O markdown --top 3
The report still includes every section, but each table is short enough to scan at a glance.
Compare two revisions
Aggregate reports do not diff revisions on their own. Run the report on each side and diff the Markdown:
git worktree add /tmp/before main
bca report -p /tmp/before -O markdown \
--strip-prefix /tmp/before/ --output /tmp/before.md
bca report -p "$PWD" -O markdown \
--strip-prefix "$PWD/" --output /tmp/after.md
diff -u /tmp/before.md /tmp/after.md | less
Because both reports use the same --strip-prefix shape, the path
columns line up and the diff is dominated by metric changes rather
than path noise.
C/C++ preprocessor-aware reports
Macro-heavy C/C++ codebases benefit from feeding preprocessor data into the analyzer so that conditional compilation is interpreted the way the compiler sees it. The workflow is two steps:
# 1. Build a preprocessor-data JSON from the headers and sources.
bca preproc \
--paths src/ include/ \
--output /tmp/preproc.json
# 2. Run the report (or any other command) with that data attached.
bca report \
--paths src/ \
--preproc-data /tmp/preproc.json \
-O markdown --output report.md
--preproc-data is accepted by every metric-computing walking
subcommand (metrics, ops, functions, report, check, …) —
anywhere accurate C/C++ analysis matters. Subcommands that do not
consume it (vcs, preproc, list-metrics, diff-baseline)
reject it as a usage error.
Analyze only files changed in a PR
Pipe a list of changed files into --paths-from - to score just the
diff, not the whole tree:
git diff --name-only --diff-filter=AM origin/main...HEAD \
| bca metrics --paths-from - -O json --output-dir ./out
--diff-filter=AMkeeps Added and Modified files and drops Deletions — you cannot analyze a file that no longer exists.--paths-from -reads newline-separated paths from stdin. A file argument works the same way:--paths-from changed.txt.- Paths fed in this way are treated as explicit, so they bypass
any
.gitignorerule that would have hidden them in a directory walk. Combine with-I '*.py' -I '*.rs'to filter by language (repeat the flag once per glob).
For a PR-scoped Markdown summary, swap metrics for the report
pipeline:
git diff --name-only --diff-filter=AM origin/main...HEAD \
| bca report --paths-from - -O markdown \
--top 10 --output pr-report.md
.gitignore is honored automatically when walking a directory, so
recipes earlier in this page no longer need an explicit
-X "**/target/**" -X "**/node_modules/**" if those paths are already
covered by your project's .gitignore. Add --no-ignore if you do
need to analyze gitignored trees.