Skip to content

simplecov CLI#1182

Merged
sferik merged 11 commits into
mainfrom
cli
May 17, 2026
Merged

simplecov CLI#1182
sferik merged 11 commits into
mainfrom
cli

Conversation

@sferik
Copy link
Copy Markdown
Collaborator

@sferik sferik commented May 11, 2026

Adds a simplecov executable, with the following subcommands:

Command What it does
simplecov run <cmd...> Wrap any command in a SimpleCov run with auto-instrumentation
simplecov coverage <path> Print stats for one file
simplecov report Print the totals to terminal
simplecov uncovered [-n N] List the N files with the lowest coverage (default 10)
simplecov merge <a> <b> ... Stitch parallel-worker resultsets
simplecov diff <baseline> Print per-file coverage delta vs. a baseline resultset
simplecov open Launch the HTML report in the default browser
simplecov clean Remove the coverage report directory
simplecov serve [--port N] Serve the HTML report over HTTP

Expose Result#coverage_for(path) and Result#source_file_for(path) and
add a CLI for editor plugins, CI scripts, and MCP-style tools that
consume reports out-of-band.

This comment was marked as resolved.

sferik added 2 commits May 11, 2026 22:42
Tiny QoL wrapper around the platform's default opener (`open` /
`xdg-open` / `start`) so users don't have to type a file:// URL or
remember the path to coverage/index.html. Defaults to
coverage/index.html; --report PATH overrides.
sferik added 3 commits May 15, 2026 17:18
Same numbers as the HTML report's All Files row plus per-group totals,
for contexts where opening a browser isn't an option (CI logs, ssh
sessions, terminal-only workflows). Reads coverage.json directly so
it's a strict consumer of existing JSONFormatter output.
So adding more subcommands doesn't keep growing the cyclomatic complexity of SimpleCov::CLI.run. Subcommand modules now accept extra keyword arguments via `**` so the dispatcher can pass both stdout and stderr uniformly.
Quick "where should I add tests next?" view: read coverage.json,
filter to files below --threshold (default 100%), and print up to
--top files (default 10) sorted worst-first. Editor- and lazy-CI-
friendly: no need to open the HTML report just to find the next file
to write tests for.
sferik added 5 commits May 15, 2026 21:55
…hell

Wraps SimpleCov::ResultMerger.merge_results so a CI matrix that drops
one .resultset.json per worker can produce a merged resultset without
hand-rolling a Rake task. The simplecov library is lazy-required so
the read-only subcommands (coverage / report / uncovered) keep their
fast cold-start path.

Validate inputs up-front and surface per-file errors before the merge
runs, so "this file isn't valid JSON" / "no resultset entries" points
at the specific bad input instead of falling out of ResultMerger as a
generic "no mergeable results in input files". When two input files
share a command_name, log a warning — ResultMerger would otherwise
silently fold them together with last-write-wins on the timestamp,
which is easy to mistake for "no merge happened".
Reads two coverage.json files (current + baseline) and lists the
files whose coverage moved on any enabled criterion, regressions
first. Line, branch, and method deltas all surface on the same row
when their absolute change exceeds a small noise threshold. Files
present on only one side are tagged "(new file)" or "(removed)".

`--fail-on-drop` exits non-zero when any file's line coverage
slipped, so this composes with CI as a "coverage of this PR didn't
drop" gate even when overall thresholds are still satisfied.
`--threshold N` filters out small deltas (useful when a baseline is
noisy); `--json` emits the rows as a JSON array for programmatic
consumption. Coverage keys with a leading `/` (from coverage.json
files written before the SourceFile#project_filename change) are
normalized so an older baseline still diffs cleanly against newer
reports.

Resolves #886.
The CLI was hardcoding 'coverage/' as the base for every default
path (--input, --report, --output). For simplecov-on-simplecov the
report actually lives in tmp/dogfood/, so 'simplecov open' fell back
to a non-existent path. Walk up from cwd for a .simplecov, lazy-load
simplecov with SimpleCov.start neutered so a project whose dotfile
starts coverage doesn't trigger tracking + an at_exit hook just from
the CLI asking for a config value, and snapshot/restore coverage_dir
so we don't quietly mutate host-process state when the CLI is
exercised inline by the spec suite.

For simplecov's own repo, drop a top-level .simplecov gated on
ENV['SIMPLECOV_CLI'] (set by the CLI's loader) so the value reaches
the CLI but doesn't leak into descendant Ruby processes (the
eval_test fixture, the cucumber test_projects) that would otherwise
inherit it via simplecov's own walk-up auto-load.
Quality-of-life wrapper around `rm -rf <coverage_dir>` that uses the
same .simplecov-aware resolution as the rest of the CLI, so it deletes
whatever the project's report dir actually is (e.g. tmp/dogfood/ when
run on simplecov itself, not the never-existed coverage/). --dry-run
prints the would-delete path so you can sanity-check before pulling
the trigger.
Tiny static-file server backed by stdlib `socket` so no extra runtime
dep is needed just to view a local report on a CI box where file://
URLs don't work, a remote dev session over ssh, or a sandboxed
browser. --port defaults to a random open port; --host defaults to
loopback. Ctrl-C terminates the loop.
@sferik sferik merged commit 3787de4 into main May 17, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants