Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,11 +442,15 @@ walking up from the analysis root to the nearest directory containing one
"roots": ["MyApp.Program.Main"],
"libraryProjects": ["MyLib"],
"ignore": ["Migrations/**", "Generated/", "**/*.designer.cs"],
"deadCode": {
"ignore": ["Plugins/**"]
},
"dupes": {
"mode": "semantic",
"minTokens": 100,
"minLines": 10,
"minOccurrences": 2
"minOccurrences": 2,
"ignore": ["**/InsurerUnionQuery.cs"]
},
"health": {
"maxComplexity": 15,
Expand All @@ -469,7 +473,11 @@ explicit `--aggressive`, `--root`, or `--library` always wins, otherwise the
config's value applies, otherwise the built-in default (`false` / no extra
roots / no extra library projects). The same `ignore` list also applies to
`roe dupes`, since a duplicate spans multiple files and doesn't map cleanly
onto a single-line inline suppression comment.
onto a single-line inline suppression comment. Each command's section takes
an `ignore` list of its own with the same rules, unioned with the top-level
one and applied only to that command — so accepting an intentional duplicate
through `dupes.ignore` doesn't cost the file its dead-code and health
coverage.

The `dupes` block sets defaults for `roe dupes`' matching mode and
thresholds, and the `health` block does the same for `roe health`'s
Expand Down
2 changes: 2 additions & 0 deletions _typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ extend-exclude = ["Cargo.lock", "tests/fixtures/", "tests/snapshots/"]
# `rejects_unknown_fields` in src/config.rs to prove serde rejects near-miss
# keys instead of silently ignoring them.
agressive = "agressive"
# Same idea for the `ignore` field, used by `rejects_unknown_dead_code_fields`.
ignor = "ignor"
5 changes: 4 additions & 1 deletion docs/commands/dead-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ never flagged even though no executable in the workspace uses it:
roe dead-code --library MyLib
```

Both can also be set persistently in a [config file](/configuration).
Both can also be set persistently in a [config file](/configuration). A
config's `deadCode.ignore` glob list drops every dead-code finding in
matching files without affecting the other commands — see
[Suppressing findings](/suppressing-findings).

## What counts as an entry point

Expand Down
16 changes: 13 additions & 3 deletions docs/commands/dupes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ roe dupes --mode semantic path/to/solution
## Ignoring files

Duplicates span multiple files, so there's no inline suppression comment for
them. Instead, use the `ignore` glob list in a
[config file](/configuration) — it applies to every command, dropping every
finding in matching files.
them. Instead, use ignore globs in a [config file](/configuration): the
top-level `ignore` list applies to every command, and the `dupes.ignore`
list adds patterns only the duplicate analysis honours — so accepting an
intentional duplicate doesn't cost the file its dead-code and health
coverage.

```json roe.json
{
"dupes": {
"ignore": ["**/InsurerUnionQuery.cs"]
}
}
```
9 changes: 5 additions & 4 deletions docs/commands/health.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ or a `??` whose fallback contains a ternary is counted on its own merits.
The footer's `N project(s), N file(s), N symbol(s) scanned` counts what was
*eligible to be reported*, not what was parsed. Anything ruled out up front —
test projects under `--exclude-tests`, files matched by the config's
[`ignore` globs](/configuration) — is subtracted, and named on a line of its
own:
[`ignore` globs](/configuration) (top-level or `health.ignore`) — is
subtracted, and named on a line of its own:

```text
found 8 issues across 7 locations in 6 files — 2 project(s), 118 file(s), 1204 symbol(s) scanned in 153 ms
Expand Down Expand Up @@ -398,5 +398,6 @@ public void ParseEverything(string input)
```

Circular dependencies span multiple files, so — like duplicates — they have
no inline comment. Use the `ignore` globs in a
[config file](/configuration) instead.
no inline comment. Use ignore globs in a [config file](/configuration)
instead — `health.ignore` scopes the suppression to health alone, so the
file keeps its dead-code and dupes coverage.
52 changes: 44 additions & 8 deletions docs/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ error.
"roots": ["MyApp.Program.Main"],
"libraryProjects": ["MyLib"],
"ignore": ["Migrations/**", "Generated/", "**/*.designer.cs"],
"deadCode": {
"ignore": ["Plugins/**"]
},
"dupes": {
"mode": "semantic",
"minTokens": 100,
"minLines": 10,
"minOccurrences": 2
"minOccurrences": 2,
"ignore": ["**/InsurerUnionQuery.cs"]
},
"health": {
"maxComplexity": 15,
Expand All @@ -41,7 +45,8 @@ error.
"maxFileLines": 750,
"maxTypeMembers": 25,
"excludeTests": true,
"baseline": "roe-baseline.json"
"baseline": "roe-baseline.json",
"ignore": ["**/GeneratedModels.cs"]
}
}
```
Expand All @@ -51,9 +56,10 @@ error.
| `aggressive` | boolean | Also flag enum members and public settable auto-properties. Default for the `--aggressive` flag. |
| `roots` | string[] | Fully-qualified symbol names to treat as extra entry-point roots. Default for `--root`. |
| `libraryProjects` | string[] | Project names to always treat in library mode (public API counts as used). Default for `--library`. |
| `ignore` | string[] | Glob patterns; every finding in a matching file is dropped. Applies to all three commands. |
| `dupes` | object | Matching mode and thresholds for [`roe dupes`](/commands/dupes). Every key is optional. |
| `health` | object | Thresholds and the baseline path for [`roe health`](/commands/health). Every key is optional. |
| `ignore` | string[] | Glob patterns; every finding in a matching file is dropped. Applies to all three commands; each command's section can add its own. |
| `deadCode` | object | Extra `ignore` globs applied only to [`roe dead-code`](/commands/dead-code). |
| `dupes` | object | Matching mode, thresholds, and extra `ignore` globs for [`roe dupes`](/commands/dupes). Every key is optional. |
| `health` | object | Thresholds, the baseline path, and extra `ignore` globs for [`roe health`](/commands/health). Every key is optional. |

Unknown fields are rejected, so a typo fails loudly instead of being
silently ignored.
Expand All @@ -69,6 +75,7 @@ Every field under `dupes` is optional and corresponds to a flag on
| `minTokens` | number | `--min-tokens` | `50` |
| `minLines` | number | `--min-lines` | `5` |
| `minOccurrences` | number | `--min-occurrences` | `2` |
| `ignore` | string[] | — | none |

This block is what calibrates a combined run: [`roe check`](/commands/check)
takes no dupes flags of its own, so raising `minTokens` here is how a one-line
Expand All @@ -89,6 +96,7 @@ Every field under `health` is optional and corresponds to a flag on
| `maxTypeMembers` | number | `--max-type-members` | `20` |
| `excludeTests` | boolean | `--exclude-tests` | `false` |
| `baseline` | string | `--baseline` | none |
| `ignore` | string[] | — | none |

Committing these is usually better than passing six flags on every CI
invocation, and it keeps local runs and CI in agreement.
Expand All @@ -108,9 +116,33 @@ full-backlog run.
A trailing `/` matches the whole directory, so `"Generated/"` needs no `**`.
Patterns containing `..` are unsupported and produce a warning.

The same `ignore` list also applies to `roe dupes` and to `roe health`'s
circular dependencies, since both span multiple files and don't map cleanly
onto a single-line [inline suppression comment](/suppressing-findings).
The top-level `ignore` list applies to all three commands — including
`roe dupes` and `roe health`'s circular dependencies, which span multiple
files and don't map cleanly onto a single-line
[inline suppression comment](/suppressing-findings).

Each command's section takes an `ignore` list of its own with the same
rules, unioned with the top-level list and applied only to that command.
That keeps a suppression as narrow as the exception it accepts: ignoring an
intentional duplicate through `dupes.ignore` doesn't cost the file its
dead-code and health coverage.

```yaml roe.yaml
ignore:
- "Generated/**"
deadCode:
ignore:
- "Plugins/**"
dupes:
ignore:
- "**/InsurerUnionQuery.cs"
health:
ignore:
- "**/GeneratedModels.cs"
```

A scoped list only ever adds patterns — it can't re-include a file the
top-level list ignores — and an empty one is a no-op.

## Precedence

Expand All @@ -136,6 +168,10 @@ Dupes settings follow the same per-field order: `--min-tokens 100` overrides
carries a value, so unlike `--aggressive` and `--exclude-tests` it has no
on-only nuance — `--mode exact` overrides a config's `"semantic"` cleanly.

Ignore lists sit outside this order entirely: they have no CLI flag, and a
command's own `ignore` list is unioned with the top-level one rather than
replacing it.

To confirm a config-only `excludeTests` or `ignore` actually applied, read the
`roe health` footer: the scanned counts narrow by whatever was excluded, and
an `excluded:` line names it. See
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/json-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ including its own `version` and `root`, so anything already written against
| --- | --- |
| `version` | Schema version, `1`. |
| `root` | The analysis root path. |
| `summary` | Scan totals: `projects`, `filesScanned`, `symbols`, one count per check (`highComplexity`, `highCognitiveComplexity`, `longMethods`, `tooManyParameters`, `largeFiles`, `largeTypes`, `circularDependencies`), and `elapsedMs`. `commitsWalked` is present only when `--hotspots` was passed. The three scan totals count what was eligible to be reported, so they narrow under `--exclude-tests` and the config's `ignore` globs. |
| `summary` | Scan totals: `projects`, `filesScanned`, `symbols`, one count per check (`highComplexity`, `highCognitiveComplexity`, `longMethods`, `tooManyParameters`, `largeFiles`, `largeTypes`, `circularDependencies`), and `elapsedMs`. `commitsWalked` is present only when `--hotspots` was passed. The three scan totals count what was eligible to be reported, so they narrow under `--exclude-tests` and the config's `ignore` globs (top-level and `health.ignore`). |
| `summary.baselined` | How many findings and cycles a [baseline](/commands/health#baselines) hid — they are counted nowhere else in this document. Present only when a baseline was in force, so `0` means "the baseline is fully ratcheted" and absent means "no baseline was used". |
| `summary.excluded` | What was ruled out before any check ran: `testProjects` (an array of project names, present under `--exclude-tests`) and `ignoredFiles` (a count). Omitted entirely when nothing was excluded. |
| `findings[].kind` | `high-complexity`, `high-cognitive-complexity`, `long-method`, `too-many-parameters`, `large-file`, or `large-type` — the same names used by [inline suppressions](/suppressing-findings). |
Expand Down
17 changes: 16 additions & 1 deletion docs/suppressing-findings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,25 @@ To drop every finding in matching files — for `dead-code`, `dupes`, and
}
```

To keep a suppression as narrow as the exception it accepts, scope it to one
command instead: each command's section takes an `ignore` list of its own,
unioned with the top-level one and applied only to that command. Accepting
an intentional duplicate this way doesn't cost the file its dead-code and
health coverage:

```json roe.json
{
"dupes": {
"ignore": ["**/InsurerUnionQuery.cs"]
}
}
```

See [Configuration](/configuration) for glob semantics and config discovery.

<Note>
Duplicate groups and circular dependencies span multiple files, so neither
maps onto a single-line comment and neither has an inline suppression.
Ignore globs are the only way to silence them.
Ignore globs — top-level, `dupes.ignore`, or `health.ignore` — are the only
way to silence them.
</Note>
Loading
Loading