From cfad16a877fa113e99cf53ddf984ec81d8024760 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 8 Aug 2026 14:54:44 +0200 Subject: [PATCH 1/2] feat: add --php option to process command Runs only rules bound to a minimal PHP version, i.e. rules implementing MinPhpVersionInterface. Useful to split a PHP version upgrade from the rest of the rules in a single config. --- src/Configuration/ConfigurationFactory.php | 8 +++ src/Configuration/ConfigurationRuleFilter.php | 23 ++++++++ src/Configuration/Option.php | 5 ++ src/Console/ProcessConfigureDecorator.php | 7 +++ src/ValueObject/Configuration.php | 6 ++ .../ConfigurationRuleFilterTest.php | 56 +++++++++++++++++++ .../Command/WorkerCommandLineFactoryTest.php | 10 ++++ 7 files changed, 115 insertions(+) create mode 100644 tests/Configuration/ConfigurationRuleFilterTest.php diff --git a/src/Configuration/ConfigurationFactory.php b/src/Configuration/ConfigurationFactory.php index 4cb759bdcea..4f81642eb0b 100644 --- a/src/Configuration/ConfigurationFactory.php +++ b/src/Configuration/ConfigurationFactory.php @@ -102,6 +102,13 @@ public function createFromInput(InputInterface $input): Configuration SimpleParameterProvider::setParameter(Option::IS_RUN_NARROWED, true); } + $isPhpOnly = (bool) $input->getOption(Option::PHP); + + // "--php" narrows the run the same way "--only" does + if ($isPhpOnly) { + SimpleParameterProvider::setParameter(Option::IS_RUN_NARROWED, true); + } + return new Configuration( $isDryRun, $showProgressBar, @@ -121,6 +128,7 @@ public function createFromInput(InputInterface $input): Configuration $levelOverflows, $showRulesSummary, $isComposerBased, + $isPhpOnly, ); } diff --git a/src/Configuration/ConfigurationRuleFilter.php b/src/Configuration/ConfigurationRuleFilter.php index 9ec95d6f671..8eacd1f3466 100644 --- a/src/Configuration/ConfigurationRuleFilter.php +++ b/src/Configuration/ConfigurationRuleFilter.php @@ -8,6 +8,7 @@ use Rector\Contract\Rector\RectorInterface; use Rector\ValueObject\Configuration; use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; +use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Rector\VersionBonding\ValueObject\ComposerBoundRuleConfiguration; /** @@ -41,6 +42,10 @@ public function filter(array $rectors): array return $this->filterComposerBased($rectors); } + if ($this->configuration->isPhpOnly()) { + return $this->filterPhpOnly($rectors); + } + return $rectors; } @@ -86,6 +91,24 @@ private function filterComposerBased(array $rectors): array return $activeRectors; } + /** + * Keeps rules bound to a minimal PHP version, e.g. PHP upgrade rules + * + * @param list $rectors + * @return list + */ + private function filterPhpOnly(array $rectors): array + { + $activeRectors = []; + foreach ($rectors as $rector) { + if ($rector instanceof MinPhpVersionInterface) { + $activeRectors[] = $rector; + } + } + + return $activeRectors; + } + /** * @return string[] */ diff --git a/src/Configuration/Option.php b/src/Configuration/Option.php index 2b4e1a3162c..7f22ca35e33 100644 --- a/src/Configuration/Option.php +++ b/src/Configuration/Option.php @@ -295,6 +295,11 @@ final class Option */ public const string COMPOSER_BASED = 'composer-based'; + /** + * Run only rules bound to a minimal PHP version + */ + public const string PHP = 'php'; + /** * @internal To filter files by specific suffix */ diff --git a/src/Console/ProcessConfigureDecorator.php b/src/Console/ProcessConfigureDecorator.php index 5e9095dae25..ce3673e499a 100644 --- a/src/Console/ProcessConfigureDecorator.php +++ b/src/Console/ProcessConfigureDecorator.php @@ -66,6 +66,13 @@ public static function decorate(Command $command): void 'Run only rules bound to an installed composer package version' ); + $command->addOption( + Option::PHP, + null, + InputOption::VALUE_NONE, + 'Run only PHP rules, e.g. rules bound to a minimal PHP version' + ); + $command->addOption( Option::ONLY_SUFFIX, null, diff --git a/src/ValueObject/Configuration.php b/src/ValueObject/Configuration.php index 2c546343a4b..19c22edc5b6 100644 --- a/src/ValueObject/Configuration.php +++ b/src/ValueObject/Configuration.php @@ -36,6 +36,7 @@ public function __construct( private array $levelOverflows = [], private bool $showRulesSummary = false, private bool $isComposerBased = false, + private bool $isPhpOnly = false, ) { } @@ -44,6 +45,11 @@ public function isComposerBased(): bool return $this->isComposerBased; } + public function isPhpOnly(): bool + { + return $this->isPhpOnly; + } + public function isDryRun(): bool { return $this->isDryRun; diff --git a/tests/Configuration/ConfigurationRuleFilterTest.php b/tests/Configuration/ConfigurationRuleFilterTest.php new file mode 100644 index 00000000000..32d7839a680 --- /dev/null +++ b/tests/Configuration/ConfigurationRuleFilterTest.php @@ -0,0 +1,56 @@ +configurationRuleFilter = $this->make(ConfigurationRuleFilter::class); + } + + public function testPhpOnlyKeepsMinPhpVersionRules(): void + { + $stringableForToStringRector = $this->make(StringableForToStringRector::class); + $removeDeadInstanceOfRector = $this->make(RemoveDeadInstanceOfRector::class); + + $this->configurationRuleFilter->setConfiguration($this->createConfiguration(true)); + + $filteredRectors = $this->configurationRuleFilter->filter( + [$stringableForToStringRector, $removeDeadInstanceOfRector] + ); + + $this->assertSame([$stringableForToStringRector], $filteredRectors); + } + + public function testWithoutPhpOnlyKeepsAllRules(): void + { + $stringableForToStringRector = $this->make(StringableForToStringRector::class); + $removeDeadInstanceOfRector = $this->make(RemoveDeadInstanceOfRector::class); + + $this->configurationRuleFilter->setConfiguration($this->createConfiguration(false)); + + $filteredRectors = $this->configurationRuleFilter->filter( + [$stringableForToStringRector, $removeDeadInstanceOfRector] + ); + + $this->assertSame([$stringableForToStringRector, $removeDeadInstanceOfRector], $filteredRectors); + } + + private function createConfiguration(bool $isPhpOnly): Configuration + { + return new Configuration(isPhpOnly: $isPhpOnly); + } +} diff --git a/tests/Parallel/Command/WorkerCommandLineFactoryTest.php b/tests/Parallel/Command/WorkerCommandLineFactoryTest.php index f33fb9bb19d..3f12115eedd 100644 --- a/tests/Parallel/Command/WorkerCommandLineFactoryTest.php +++ b/tests/Parallel/Command/WorkerCommandLineFactoryTest.php @@ -185,6 +185,16 @@ public static function provideData(): Iterator ], "'" . PHP_BINARY . "' '" . self::DUMMY_MAIN_SCRIPT . "' '" . $cliInputOptionsAsString . "' worker --memory-limit='-1' --port 2000 --identifier 'identifier' 'src' --output-format 'json' --no-ansi", ]; + + yield [ + [ + self::COMMAND => 'process', + Option::SOURCE => ['src'], + '--' . Option::OUTPUT_FORMAT => ConsoleOutputFormatter::NAME, + '--' . Option::PHP => true, + ], + "'" . PHP_BINARY . "' '" . self::DUMMY_MAIN_SCRIPT . "' '" . $cliInputOptionsAsString . "' worker --php --port 2000 --identifier 'identifier' 'src' --output-format 'json' --no-ansi", + ]; } private function cleanUpEmptyQuoteExpectedCommandOutput(string $result): string From 58f0dd734b51833ea2d67a7887b5339f8ffffe3a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 8 Aug 2026 12:56:33 +0000 Subject: [PATCH 2/2] [ci-review] Rector Rectify --- src/Configuration/ConfigurationRuleFilter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Configuration/ConfigurationRuleFilter.php b/src/Configuration/ConfigurationRuleFilter.php index 8eacd1f3466..572bd58a614 100644 --- a/src/Configuration/ConfigurationRuleFilter.php +++ b/src/Configuration/ConfigurationRuleFilter.php @@ -13,6 +13,7 @@ /** * Modify available rector rules based on the configuration options + * @see \Rector\Tests\Configuration\ConfigurationRuleFilterTest */ final class ConfigurationRuleFilter {