From 193bb4e5cb62a600273a40509c654cd9b0631292 Mon Sep 17 00:00:00 2001 From: staabm <120441+staabm@users.noreply.github.com> Date: Mon, 29 Jun 2026 21:21:07 +0000 Subject: [PATCH 1/4] Notify in CI when a slow full analysis ran without a pre-existing result cache - Add `ResultCacheManager::resultCacheExists()` to report whether the result cache file was on disk when PHPStan started, before `restore()` can unlink it. - Thread that fact through `AnalyseApplication` into a new `AnalysisResult::resultCacheExisted()` getter (defaults to true so a stale but present cache that forced a full re-analysis does not trigger the message). - In `AnalyseCommand`, after a full analysis, print a hint to persist the result cache directory when: running in CI (detected via `CiDetector`), analysing full paths (not `--only-files`), the cache file did not exist at start, and the run took longer than `RESULT_CACHE_CI_NOTIFICATION_ELAPSED_LIMIT` (60s). - The message is intentionally suppressed when the cache existed but was invalid. --- .../ResultCache/ResultCacheManager.php | 9 ++ src/Command/AnalyseApplication.php | 2 + src/Command/AnalyseCommand.php | 30 ++++ src/Command/AnalysisResult.php | 12 ++ .../Command/ResultCacheCiNotificationTest.php | 140 ++++++++++++++++++ 5 files changed, 193 insertions(+) create mode 100644 tests/PHPStan/Command/ResultCacheCiNotificationTest.php diff --git a/src/Analyser/ResultCache/ResultCacheManager.php b/src/Analyser/ResultCache/ResultCacheManager.php index e3172812c5b..0d3fb510fce 100644 --- a/src/Analyser/ResultCache/ResultCacheManager.php +++ b/src/Analyser/ResultCache/ResultCacheManager.php @@ -117,6 +117,15 @@ public function __construct( { } + /** + * Whether the result cache file was present on disk when PHPStan started. + * Distinguishes "the cache never existed" from "the cache existed but was invalid". + */ + public function resultCacheExists(): bool + { + return is_file($this->cacheFilePath); + } + /** * @param string[] $allAnalysedFiles * @param mixed[]|null $projectConfigArray diff --git a/src/Command/AnalyseApplication.php b/src/Command/AnalyseApplication.php index 2cc886eb0f9..7ec2169d4fb 100644 --- a/src/Command/AnalyseApplication.php +++ b/src/Command/AnalyseApplication.php @@ -71,6 +71,7 @@ public function analyse( $fileReplacements = [$insteadOfFile => $tmpFile]; } $resultCacheManager = $this->resultCacheManagerFactory->create($fileReplacements); + $resultCacheExisted = $resultCacheManager->resultCacheExists(); $ignoredErrorHelperResult = $this->ignoredErrorHelper->initialize(); $fileSpecificErrors = []; @@ -190,6 +191,7 @@ public function analyse( $isResultCacheUsed, $changedProjectExtensionFilesOutsideOfAnalysedPaths, $processedFiles, + $resultCacheExisted, ); } diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index d2e39d33003..4a9a901259e 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -54,6 +54,7 @@ use function is_bool; use function is_file; use function is_string; +use function microtime; use function pathinfo; use function rewind; use function sprintf; @@ -76,6 +77,8 @@ final class AnalyseCommand extends Command public const DEFAULT_LEVEL = CommandHelper::DEFAULT_LEVEL; + private const RESULT_CACHE_CI_NOTIFICATION_ELAPSED_LIMIT = 60.0; + /** * @param string[] $composerAutoloaderProjectPaths */ @@ -494,6 +497,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $analysisResult->isResultCacheUsed(), $analysisResult->getChangedProjectExtensionFilesOutsideOfAnalysedPaths(), $analysisResult->getProcessedFiles(), + $analysisResult->resultCacheExisted(), ); $exitCode = $errorFormatter->formatErrors($analysisResult, $inceptionResult->getStdOutput()); @@ -650,6 +654,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } + $this->reportMissingResultCacheInCi($errorOutput, $analysisResult, $onlyFiles); + $this->runDiagnoseExtensions($container, $inceptionResult->getErrorOutput(), $analysisResult->getProcessedFiles()); return $inceptionResult->handleReturn( @@ -659,6 +665,30 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); } + private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResult $analysisResult, bool $onlyFiles): void + { + if ( + $onlyFiles + || $analysisResult->isResultCacheUsed() + || $analysisResult->resultCacheExisted() + ) { + return; + } + + if (microtime(true) - $this->analysisStartTime < self::RESULT_CACHE_CI_NOTIFICATION_ELAPSED_LIMIT) { + return; + } + + if (!(new CiDetector())->isCiDetected()) { + return; + } + + $errorOutput->writeLineFormatted('This analysis took more than a minute and the result cache was not present.'); + $errorOutput->writeLineFormatted('Persisting PHPStan\'s result cache directory between CI runs will speed up subsequent analyses.'); + $errorOutput->writeLineFormatted('Learn how to set it up: https://phpstan.org/user-guide/result-cache'); + $errorOutput->writeLineFormatted(''); + } + private function createStreamOutput(): StreamOutput { $resource = fopen('php://memory', 'w', false); diff --git a/src/Command/AnalysisResult.php b/src/Command/AnalysisResult.php index bdcb5fd1961..3a100dbc4de 100644 --- a/src/Command/AnalysisResult.php +++ b/src/Command/AnalysisResult.php @@ -39,6 +39,7 @@ public function __construct( private bool $isResultCacheUsed, private array $changedProjectExtensionFilesOutsideOfAnalysedPaths, private array $processedFiles = [], + private bool $resultCacheExisted = true, ) { usort( @@ -142,6 +143,16 @@ public function isResultCacheUsed(): bool return $this->isResultCacheUsed; } + /** + * Whether the result cache file existed when PHPStan started. + * False means the cache was never created; a stale/invalid cache that + * triggered a full re-analysis still counts as existing. + */ + public function resultCacheExisted(): bool + { + return $this->resultCacheExisted; + } + /** * @return array */ @@ -177,6 +188,7 @@ public function withFileSpecificErrors(array $fileSpecificErrors): self $this->isResultCacheUsed, $this->changedProjectExtensionFilesOutsideOfAnalysedPaths, $this->processedFiles, + $this->resultCacheExisted, ); } diff --git a/tests/PHPStan/Command/ResultCacheCiNotificationTest.php b/tests/PHPStan/Command/ResultCacheCiNotificationTest.php new file mode 100644 index 00000000000..8ed073d3bc6 --- /dev/null +++ b/tests/PHPStan/Command/ResultCacheCiNotificationTest.php @@ -0,0 +1,140 @@ +originalGithubActions = getenv('GITHUB_ACTIONS'); + $this->workingDir = sys_get_temp_dir() . '/phpstan-result-cache-ci-' . uniqid(); + mkdir($this->workingDir); + mkdir($this->workingDir . '/src'); + mkdir($this->workingDir . '/tmp'); + FileWriter::write($this->workingDir . '/src/Foo.php', "workingDir . '/phpstan.neon', sprintf("parameters:\n\tlevel: 0\n\ttmpDir: %s\n", $this->workingDir . '/tmp')); + } + + #[Override] + protected function tearDown(): void + { + parent::tearDown(); + + if ($this->originalGithubActions === false) { + putenv('GITHUB_ACTIONS'); + } else { + putenv('GITHUB_ACTIONS=' . $this->originalGithubActions); + } + + self::deleteDirectory($this->workingDir); + } + + public function testNotifiesInCiOnSlowFullAnalysisWithoutResultCache(): void + { + putenv('GITHUB_ACTIONS=true'); + + $output = $this->runCommand(microtime(true) - 120); + $this->assertStringContainsString(self::MESSAGE, $output); + } + + public function testDoesNotNotifyWhenResultCacheExists(): void + { + putenv('GITHUB_ACTIONS=true'); + + // first run creates the result cache + $this->runCommand(microtime(true) - 120); + + // second run finds the cache present + $output = $this->runCommand(microtime(true) - 120); + $this->assertStringNotContainsString(self::MESSAGE, $output); + } + + public function testDoesNotNotifyWhenAnalysisIsFast(): void + { + putenv('GITHUB_ACTIONS=true'); + + $output = $this->runCommand(microtime(true)); + $this->assertStringNotContainsString(self::MESSAGE, $output); + } + + public function testDoesNotNotifyOutsideCi(): void + { + putenv('GITHUB_ACTIONS'); + + $output = $this->runCommand(microtime(true) - 120); + $this->assertStringNotContainsString(self::MESSAGE, $output); + } + + private function runCommand(float $analysisStartTime): string + { + $commandTester = new CommandTester(new AnalyseCommand([], $analysisStartTime)); + + $commandTester->execute([ + 'paths' => [$this->workingDir . DIRECTORY_SEPARATOR . 'src'], + '--configuration' => $this->workingDir . DIRECTORY_SEPARATOR . 'phpstan.neon', + '--debug' => true, + ], ['debug' => true]); + + return $commandTester->getDisplay(); + } + + private static function deleteDirectory(string $directory): void + { + if (!is_dir($directory)) { + return; + } + + $entries = scandir($directory); + if ($entries === false) { + throw new ShouldNotHappenException(); + } + + foreach ($entries as $entry) { + if ($entry === '.' || $entry === '..') { + continue; + } + + $path = $directory . DIRECTORY_SEPARATOR . $entry; + if (is_dir($path)) { + self::deleteDirectory($path); + } else { + unlink($path); + } + } + + rmdir($directory); + } + +} From b99f0fc32263c7dc55d5f220fe395f06a0be02e3 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Tue, 30 Jun 2026 05:37:02 +0000 Subject: [PATCH 2/4] Gate result cache CI notification behind a bleeding edge feature toggle Add the notifyAboutMissingResultCacheInCi feature toggle (off by default, on under bleedingEdge.neon) and only emit the missing-result-cache CI hint when it is enabled. Co-Authored-By: Claude Opus 4.8 --- conf/bleedingEdge.neon | 1 + conf/config.neon | 1 + conf/parametersSchema.neon | 1 + src/Command/AnalyseCommand.php | 13 +++++++++++-- .../Command/ResultCacheCiNotificationTest.php | 2 +- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/conf/bleedingEdge.neon b/conf/bleedingEdge.neon index 2ad962c8d32..55b3ab6cdcf 100644 --- a/conf/bleedingEdge.neon +++ b/conf/bleedingEdge.neon @@ -22,3 +22,4 @@ parameters: checkDynamicConstantNameValues: true unusedLabel: true newOnNonObject: true + notifyAboutMissingResultCacheInCi: true diff --git a/conf/config.neon b/conf/config.neon index 0af76250814..23e0b509385 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -49,6 +49,7 @@ parameters: checkDynamicConstantNameValues: false unusedLabel: false newOnNonObject: false + notifyAboutMissingResultCacheInCi: false fileExtensions: - php checkAdvancedIsset: false diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon index 7d1ed9047b5..13d08b5586f 100644 --- a/conf/parametersSchema.neon +++ b/conf/parametersSchema.neon @@ -51,6 +51,7 @@ parametersSchema: checkDynamicConstantNameValues: bool() unusedLabel: bool() newOnNonObject: bool() + notifyAboutMissingResultCacheInCi: bool() ]) fileExtensions: listOf(string()) checkAdvancedIsset: bool() diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 4a9a901259e..8f98cfd7c12 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -654,7 +654,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $this->reportMissingResultCacheInCi($errorOutput, $analysisResult, $onlyFiles); + $this->reportMissingResultCacheInCi( + $errorOutput, + $analysisResult, + $onlyFiles, + $container->getParameter('featureToggles')['notifyAboutMissingResultCacheInCi'], + ); $this->runDiagnoseExtensions($container, $inceptionResult->getErrorOutput(), $analysisResult->getProcessedFiles()); @@ -665,8 +670,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); } - private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResult $analysisResult, bool $onlyFiles): void + private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResult $analysisResult, bool $onlyFiles, bool $notifyAboutMissingResultCacheInCi): void { + if (!$notifyAboutMissingResultCacheInCi) { + return; + } + if ( $onlyFiles || $analysisResult->isResultCacheUsed() diff --git a/tests/PHPStan/Command/ResultCacheCiNotificationTest.php b/tests/PHPStan/Command/ResultCacheCiNotificationTest.php index 8ed073d3bc6..8a6a9eabbfb 100644 --- a/tests/PHPStan/Command/ResultCacheCiNotificationTest.php +++ b/tests/PHPStan/Command/ResultCacheCiNotificationTest.php @@ -44,7 +44,7 @@ protected function setUp(): void mkdir($this->workingDir . '/src'); mkdir($this->workingDir . '/tmp'); FileWriter::write($this->workingDir . '/src/Foo.php', "workingDir . '/phpstan.neon', sprintf("parameters:\n\tlevel: 0\n\ttmpDir: %s\n", $this->workingDir . '/tmp')); + FileWriter::write($this->workingDir . '/phpstan.neon', sprintf("includes:\n\t- %s\n\nparameters:\n\tlevel: 0\n\ttmpDir: %s\n", __DIR__ . '/../../../conf/bleedingEdge.neon', $this->workingDir . '/tmp')); } #[Override] From 6bc8bddc2309ecdf68e4ef16b4972b4c274c4b04 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Tue, 30 Jun 2026 07:56:34 +0000 Subject: [PATCH 3/4] Enable result cache CI notification for everyone and make the threshold configurable Drops the bleeding-edge-only feature toggle so the slow-full-analysis hint runs for all users, and replaces the hardcoded 60s constant with a resultCacheCiNotificationSeconds parameter. The message is reworded to be a clearer call to action about speeding up CI. Co-Authored-By: Claude Opus 4.8 --- conf/bleedingEdge.neon | 1 - conf/config.neon | 2 +- conf/parametersSchema.neon | 2 +- src/Command/AnalyseCommand.php | 17 +-- .../Command/ResultCacheCiNotificationTest.php | 140 ------------------ 5 files changed, 8 insertions(+), 154 deletions(-) delete mode 100644 tests/PHPStan/Command/ResultCacheCiNotificationTest.php diff --git a/conf/bleedingEdge.neon b/conf/bleedingEdge.neon index 55b3ab6cdcf..2ad962c8d32 100644 --- a/conf/bleedingEdge.neon +++ b/conf/bleedingEdge.neon @@ -22,4 +22,3 @@ parameters: checkDynamicConstantNameValues: true unusedLabel: true newOnNonObject: true - notifyAboutMissingResultCacheInCi: true diff --git a/conf/config.neon b/conf/config.neon index 23e0b509385..f28d2b30259 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -49,7 +49,6 @@ parameters: checkDynamicConstantNameValues: false unusedLabel: false newOnNonObject: false - notifyAboutMissingResultCacheInCi: false fileExtensions: - php checkAdvancedIsset: false @@ -168,6 +167,7 @@ parameters: resultCachePath: %tmpDir%/resultCache.php resultCacheSkipIfOlderThanDays: 7 resultCacheChecksProjectExtensionFilesDependencies: false + resultCacheCiNotificationSeconds: 60 dynamicConstantNames: - ICONV_IMPL - LIBXML_VERSION diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon index 13d08b5586f..3d7a21a858f 100644 --- a/conf/parametersSchema.neon +++ b/conf/parametersSchema.neon @@ -51,7 +51,6 @@ parametersSchema: checkDynamicConstantNameValues: bool() unusedLabel: bool() newOnNonObject: bool() - notifyAboutMissingResultCacheInCi: bool() ]) fileExtensions: listOf(string()) checkAdvancedIsset: bool() @@ -162,6 +161,7 @@ parametersSchema: resultCachePath: string() resultCacheSkipIfOlderThanDays: int() resultCacheChecksProjectExtensionFilesDependencies: bool() + resultCacheCiNotificationSeconds: int() dynamicConstantNames: arrayOf(string()) customRulesetUsed: schema(bool(), nullable()) rootDir: string() diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 8f98cfd7c12..bbb186465af 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -77,8 +77,6 @@ final class AnalyseCommand extends Command public const DEFAULT_LEVEL = CommandHelper::DEFAULT_LEVEL; - private const RESULT_CACHE_CI_NOTIFICATION_ELAPSED_LIMIT = 60.0; - /** * @param string[] $composerAutoloaderProjectPaths */ @@ -658,7 +656,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $errorOutput, $analysisResult, $onlyFiles, - $container->getParameter('featureToggles')['notifyAboutMissingResultCacheInCi'], + $container->getParameter('resultCacheCiNotificationSeconds'), ); $this->runDiagnoseExtensions($container, $inceptionResult->getErrorOutput(), $analysisResult->getProcessedFiles()); @@ -670,12 +668,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); } - private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResult $analysisResult, bool $onlyFiles, bool $notifyAboutMissingResultCacheInCi): void + private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResult $analysisResult, bool $onlyFiles, int $resultCacheCiNotificationSeconds): void { - if (!$notifyAboutMissingResultCacheInCi) { - return; - } - if ( $onlyFiles || $analysisResult->isResultCacheUsed() @@ -684,7 +678,7 @@ private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResul return; } - if (microtime(true) - $this->analysisStartTime < self::RESULT_CACHE_CI_NOTIFICATION_ELAPSED_LIMIT) { + if (microtime(true) - $this->analysisStartTime < $resultCacheCiNotificationSeconds) { return; } @@ -692,8 +686,9 @@ private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResul return; } - $errorOutput->writeLineFormatted('This analysis took more than a minute and the result cache was not present.'); - $errorOutput->writeLineFormatted('Persisting PHPStan\'s result cache directory between CI runs will speed up subsequent analyses.'); + $errorOutput->writeLineFormatted('Tip: This CI run analysed your whole project from scratch, which is why it was slow.'); + $errorOutput->writeLineFormatted('Persist PHPStan\'s result cache directory between CI runs to make your pipeline dramatically faster.'); + $errorOutput->writeLineFormatted('Only changed files and their dependencies are re-analysed, so most runs finish in a fraction of the time.'); $errorOutput->writeLineFormatted('Learn how to set it up: https://phpstan.org/user-guide/result-cache'); $errorOutput->writeLineFormatted(''); } diff --git a/tests/PHPStan/Command/ResultCacheCiNotificationTest.php b/tests/PHPStan/Command/ResultCacheCiNotificationTest.php deleted file mode 100644 index 8a6a9eabbfb..00000000000 --- a/tests/PHPStan/Command/ResultCacheCiNotificationTest.php +++ /dev/null @@ -1,140 +0,0 @@ -originalGithubActions = getenv('GITHUB_ACTIONS'); - $this->workingDir = sys_get_temp_dir() . '/phpstan-result-cache-ci-' . uniqid(); - mkdir($this->workingDir); - mkdir($this->workingDir . '/src'); - mkdir($this->workingDir . '/tmp'); - FileWriter::write($this->workingDir . '/src/Foo.php', "workingDir . '/phpstan.neon', sprintf("includes:\n\t- %s\n\nparameters:\n\tlevel: 0\n\ttmpDir: %s\n", __DIR__ . '/../../../conf/bleedingEdge.neon', $this->workingDir . '/tmp')); - } - - #[Override] - protected function tearDown(): void - { - parent::tearDown(); - - if ($this->originalGithubActions === false) { - putenv('GITHUB_ACTIONS'); - } else { - putenv('GITHUB_ACTIONS=' . $this->originalGithubActions); - } - - self::deleteDirectory($this->workingDir); - } - - public function testNotifiesInCiOnSlowFullAnalysisWithoutResultCache(): void - { - putenv('GITHUB_ACTIONS=true'); - - $output = $this->runCommand(microtime(true) - 120); - $this->assertStringContainsString(self::MESSAGE, $output); - } - - public function testDoesNotNotifyWhenResultCacheExists(): void - { - putenv('GITHUB_ACTIONS=true'); - - // first run creates the result cache - $this->runCommand(microtime(true) - 120); - - // second run finds the cache present - $output = $this->runCommand(microtime(true) - 120); - $this->assertStringNotContainsString(self::MESSAGE, $output); - } - - public function testDoesNotNotifyWhenAnalysisIsFast(): void - { - putenv('GITHUB_ACTIONS=true'); - - $output = $this->runCommand(microtime(true)); - $this->assertStringNotContainsString(self::MESSAGE, $output); - } - - public function testDoesNotNotifyOutsideCi(): void - { - putenv('GITHUB_ACTIONS'); - - $output = $this->runCommand(microtime(true) - 120); - $this->assertStringNotContainsString(self::MESSAGE, $output); - } - - private function runCommand(float $analysisStartTime): string - { - $commandTester = new CommandTester(new AnalyseCommand([], $analysisStartTime)); - - $commandTester->execute([ - 'paths' => [$this->workingDir . DIRECTORY_SEPARATOR . 'src'], - '--configuration' => $this->workingDir . DIRECTORY_SEPARATOR . 'phpstan.neon', - '--debug' => true, - ], ['debug' => true]); - - return $commandTester->getDisplay(); - } - - private static function deleteDirectory(string $directory): void - { - if (!is_dir($directory)) { - return; - } - - $entries = scandir($directory); - if ($entries === false) { - throw new ShouldNotHappenException(); - } - - foreach ($entries as $entry) { - if ($entry === '.' || $entry === '..') { - continue; - } - - $path = $directory . DIRECTORY_SEPARATOR . $entry; - if (is_dir($path)) { - self::deleteDirectory($path); - } else { - unlink($path); - } - } - - rmdir($directory); - } - -} From fdb299214762e3ce4802bd4e0c009c7bc9bd341a Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Tue, 30 Jun 2026 07:56:50 +0000 Subject: [PATCH 4/4] Cover result cache CI notification with an E2E test Adds an e2e/result-cache-ci-notification case driven from e2e-tests.yml: a fresh run emits the hint, the cached re-run does not. Replaces the removed CommandTester-based unit test. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/e2e-tests.yml | 14 ++++++++++++++ e2e/result-cache-ci-notification/phpstan.neon | 6 ++++++ e2e/result-cache-ci-notification/src/Foo.php | 13 +++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 e2e/result-cache-ci-notification/phpstan.neon create mode 100644 e2e/result-cache-ci-notification/src/Foo.php diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 208bb0e5069..36c45eb4705 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -352,6 +352,20 @@ jobs: composer install ../../bin/phpstan -vvv ../../bin/phpstan -vvv + - script: | + cd e2e/result-cache-ci-notification + # https://github.com/phpstan/phpstan/issues/14881 + # A slow full analysis in CI without a pre-existing result cache should hint + # the user to persist the result cache directory between runs. + ../../bin/phpstan clear-result-cache + OUTPUT=$(../../bin/phpstan analyse 2>&1) + echo "$OUTPUT" + ../bashunit -a contains 'Persist PHPStan' "$OUTPUT" + ../bashunit -a contains 'to make your pipeline dramatically faster' "$OUTPUT" + # The second run finds the cache present, so the hint is not shown again. + OUTPUT=$(../../bin/phpstan analyse 2>&1) + echo "$OUTPUT" + ../bashunit -a not_contains 'to make your pipeline dramatically faster' "$OUTPUT" - script: | cd e2e/bug-12606 export CONFIGTEST=test diff --git a/e2e/result-cache-ci-notification/phpstan.neon b/e2e/result-cache-ci-notification/phpstan.neon new file mode 100644 index 00000000000..101d854bece --- /dev/null +++ b/e2e/result-cache-ci-notification/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 0 + paths: + - src + # Notify already after 0 seconds so the slow-analysis condition is always met in the test. + resultCacheCiNotificationSeconds: 0 diff --git a/e2e/result-cache-ci-notification/src/Foo.php b/e2e/result-cache-ci-notification/src/Foo.php new file mode 100644 index 00000000000..fa70dd29416 --- /dev/null +++ b/e2e/result-cache-ci-notification/src/Foo.php @@ -0,0 +1,13 @@ +