Skip to content

[reporting] Report unused skips in JSON output too#8065

Merged
TomasVotruba merged 1 commit into
mainfrom
tv-skip-5
Jun 20, 2026
Merged

[reporting] Report unused skips in JSON output too#8065
TomasVotruba merged 1 commit into
mainfrom
tv-skip-5

Conversation

@TomasVotruba

@TomasVotruba TomasVotruba commented Jun 20, 2026

Copy link
Copy Markdown
Member

Why

->reportUnusedSkips() reports skips that never matched, so you can clean up dead ->withSkip() entries. It writes via SymfonyStyle, but when --output-format=json is used, ProcessCommand forces VERBOSITY_QUIET and the warning is silenced entirely. Editor/CI integrations typically run --dry-run --output-format=json, so unused skips never showed up there.

What

Surface unused skips in the JSON payload too. The computation is extracted into a shared UnusedSkipResolver service, so console and JSON stay in sync.

Example

Config:

return RectorConfig::configure()
    ->withRules([SimplifyUselessVariableRector::class])
    ->reportUnusedSkips()
    ->withSkip([
        SimplifyUselessVariableRector::class => [
            __DIR__ . '/src/Used.php',          // matched -> not reported
            __DIR__ . '/src/NeverMatches.php',  // never matched -> reported
        ],
    ]);

Console output (already worked):

 [WARNING] This skip is unused, it never matched any element. You can remove it
           from "->withSkip()"

 * Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector => /src/NeverMatches.php

JSON output before -- unused skips silently missing:

{
    "totals": { "changed_files": 1, "errors": 0 },
    "file_diffs": [ ... ],
    "changed_files": [ "src/SomeClass.php" ]
}

JSON output after -- new unused_skips key:

{
    "totals": { "changed_files": 1, "errors": 0 },
    "file_diffs": [ ... ],
    "changed_files": [ "src/SomeClass.php" ],
    "unused_skips": [
        "Rector\\CodeQuality\\Rector\\FunctionLike\\SimplifyUselessVariableRector => /src/NeverMatches.php"
    ]
}

The key is added only when reportUnusedSkips() is enabled and something is actually unused, so the JSON schema is otherwise untouched.

Changes

  • src/Reporting/UnusedSkipResolver.php (new) -- single source of truth. Returns "rule => path" for rule-scoped skips and a plain path for global ones; honors the reportUnusedSkips() guard; keeps the existing rules (per-path granularity, rule-scoped masks kept, global masks excluded).
  • src/Reporting/MissConfigurationReporter.php -- delegates to the resolver; console output unchanged.
  • src/ChangesReporting/Output/JsonOutputFormatter.php -- injects the resolver, passes results to the factory.
  • src/ChangesReporting/Output/Factory/JsonOutputFactory.php -- optional $unusedSkips param, adds the unused_skips key when non-empty.

Tests

  • New UnusedSkipResolverTest (unit): rule-scoped unused skip reported as rule => path; matched / global-mask / skip-everywhere excluded; disabled returns empty.
  • MissConfigurationReporterTest updated to the new constructor.

JSON output forces VERBOSITY_QUIET, which silenced the unused-skips
warning. Extract the computation into UnusedSkipResolver and surface it
as an unused_skips key in the JSON payload, so editor/CI runs using
--output-format=json see unused skips as well.
@TomasVotruba TomasVotruba merged commit 53a840f into main Jun 20, 2026
66 checks passed
@TomasVotruba TomasVotruba deleted the tv-skip-5 branch June 20, 2026 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant