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..572bd58a614 100644 --- a/src/Configuration/ConfigurationRuleFilter.php +++ b/src/Configuration/ConfigurationRuleFilter.php @@ -8,10 +8,12 @@ use Rector\Contract\Rector\RectorInterface; use Rector\ValueObject\Configuration; use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; +use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Rector\VersionBonding\ValueObject\ComposerBoundRuleConfiguration; /** * Modify available rector rules based on the configuration options + * @see \Rector\Tests\Configuration\ConfigurationRuleFilterTest */ final class ConfigurationRuleFilter { @@ -41,6 +43,10 @@ public function filter(array $rectors): array return $this->filterComposerBased($rectors); } + if ($this->configuration->isPhpOnly()) { + return $this->filterPhpOnly($rectors); + } + return $rectors; } @@ -86,6 +92,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