Skip to content

feat: surface coverage status in repositories and repository - #48

Open
alerizzo wants to merge 3 commits into
mainfrom
feat/coverage-status
Open

feat: surface coverage status in repositories and repository#48
alerizzo wants to merge 3 commits into
mainfrom
feat/coverage-status

Conversation

@alerizzo

Copy link
Copy Markdown
Collaborator

Summary

The API now returns a CoverageStatus (None/UpToDate/Waiting/Stopped) on Coverage, so the CLI can finally tell apart three situations that looked identical before: a stale percentage, a repository that stopped receiving reports, and one that never had coverage. Mirrors codacy-spa#3110. No API bump — pinned 57.4.17 already ships the field.

  • repositories — a dim after a Waiting value, a dim instead of a Stopped one (the API sends no percentage), and a legend under the table listing only the statuses actually present. Glyphs follow the existing vocabulary: is already formatStandards's "not final yet" marker, shares the Mathematical Operators block with the public-repo marker. No emojis.
  • repository — the Metrics row spells the state out with the date and commit of the last report, notes when a stopped repository's coverage gate is no longer enforced, and renders None as Not set up rather than a bare N/A.
  • Analysis row rewrittenformatAnalysisStatus gained an authoritative coverageStatus that wins over its expectsCoverage/hasCoverageData heuristic. That heuristic was wrong for Waiting: a waiting repository still reports a stale percentage, so hasCoverageData was true and the row said nothing in exactly the case worth surfacing. pull-request keeps the heuristic — its coverage models carry no status field — and is untouched.
 Name                      Grade  Issues  Complexity  Duplication  Coverage  Last Updated
 codacy-spa                A         373       12.0%          N/A     81.0%  1h ago
 portal                    A         241        5.0%        13.0%   19.0% ⋯  4 min ago
 remote-provider-service   A         126        6.0%        17.0%         ⊘  2026-08-25
 codacy-cloud-cli ⊙        A          55       33.0%        28.0%       N/A  Yesterday

 ⋯ no coverage report for the latest commit yet — showing the last known value
 ⊘ stopped receiving coverage reports

Worth a reviewer's attention

  • One fewer request, and repository tokens gain capability. Dropping the superseded listCoverageReports call takes repository from 5 parallel requests to 4. Because getRepositoryWithAnalysis is whitelisted for repository tokens while listCoverageReports is not, repository-token users get the coverage state for the first time, and unavailable is now ["pullRequests"] alone.
  • Accepted trade-off. When status is undefined (39 of 248 repos in the codacy org), the Analysis row now shows no coverage hint where the heuristic might have said "Missing coverage reports". That's the honest reading of an absent status, but it is a behavior removal. If you'd rather not, the fallback is to keep the call and let the status win only when defined — 3 lines in formatAnalysisStatus.
  • repositories.ts's local formatMetric was deleted — a stale copy of the shared colorMetric. Leaving it would have let coverage and complexity/duplication drift inside the same table. Side effect: absent metrics there now render a dim N/A instead of a bare one.
  • Waiting keeps its threshold coloring on the stale value, matching the SPA. The glyph is what marks it stale. Happy to change if that reads as misleading.

Test plan

  • npx tsc --noEmit && npm test — 664 tests (39 new).
  • Live check, one fixture per status:
    codacy repos gh codacy --search codacy-spa               # UpToDate: "81.0%", no glyph, no legend
    codacy repos gh codacy --search portal                   # Waiting:  "19.0% ⋯" + ⋯ legend
    codacy repos gh codacy --search remote-provider-service  # Stopped:  "⊘", no %, + ⊘ legend
    codacy repos gh codacy --search codacy-cloud-cli         # None:     "N/A", no glyph, no legend
    codacy repo gh codacy portal                             # Metrics + Analysis row both say "not reported yet"
    codacy repo gh codacy remote-provider-service            # "Stopped receiving reports … — coverage gate no longer enforced"
    
  • Degradation at scale — the ~39 status-less repos must render exactly as before:
    codacy repos gh codacy -o json | jq -r 'map(.coverage.status // "MISSING") | group_by(.) | map({(.[0]): length}) | add'
    
  • codacy repo gh codacy codacy-cloud-cli -o json | jq '.repository.coverage'{"status":"None"} and nothing else.
  • pull-request unaffected: codacy pr gh codacy portal <n> still shows its Analysis row from the 3h heuristic.

Verified end to end against the live API on all of the above except the repository-token path, which rests on the unit test asserting unavailable === ["pullRequests"].

🤖 Generated with Claude Code

The API now returns a CoverageStatus (None/UpToDate/Waiting/Stopped) on
Coverage, so the CLI can tell apart three situations that previously looked
identical: a stale percentage, a repository that stopped receiving reports,
and one that never had coverage at all. Mirrors codacy-spa#3110.

The field rides on Coverage, embedded only in RepositoryWithAnalysis, so
`repositories` and `repository` are the only commands that can show it.
`repositories` marks a Waiting value with a dim glyph and replaces a Stopped
one (the API sends no percentage) with its own, explained by a legend that
only lists the statuses actually present. `repository`'s Metrics row spells
the state out with dates and commit, and notes when a stopped repository's
coverage gate is no longer enforced.

Also replaces formatAnalysisStatus's coverage heuristic for `repository`. It
inferred state from a separate listCoverageReports call plus "is a percentage
present", which was wrong for Waiting -- a waiting repository still reports a
stale percentage, so the row stayed silent in exactly the case worth
surfacing. Reading the real status drops that request, and because
getRepositoryWithAnalysis is whitelisted for repository tokens while
listCoverageReports is not, coverage state reaches repository-token users for
the first time. `pull-request` keeps the heuristic: its coverage models carry
no status field.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codacy-production

codacy-production Bot commented Sep 10, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 51 complexity · 12 duplication

Metric Results
Complexity 51
Duplication 12

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

No merge-blocking security or logic issues were identified. Codacy is up to standards, but the coverage report is unavailable, so production-line test coverage cannot be independently verified.

Two acceptance-related scenarios remain unverified: status-less repository dashboard behavior and continued pull-request heuristic behavior. The main test file is also high-maintenance due to its size, as noted in the file comment.

About this PR

  • Add automated coverage for status-less repository dashboard behavior and preservation of pull-request heuristic behavior.
  • The coverage report is empty, so production-line coverage for the new behavior cannot be independently verified.
1 comment outside of the diff
src/utils/formatting.test.ts

line 1 🟡 MEDIUM RISK
Suggestion: Split this test file into focused files for repository coverage-status behavior and general formatting cases, with shared fixtures/helpers kept in a small module.

Test suggestions

  • Waiting repository table renders stale percentage, glyph, and conditional legend
  • Stopped repository table renders only and conditional legend
  • Healthy, None, absent, and status-less repository table rendering remains compatible
  • Conditional coverage legend deduplicates and includes only present statuses
  • Repository detail renders Waiting provenance and Stopped last-report information
  • Coverage gate consequence appears only when a goal is configured
  • None repository detail renders Not set up
  • Analysis status prioritizes Waiting/Stopped over the heuristic and leaves UpToDate/None silent
  • Coverage formatting helpers preserve threshold coloring and sanitize commit identifiers
  • Repository JSON projects coverage status fields and None-only payload
  • Repository-token dashboard skips pull requests and reports only pullRequests unavailable
  • Status-less repository dashboard preserves the prior heuristic-removal behavior
  • Pull-request command remains behaviorally covered by the heuristic after repository changes
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Status-less repository dashboard preserves the prior heuristic-removal behavior
2. Pull-request command remains behaviorally covered by the heuristic after repository changes

TIP How was this review? Give us feedback

alerizzo and others added 2 commits September 10, 2026 16:20
From a pre-review pass over the branch.

A `Waiting` payload with no `coveragePercentage` rendered as "N/A ⋯" under a
legend reading "showing the last known value", and as "N/A  Not reported yet
... — value from 11h ago" in the detail view — both describing a number that
isn't on screen. Observed payloads always carry a stale percentage, but the
field is documented as present only for the latest commit, which a waiting
repository by definition doesn't have, so gate both claims on a value actually
being there rather than on the status alone.

Also replaces the two non-null assertions with `&& glyph` / `&& note` guards,
so a missing marker degrades to the ordinary metric instead of printing the
string "undefined", and adds COVERAGE_STATUS_GLYPH as a
Record<CoverageStatus, …>. The four renderers all fall through to "render
nothing", so a new status member from `npm run update-api` would have compiled
clean and silently disappeared; now it fails to compile at the Record.

AGENTS.md claimed `None` renders "exactly as before", which is true of the
table but not the detail view — the same PR deliberately renders it as
"Not set up". Corrected, since that file is loaded as project instructions and
would have talked the next agent out of intended behavior.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both gaps were real. `pull-request` is now `formatAnalysisStatus`'s only caller
of the expectsCoverage/hasCoverageData heuristic, but its tests only ever mocked
hasCoverageOverview: false, so the hint path was never exercised at the command
level and nothing would have failed if someone deleted the heuristic outright.
Adds a test that drives it past the 3h grace period and asserts "Missing
coverage reports", pinning the threshold rather than just that some hint appears.

The status-less dashboard case was only covered incidentally (the shared repo
fixture happens to carry no status). Since "no coverage hint when status is
undefined" is a deliberate behavior removal, it now has an explicit test rather
than resting on a fixture detail.

Also broadens the test-file bullet in the Codacy review instructions. It already
said length and duplication findings on *.test.ts are expected, but the reviewer
suggested splitting formatting.test.ts by theme, which the wording didn't cover.
Tests are co-located one-per-module by design, so a helper's tests belong beside
its source however long that file grows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@alerizzo

Copy link
Copy Markdown
Collaborator Author

Thanks — both flagged test gaps were real, and both are now covered.

Added: pull-request heuristic coverage (6770d25). This one was a genuine hole. repository now reads the API's authoritative coverage.status, which leaves pull-request as the only caller of formatAnalysisStatus's expectsCoverage/hasCoverageData heuristic — but its tests only ever mocked hasCoverageOverview: false, so the hint path was never exercised at the command level and nothing would have failed if someone deleted the heuristic outright. The new test drives it past the 3-hour grace period and asserts Missing coverage reports, so it pins the threshold rather than merely that some hint appears.

Added: status-less dashboard behavior (6770d25). Previously covered only incidentally — the shared repo fixture happens to carry no status. Since "no coverage hint when status is undefined" is a deliberate behavior removal (documented as an accepted trade-off in SPECS/commands/analysis.md), it now has an explicit test instead of resting on a fixture detail.

Not doing: splitting src/utils/formatting.test.ts. Two reasons. First, .codacy/instructions/review.md already asks for this class of finding to be skipped on *.test.ts — the existing bullet covered length and duplication, so I've broadened it to cover reorganization suggestions too. Second, the file's size is structural and pre-existing (517 lines and 15 describe blocks before this PR — it covers ~20 shared helpers); tests here are co-located one-per-module by design, so a helper's tests belong beside its source however long that file grows. Splitting by theme would break that mapping, and doing it in this PR would bury the feature diff in a rename.

On the empty coverage report: this repository has no coverage set up at all (coverage.status: "None") — which is, fittingly, one of the states this PR exists to make visible. Nothing to fix here, though it does mean the new tests are the only coverage signal for this change.

Also folded in a separate pre-review pass (a20d380): a Waiting payload with no coveragePercentage was rendering N/A ⋯ under a legend reading "showing the last known value", describing a number that isn't on screen. Both that claim and the detail view's "value from ..." clause are now gated on a value actually being rendered.

668 tests pass; all checks green.

🤖 Generated by /pr-fixup command

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.

1 participant