<!-- markdownlint-disable-line MD013 -->
# rebar3_uncovered [![CI Status][ci-img]][ci] [![Hex.pm Version][hex-img]][hex] [![Minimum Erlang Version][erlang-img]][erlang] [![License][license-img]][license]
[ci]: https://github.com/eproxus/rebar3_uncovered/actions/workflows/ci.yml?query=branch%3Amain
[ci-img]: https://img.shields.io/github/actions/workflow/status/eproxus/rebar3_uncovered/ci.yml?label=ci
[hex]: https://hex.pm/packages/rebar3_uncovered
[hex-img]: https://img.shields.io/hexpm/v/rebar3_uncovered
[erlang]: https://github.com/eproxus/rebar3_uncovered/blob/main/mise.toml
[erlang-img]: https://img.shields.io/badge/erlang-28+-blue.svg
[license]: LICENSE.md
[license-img]: https://img.shields.io/hexpm/l/rebar3_uncovered
A Rebar 3 plugin that reports on uncovered lines from tests. Run it after
`rebar3 eunit` or `rebar3 ct` to see which lines your tests missed. Use `--git`
to narrow the report to lines changed on this branch.

A machine-readable format is also available for script / CI / LLM consumption.
Prefix with `QUIET=1` to suppress Rebar's own log messages:
```console
$ QUIET=1 rebar3 uncovered --git --format=raw --context=0 --counts=false
src/gaffer_queue.erl:141 _ = gaffer_hooks:with_hooks(
src/gaffer_queue.erl:142 Hooks, [gaffer, queue, delete], Name, fun(N) -> N end
src/gaffer_queue.erl:144 ok = gaffer_sup:stop_queue(gaffer_queue_sup:pid(Name)),
src/gaffer_queue.erl:145 persistent_term:erase({gaffer_queue, Name})
src/gaffer_queue.erl:151 {error, not_found} -> ok
```
## Installation
Add the plugin to your project's `rebar.config`:
```erlang
{project_plugins, [rebar3_uncovered]}.
```
To install it globally for all projects, add it to
`~/.config/rebar3/rebar.config`:
```erlang
{plugins, [rebar3_uncovered]}.
```
## Usage
```console
rebar3 uncovered [options] [-- path ...]
rebar3 help uncovered
```
Positional arguments after `--` are used as file or directory filters.
### Git scopes
Git organizes your working state as layers on top of trunk:
```sh
unstaged # Edits not yet added to the index
staged # Changes added to the index but not committed
HEAD # The latest commit on this branch
HEAD~X # Some intermediary commit between trunk and HEAD
trunk # Base branch (origin/main, origin/master, …)
```
`--git-scope` picks which layer to diff against, which determines what counts
as "changed":
- `auto` *(default)*: diff against trunk: branch commits, staged, and
unstaged all count
- `HEAD`: only uncommitted work (staged + unstaged)
- `staged`: only staged changes
- `unstaged`: only unstaged changes
- Any git ref (`origin/main`, `HEAD~1`, a commit SHA, etc.): diff against that
ref
### Examples
Show uncovered lines in the dirty working tree before committing:
```console
rebar3 uncovered --git --git-scope HEAD
```
Show uncovered lines on this branch against trunk:
```console
rebar3 uncovered --git
```
In CI or in LLM tooling, check that all changed lines are covered by tests (raw
format, no context lines):
```console
QUIET=1 rebar3 uncovered --git --format=raw --context=0 --counts=false
```
Show uncovered lines against a specific ref:
```console
rebar3 uncovered --git --git-scope origin/main
rebar3 uncovered --git --git-scope HEAD~3
```
### All Options
- **`--help`**, **`-h`**
Show usage information and available options.
- **`--git`**, **`-g`**
Filter uncovered lines to only those changed in the current git diff.
*Disabled by default.*
- **`--git-scope`**
Which git diff to consider. Only has effect when `--git` is enabled. Refs
include all changes between where they diverged and `HEAD`.
- `auto` *(default)*: diff against trunk, resolved as the first of
`origin/HEAD`, `origin/main`, `origin/master`, `HEAD`
- `staged`: only changes added to the index
- `unstaged`: only working tree changes
- any git ref (e.g. `HEAD`, `HEAD~1`, `origin/main`, a commit SHA):
diff against that ref
- **`--coverage`**
Which coverage data to use.
- `aggregate` *(default)*: combine all test suites
- `eunit`: only EUnit coverage data
- `ct`: only Common Test coverage data
- **`--format`**, **`-f`**
Output format.
- `human` *(default)*: color-coded table with line numbers, coverage counts,
and source context
- `raw`: one line per uncovered line in a grep-like format suitable for
scripts, CI, or LLM consumption. Set the environment variable `QUIET=1` to
suppress Rebar's own log messages for clean output
- **`--context`**, **`-C`**
Number of covered lines to show around each uncovered line for context.
- `<integer>` *(default: `2`)*: number of context lines to show
- `0`: show only uncovered lines
- `all`: show the entire function
- **`--counts`**
Show how many times each line was executed. Use `--counts false` to hide the
counts column. *Enabled by default.*
- **`--color`**
Color output. Respects the `NO_COLOR` environment variable.
- `auto` *(default)*: enable color when output is a terminal
- `always`: force color on
- `never`: disable color
## Changelog
See the [Releases](https://github.com/eproxus/rebar3_uncovered/releases) page.
## Code of Conduct
Find this project's code of conduct in [Contributor Covenant Code of
Conduct](CODE_OF_CONDUCT.md).
## Contributing
First of all, thank you for contributing with your time and energy.
If you want to request a new feature make sure to [open an
issue](https://github.com/eproxus/rebar3_uncovered/issues/new?template=feature_request.md)
so we can discuss it first.
Bug reports and questions are also welcome. If you found a bug, please check
that you're using the latest version first. If you have a question, search the
issue database as it might have already been answered.
Contributions will be subject to the MIT License. You will retain the copyright.
For more information check out [CONTRIBUTING.md](CONTRIBUTING.md).
## Security
This project's security policy is made explicit in [SECURITY.md](SECURITY.md).
## Conventions
### Versions
This project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### License
This project uses the [MIT License](LICENSE.md).