Repository navigation
Add a result-cache-info command reporting how the next analyse would use the result cache - #6312
Merged
ondrejmirtes merged 1 commit intoAug 31, 2026
Conversation
…uld use the result cache - New `PHPStan\Command\ResultCacheInfoCommand` (`result-cache-info`), registered in `bin/phpstan`. It performs the same inception and file discovery as `analyse`, runs `ResultCacheManager::restore()` and then stops, so it answers whether the result cache would be used and how many files out of how many would be analysed - without analysing anything. - Human-readable output by default, `--json` for machine-readable output (`resultCachePath`, `resultCacheExists`, `resultCacheUsed`, `notUsedReason`, `analysedFilesCount`, `filesToAnalyseCount`, `lastFullAnalysisTime`). - `--fail-without-result-cache` makes the command exit with code 2 when the cache would not be used, matching the option name and exit code already used by `analyse`. - `ResultCache` carries a new `fullAnalysisReason` (`getFullAnalysisReason()`), so the reason the cache could not be reused is available to callers instead of only being printed in very verbose mode. - `ResultCacheManager::restore()`: extracted the twelve duplicated `return new ResultCache(fullAnalysis: true, ...)` blocks into a single private `fullAnalysis()` helper that both prints the reason in very verbose mode and stores it on the result. All twelve reasons (debug mode, only files, missing cache file, unreadable cache file, corrupted cache file, meta mismatch, changed Composer packages registering container classes, cache too old, missing/changed extension file, missing/changed stub file) are covered - the same sweep across the whole family.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The issue asks for a way to inspect the result cache state before running an analysis, so a project can decide whether it is worth downloading a result cache artifact built in CI. Two options were floated; in the discussion @ondrejmirtes settled on a
result-cache-infocommand that "verifies howanalysewould approach the analysis if nothing else changed between running the two commands", with human output first and--jsonfor machine-readable output.This adds that command. It runs the same inception and file discovery as
analyse, feeds the discovered files throughResultCacheManager::restore(), and then stops - nothing is analysed. It reports whether the result cache will be used at all, why not when it will not, and how many files out of how many would be analysed.Changes
src/Command/ResultCacheInfoCommand.php(new) - theresult-cache-infocommand. Takes the samepathsargument and--configuration/--level/--autoload-file/--memory-limit/--debug/--xdebugoptions asanalyse, plus--jsonand--fail-without-result-cache.deferBootstrapFiles: truelikeanalysedoes, becauseanalysealso restores the result cache before the bootstrap files run - so the computed meta is identical.--debugis deliberately not forwarded torestore(): debug mode always disables the result cache, and the command would then have nothing to report.--fail-without-result-cachereturns exit code 2 when the cache would not be used, reusing the option name and exit code thatanalysealready has for the same question. Without it the command always exits 0 on success.bin/phpstan- registers the new command.src/Analyser/ResultCache/ResultCache.php- newfullAnalysisReasonconstructor parameter andgetFullAnalysisReason();nullwhen the result cache is being used.src/Analyser/ResultCache/ResultCacheManager.php- new privatefullAnalysis()helper, replacing the twelve copies of theif ($output->isVeryVerbose()) { ... } return new ResultCache(fullAnalysis: true, ...)block. The helper prints the reason in very verbose mode (unchanged behaviour) and records it on theResultCache. Net effect on that file: 235 lines removed, 127 added.Analogous cases considered:
restore()were swept in one go, not just the ones easy to hit: debug mode, only-files, missing cache file, unreadable cache file, corrupted cache file, meta mismatch, changed Composer packages that register a container class, cache older thanresultCacheSkipIfOlderThanDays, missing extension file, changed extension file hash, missing stub file, changed stub file hash. Every one of them now reports its reason throughgetFullAnalysisReason().ResultCacheManager::process()/doSave()are the obvious parallel family. They were probed and deliberately left alone: they are only knowable after an analysis has run, soresult-cache-infocannot report them and threading a reason throughResultCacheProcessResultwould add an unused API.restore()callers (AnalyseApplication,FixerWorkerRunner) were checked - both use named arguments and are unaffected by the new constructor parameter.Root cause
Not a bug - a missing capability. The information the issue asks for already exists inside
ResultCacheManager::restore(), but it was only reachable in two ways: by running a full analysis (analyse --fail-without-result-cache, which only fails after the analysis) or by reading very verbose log lines. The reason string in particular was written straight to the output and then thrown away, which is why it was duplicated twelve times next to twelve identicalnew ResultCache(...)calls. Turning the reason into a value onResultCacheboth removes that duplication and makes the information available to a command that does not analyse anything.Test
tests/PHPStan/Command/ResultCacheInfoCommandTest.php(new,execgroup, so it runs undermake tests-integration) builds a throwaway two-file project in a temp directory with its owntmpDirand drives the realbin/phpstanbinary throughexec():resultCacheExists: false,resultCacheUsed: false, reason "Result cache not used because the cache file does not exist.", 2 out of 2 files; and exit code 2 with--fail-without-result-cacheanalyse:resultCacheUsed: true, 0 out of 2 files, alastFullAnalysisTimetimestamp, and exit code 0 with--fail-without-result-cache-l 6against a level-5 cache: not used, reason reports thelevelmeta differenceAll five fail without the change (the command does not exist), verified by reverting the
bin/phpstanregistration. Fullmake tests,make tests-integration,make phpstanandmake csare green.Fixes phpstan/phpstan#15135