From 7b52bd307ff0a0f421fc39a77f66bbfe10d0a41a Mon Sep 17 00:00:00 2001 From: M-arcus <25648755+M-arcus@users.noreply.github.com> Date: Wed, 28 Oct 2026 09:24:39 +0100 Subject: [PATCH] Sort root files in withRootFiles() to keep cache hash stable --- src/Configuration/RectorConfigBuilder.php | 2 + .../RectorConfigBuilderRootFilesTest.php | 79 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/Configuration/RectorConfigBuilderRootFilesTest.php diff --git a/src/Configuration/RectorConfigBuilder.php b/src/Configuration/RectorConfigBuilder.php index 23199b2f1b0..2da7de4aaf6 100644 --- a/src/Configuration/RectorConfigBuilder.php +++ b/src/Configuration/RectorConfigBuilder.php @@ -405,6 +405,8 @@ public function withRootFiles(): self // this file cannot be interpreted as PHP file // https://www.jetbrains.com/help/phpstorm/ide-advanced-metadata.html#expected-arguments ->notName('.phpstorm.meta.php') + // the paths are part of the cache hash, so the filesystem order must not leak into it + ->sortByName() ; foreach ($rootPhpFilesFinder as $rootPhpFileFinder) { diff --git a/tests/Configuration/RectorConfigBuilderRootFilesTest.php b/tests/Configuration/RectorConfigBuilderRootFilesTest.php new file mode 100644 index 00000000000..8d147d5445f --- /dev/null +++ b/tests/Configuration/RectorConfigBuilderRootFilesTest.php @@ -0,0 +1,79 @@ +originalWorkingDirectory = $workingDirectory; + + $temporaryDirectory = realpath(sys_get_temp_dir()); + Assert::string($temporaryDirectory); + + $this->projectDirectory = $temporaryDirectory . '/' . uniqid('rector_root_files_'); + foreach (self::ROOT_FILE_NAMES as $rootFileName) { + FileSystem::write($this->projectDirectory . '/' . $rootFileName, 'projectDirectory); + } + + protected function tearDown(): void + { + chdir($this->originalWorkingDirectory); + + FileSystem::delete($this->projectDirectory); + } + + public function testRootFilesAreSortedByName(): void + { + $rectorConfigBuilder = RectorConfig::configure()->withRootFiles(); + + // the paths are part of the cache invalidation hash, so their order has to be stable across machines + $expectedPaths = [ + $this->projectDirectory . '/.php-cs-fixer.dist.php', + $this->projectDirectory . '/deploy.php', + $this->projectDirectory . '/ecs.php', + $this->projectDirectory . '/rector.php', + ]; + + $this->assertSame($expectedPaths, $this->resolvePaths($rectorConfigBuilder)); + } + + /** + * @return string[] + */ + private function resolvePaths(RectorConfigBuilder $rectorConfigBuilder): array + { + $pathsReflectionProperty = new ReflectionProperty(RectorConfigBuilder::class, 'paths'); + + /** @var string[] $paths */ + $paths = $pathsReflectionProperty->getValue($rectorConfigBuilder); + + return $paths; + } +}