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
10 changes: 10 additions & 0 deletions .changeset/confirm-bulk-ignore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@codacy/codacy-cloud-cli": minor
---

`codacy issues --ignore` now asks for confirmation before bulk-ignoring. It
prints how many issues match the current filters and only proceeds when you
answer `y`, guarding against a mistyped or too-broad filter ignoring far more
issues than intended. Pass `--skip-confirmation` (`-y`) to bypass the prompt in
CI or scripts; in a non-interactive shell without that flag the command aborts
without ignoring anything.
13 changes: 13 additions & 0 deletions .changeset/list-ignored-issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@codacy/codacy-cloud-cli": minor
---

Add `codacy issues --ignored` (`-i`) to list issues that were marked as ignored
on Codacy. Without the flag, `codacy issues` behaves exactly as before; pass
`--ignored` to see the ignored ones instead. The
ignored listing accepts all the same filters as the normal search (`--branch`,
`--severities`, `--categories`, `--tools`, `--patterns`, `--languages`, `--tags`,
`--authors`, `--limit`, and `--false-positives`), and each ignored issue shows
who ignored it, when, the reason, and any comment. It cannot be combined with
`--overview` or `--ignore`. `--output json` emits an `ignoredIssues` array.
Unignoring individual issues stays with `codacy issue <id> --unignore`.
8 changes: 8 additions & 0 deletions .gemini/styleguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ concerns.
versions (no `^`/`~`) for reproducibility and to avoid dependency-confusion
risk. Flagging an unpinned range is correct; suggesting a range is not.

## CLI output / rendering
- `src/utils/formatting.ts` has two issue-card renderers that differ **on
purpose**: `printIgnoredIssueCard` omits the "Potential false positive"
warning that `printIssueCard` shows, because an ignored issue already surfaces
its ignore reason (usually `FalsePositive`) on the metadata line. Don't flag
the missing warning as a parity gap. The shared header/message/file-line block
is factored into `printIssueCardBody`; the trailing sections diverge by design.

## Generated files
- `package-lock.json` and everything under `src/api/client/**` are generated.
Complexity, duplication, and size findings on these are false positives.
2 changes: 2 additions & 0 deletions SPECS/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,6 @@ _No pending tasks._ All commands implemented.
| 2026-06-24 | `findings` and `finding` now surface the vulnerable dependency's import chain from the new `dependencyChains` field: Direct (`Update <pkg> to <fixed>`) vs Transitive (`<chain> (Fixed in <fixed>)`), with the middle collapsed to `... N more ...` for 4+ packages. List shows the first chain + `... and X more`; detail shows all chains aligned under a single label. New helpers in `utils/formatting.ts` (`formatDependencyChain`, `formatDependencyChainsLine`, `formatDependencyChainsBlock`); `dependencyChains` added to both JSON projections (17 new tests, 390 total) |
| 2026-06-30 | npm-style "update available" notice via `update-notifier@5`: one-time stderr hint when a newer version is published, gated to `--output table` (suppressed for `json`, when piped, in CI, under `npx`). Non-blocking daily background check; never auto-updates. New `src/version.ts` (single source of name/version) + `src/utils/update-check.ts` (`maybeNotifyUpdate`); `preAction` hook + `--no-update-notifier` flag wired in `index.ts`. Opt-outs: `CODACY_DISABLE_UPDATE_CHECK`, `NO_UPDATE_NOTIFIER`, `--no-update-notifier`. `package.json` `overrides` pin transitive `got@^11.8.6`/`package-json@^7` (CVE-2022-33987) (7 new tests, 409 total) |
| 2026-07-07 | `ls` and `directories` commands: browse a repository's folders/files with quality metrics (Grade/Issues/Complexity/Duplication/Coverage). Auto-detect provider/org/repo and the cwd-relative path; `--path`/`--branch` options; `directories --plus-children` shows one extra level as a `└─` tree (header adds `, M subdirectories`). `--sort`/`--direction` (server-side; in `ls`, directories and files sorted independently), and `ls --search <term>` (files only; folds the path into the search as `<path>/%<term>` and shows full paths). Duplication uses `numberOfClones`; Complexity uses `complexity` (hotspots). Both fetch **all** pages (no pagination warning) via new `src/utils/repo-tree.ts` (path resolution + `resolveSort`/`resolveDirection` + `fetchAllDirectories`/`fetchAllFiles`). Row markers `▸` folder / dim `·` file (no emojis). Promoted `formatGrade` to `utils/formatting.ts` (now also colors E red) and added `formatCountCell`/`formatCoverageCell` (48 new tests, 457 total) |
| 2026-07-16 | `issues --ignored` (`-i`): new read-only mode listing issues marked as ignored on Codacy, via the dedicated `searchRepositoryIgnoredIssues` endpoint. Boolean flag modeled on `--false-positives` for consistency (not a `--state <value>` selector). Reuses `buildFilterBody` (all existing filters + `--false-positives` pass through) and the paginate-to-`--limit` loop; errors when combined with `--overview`/`--ignore`. New `printIgnoredIssueCard` in `utils/formatting.ts` renders the ignore metadata line (`Ignored as <reason> by <name> · <date>` + optional comment) and the string `issueId` (ignored issues have no numeric `resultDataId`). Omitting the flag keeps existing behavior unchanged (10 new tests, 475 total) |
| 2026-07-08 | `issues --overview` noise suggestions tuned to stop firing on low-volume repos: added a `NOISE_MIN_TOTAL` (200) floor on the repo's total issues that suppresses the whole "reduce noise" section below it, and a `NOISE_MIN_PATTERN` (100) absolute floor on each pattern's own count (AND-gated with the relative rules) so a long tail of tiny patterns can't drag the median down and make a ~9-issue pattern look noisy — the total floor is kept above the per-pattern floor so it isn't dead code; the ≥10% share rule now only applies with ≥11 distinct patterns (`NOISE_MIN_PATTERNS_FOR_SHARE` — an even split only drops below 10% once N > 10, so 8–10 balanced patterns would otherwise all be flagged); and the ≥3× multiple rule (`NOISE_MEDIAN_MULTIPLE`) now measures against the **median** (via new `medianOf()`) instead of the mean, so a single huge pattern can no longer inflate the baseline and mask smaller disproportionate patterns (5 new tests, 465 total) |
| 2026-07-17 | `issues --ignore` now confirms before bulk-ignoring: `executeBulkIgnore` prints the match count then prompts via shared `confirmAction` (`utils/prompt.ts`), proceeding only on `y`. New `--skip-confirmation` (`-y`) bypasses the prompt for CI/scripts (same short flag as `tools --import --skip-approval`); non-TTY without the flag aborts rather than ignoring by accident. Confirmation runs after the fetch (count is shown) but before any `bulkIgnoreIssues` call (3 new tests, 478 total) |
49 changes: 48 additions & 1 deletion SPECS/commands/issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ codacy is gh my-org my-repo --output json
## API Endpoints

- [`searchRepositoryIssues`](https://api.codacy.com/api/api-docs#searchrepositoryissues) — `AnalysisService.searchRepositoryIssues(provider, org, repo, cursor, limit, body)`
- [`searchRepositoryIgnoredIssues`](https://api.codacy.com/api/api-docs#searchrepositoryignoredissues) — `AnalysisService.searchRepositoryIgnoredIssues(provider, org, repo, cursor, limit, body)` (only when `--ignored` is given; accepts the same `SearchRepositoryIssuesBody`)
- [`issuesOverview`](https://api.codacy.com/api/api-docs#issuesoverview) — `AnalysisService.issuesOverview(provider, org, repo, body)` (only when `--overview` is given)
- [`listTools`](https://api.codacy.com/api/api-docs#listtools) — `ToolsService.listTools(cursor, limit)` (only when `--overview` surfaces noisy patterns, to map each pattern's `prefix` to its owning tool)
- [`listRepositoryTools`](https://api.codacy.com/api/api-docs#listrepositorytools) — `AnalysisService.listRepositoryTools(provider, org, repo)` (only when `--overview` surfaces noisy patterns, to detect config-file-driven tools)
Expand All @@ -39,10 +40,12 @@ codacy is gh my-org my-repo --output json
| `--tools <tools>` | `-T` | Comma-separated tool UUIDs or names |
| `--limit <n>` | `-n` | Maximum number of issues (default: 100, max: 1000) |
| `--overview` | `-O` | Show overview counts instead of list |
| `--ignored` | `-i` | List issues marked as ignored instead of active ones |
| `--false-positives [value]` | `-F` | Filter by potential false positives (true, false, or omit) |
| `--ignore` | `-I` | Ignore all issues matching current filters |
| `--ignore-reason <reason>` | `-R` | Reason for ignoring (AcceptedUse, FalsePositive, NotExploitable, TestCode, ExternalCode) |
| `--ignore-comment <comment>` | `-m` | Optional comment when using --ignore |
| `--skip-confirmation` | `-y` | Skip the confirmation prompt when using --ignore (for CI/scripts) |

## Output

Expand Down Expand Up @@ -128,6 +131,50 @@ calls only run when at least one noisy pattern exists.

`--output json` is unaffected (raw counts only — no relabeling or suggestions).

### Ignored mode (`--ignored`)

Lists issues that were marked as ignored on Codacy, via the dedicated
`searchRepositoryIgnoredIssues` endpoint. `--ignored` is a boolean flag (like
`--false-positives`); without it, `codacy issues …` lists active issues as
before, and passing `--ignored` switches to the ignored listing.

The endpoint accepts the same filter body as the active-issues search, so every
filter (`--branch`, `--patterns`, `--tools`, `--severities`, `--categories`,
`--languages`, `--tags`, `--authors`, `--limit`) and `--false-positives` apply.
It cannot be combined with `--overview` (no ignored-issues overview exists) or
`--ignore` (those issues are already ignored) — both error out.

Output is a card list sorted by severity, like the default list mode, plus an
ignore-metadata line per issue:

```
Critical | Security Injection <issueId>
Potential SQL injection vulnerability

src/auth.ts:20
db.query(`SELECT * FROM users WHERE id = ${id}`);

Ignored as FalsePositive by Jane Dev · 2026-06-01
Comment: Reviewed, not exploitable
```

Ignored issues carry the string `issueId` (there is no numeric `resultDataId`),
and the `Comment:` line is shown only when a comment was recorded. Unignoring is
not part of this mode — use `codacy issue <id> --unignore` (there is no
bulk-unignore endpoint). `--output json` emits `{ ignoredIssues: [...] }`
projected to the shown fields.

### Bulk ignore mode (`--ignore`)

Fetches every issue matching the current filters (all pages) and marks them all
as ignored via `bulkIgnoreIssues` (batched at 100 IDs per call). Because this is
destructive and applies to *all* matching issues, it prompts for confirmation
after showing the count (`Ignore all N matching issues? …`) and only proceeds on
an explicit `y`. `--skip-confirmation` (`-y`) bypasses the prompt for CI/scripts;
in a non-interactive shell without that flag the prompt cannot be answered, so
the command aborts without ignoring anything (rather than ignoring by accident).
Cannot be combined with `--overview` or `--limit`.

## Tests

File: `src/commands/issues.test.ts` — 46 tests.
File: `src/commands/issues.test.ts` — 64 tests.
7 changes: 7 additions & 0 deletions src/commands/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,15 @@ Keeps the two command handlers thin: they only supply the API-specific callbacks
- **`--ignore` mode** (`-I`): fetches all issues matching current filters (all pages), then calls `AnalysisService.bulkIgnoreIssues` in batches of 100
- `-R, --ignore-reason`: `AcceptedUse` (default) | `FalsePositive` | `NotExploitable` | `TestCode` | `ExternalCode`
- `-m, --ignore-comment`: optional free-text comment
- **Confirmation** (`-y, --skip-confirmation`): the ignore is destructive and applies to *all* matching issues, so `executeBulkIgnore` prompts via `confirmAction` (shared `utils/prompt.ts`) after printing the count, and only proceeds on an explicit `y`. `--skip-confirmation` skips the prompt for CI/scripts. `confirmAction` returns `false` on a non-TTY, so a non-interactive run without the flag aborts rather than ignoring by accident. Same `-y` short flag as `tools --import`'s `--skip-approval`. Confirmation happens *after* fetching (so the count is shown) but *before* any `bulkIgnoreIssues` call
- Cannot be combined with `--overview` or `--limit`
- Works with any combination of filters; use `--false-positives --ignore` to ignore only FP issues
- **`--ignored` mode** (`-i`): boolean flag that lists ignored issues instead of active ones. Modeled as a boolean flag for consistency with the other boolean filter, `--false-positives` (not a `--state <value>` selector). `-i` is the natural short flag; note it is distinct from `-I/--ignore` (the bulk-ignore *action*) — `-i` lists already-ignored issues, `-I` ignores matching active ones. Omitting the flag keeps the existing active-issues behavior unchanged
- `--ignored` calls `AnalysisService.searchRepositoryIgnoredIssues` (dedicated `.../ignoredIssues/search` endpoint), reusing `buildFilterBody` — every base filter passes through unchanged — and the same paginate-to-`--limit` loop + pagination warning as list mode
- Guards: errors when combined with `--overview` (no ignored-issues overview endpoint) or `--ignore` (those issues are already ignored). `--false-positives` is intentionally **allowed** — it's part of the shared filter body, so "ignored issues that are potential false positives" is a valid query
- Rendered via `printIgnoredIssueCard` (in `utils/formatting.ts`): a variant of `printIssueCard` because `IgnoredIssue` has no numeric `resultDataId` (shows the string `issueId` instead) and carries ignore metadata — the trailing `Ignored as <reason> by <name> · <friendly date>` line plus an optional `Comment:` line
- View-only: unignoring stays with `issue --unignore` (there is no bulk-unignore endpoint; it would be N per-issue `updateIssueState` calls — a possible fast-follow since `IgnoredIssue` carries the string `issueId`)
- JSON: `{ ignoredIssues: [...] }`, each item projected via `pickDeep` (`issueId`, `reason`, `comment`, `ignoredByName`, `ignoredTimestamp`, `patternInfo.*`, `filePath`, `lineNumber`, `lineText`, `falsePositive*`)

## finding command (`finding.ts`)

Expand Down
Loading
Loading