Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
- 'e2e/applied-rule-change-docblock'
- 'e2e/applied-rule-removed-node'
- 'e2e/applied-rule-return-array-nodes'
- 'e2e/config-dist-fallback'
- 'e2e/config-file-priority'
- 'e2e/different-path-over-skip-config'
- 'e2e/invalid-paths'
- 'e2e/no-parallel-reflection-resolver'
Expand Down
1 change: 1 addition & 0 deletions e2e/config-dist-fallback/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor
7 changes: 7 additions & 0 deletions e2e/config-dist-fallback/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"require": {
"php": "^8.1"
},
"minimum-stability": "dev",
"prefer-stable": true
}
22 changes: 22 additions & 0 deletions e2e/config-dist-fallback/expected-output.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
1 file with changes
===================

1) src/SomeClass.php:4

---------- begin diff ----------
@@ @@

final class SomeClass
{
- /**
- * @var string
- */
public string $name = 'name';
}
----------- end diff -----------

Applied rules:
* RemoveUselessVarTagRector


[OK] 1 file would have been changed (dry-run) by Rector
15 changes: 15 additions & 0 deletions e2e/config-dist-fallback/rector.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\DeadCode\Rector\Property\RemoveUselessVarTagRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/src',
]);

// This rule should be applied when rector.dist.php is used as fallback
$rectorConfig->rule(RemoveUselessVarTagRector::class);
};
11 changes: 11 additions & 0 deletions e2e/config-dist-fallback/src/SomeClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

final class SomeClass
{
/**
* @var string
*/
public string $name = 'name';
}
1 change: 1 addition & 0 deletions e2e/config-file-priority/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor
7 changes: 7 additions & 0 deletions e2e/config-file-priority/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"require": {
"php": "^8.1"
},
"minimum-stability": "dev",
"prefer-stable": true
}
22 changes: 22 additions & 0 deletions e2e/config-file-priority/expected-output.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
1 file with changes
===================

1) src/SomeClass.php:4

---------- begin diff ----------
@@ @@

final class SomeClass
{
- /**
- * @var string
- */
public string $name = 'name';
}
----------- end diff -----------

Applied rules:
* RemoveUselessVarTagRector


[OK] 1 file would have been changed (dry-run) by Rector
15 changes: 15 additions & 0 deletions e2e/config-file-priority/rector.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/src',
]);

// This rule should NOT be applied because rector.php takes priority
$rectorConfig->rule(ClosureToArrowFunctionRector::class);
};
15 changes: 15 additions & 0 deletions e2e/config-file-priority/rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\DeadCode\Rector\Property\RemoveUselessVarTagRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/src',
]);

// This rule should be applied when rector.php is used
$rectorConfig->rule(RemoveUselessVarTagRector::class);
};
11 changes: 11 additions & 0 deletions e2e/config-file-priority/src/SomeClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

final class SomeClass
{
/**
* @var string
*/
public string $name = 'name';
}
16 changes: 13 additions & 3 deletions src/Bootstrap/RectorConfigsResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@

final class RectorConfigsResolver
{
public const string DEFAULT_CONFIG_FILE = 'rector.php';

public const string DEFAULT_DIST_CONFIG_FILE = 'rector.dist.php';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is common fallback file has .php.dist instead of .dist.php?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the .dist.php format because IDEs will automatically recognise them as PHP files. Some tools like phpunit only support the xml.dist format. Others like phpstan support both. PHP-CS-Fixer supports .dist.php. So it seems that there is not a full consensus on this.
I can change this (or support both options) if needed, please let me know

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, I will let @TomasVotruba decide on this :)


public function provide(): BootstrapConfigs
{
$argvInput = new ArgvInput();
$mainConfigFile = $this->resolveFromInputWithFallback($argvInput, 'rector.php');
$mainConfigFile = $this->resolveFromInputWithFallback($argvInput);

return new BootstrapConfigs($mainConfigFile, []);
}
Expand All @@ -30,14 +34,20 @@ private function resolveFromInput(ArgvInput $argvInput): ?string
return realpath($configFile);
}

private function resolveFromInputWithFallback(ArgvInput $argvInput, string $fallbackFile): ?string
private function resolveFromInputWithFallback(ArgvInput $argvInput): ?string
{
$configFile = $this->resolveFromInput($argvInput);
if ($configFile !== null) {
return $configFile;
}

return $this->createFallbackFileInfoIfFound($fallbackFile);
// Try rector.php first, then fall back to rector.dist.php
$rectorConfigFile = $this->createFallbackFileInfoIfFound(self::DEFAULT_CONFIG_FILE);
if ($rectorConfigFile !== null) {
return $rectorConfigFile;
}

return $this->createFallbackFileInfoIfFound(self::DEFAULT_DIST_CONFIG_FILE);
}

private function createFallbackFileInfoIfFound(string $fallbackFile): ?string
Expand Down
20 changes: 17 additions & 3 deletions src/Configuration/ConfigInitializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Rector\Configuration;

use Nette\Utils\FileSystem;
use Rector\Bootstrap\RectorConfigsResolver;
use Rector\Contract\Rector\RectorInterface;
use Rector\FileSystem\InitFilePathsResolver;
use Rector\PostRector\Contract\Rector\PostRectorInterface;
Expand All @@ -24,14 +25,27 @@ public function __construct(

public function createConfig(string $projectDirectory): void
{
$commonRectorConfigPath = $projectDirectory . '/rector.php';
$commonRectorConfigPath = $projectDirectory . '/' . RectorConfigsResolver::DEFAULT_CONFIG_FILE;
$distRectorConfigPath = $projectDirectory . '/' . RectorConfigsResolver::DEFAULT_DIST_CONFIG_FILE;

if (file_exists($commonRectorConfigPath)) {
$this->symfonyStyle->warning('Register rules or sets in your "rector.php" config');
$this->symfonyStyle->warning(
'Register rules or sets in your "' . RectorConfigsResolver::DEFAULT_CONFIG_FILE . '" config'
);
return;
}

$response = $this->symfonyStyle->ask('No "rector.php" config found. Should we generate it for you?', 'yes');
if (file_exists($distRectorConfigPath)) {
$this->symfonyStyle->warning(
'Register rules or sets in your "' . RectorConfigsResolver::DEFAULT_DIST_CONFIG_FILE . '" config'
);
return;
}

$response = $this->symfonyStyle->ask(
'No "' . RectorConfigsResolver::DEFAULT_CONFIG_FILE . '" config found. Should we generate it for you?',
'yes'
);
// be tolerant about input
if (! in_array($response, ['yes', 'YES', 'y', 'Y'], true)) {
// okay, nothing we can do
Expand Down
8 changes: 1 addition & 7 deletions src/Console/ConsoleApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ private function addCustomOptions(InputDefinition $inputDefinition): void
Option::CONFIG,
'c',
InputOption::VALUE_REQUIRED,
'Path to config file',
$this->getDefaultConfigPath()
'Path to config file'
));

$inputDefinition->addOption(new InputOption(
Expand All @@ -146,11 +145,6 @@ private function addCustomOptions(InputDefinition $inputDefinition): void
));
}

private function getDefaultConfigPath(): string
{
return getcwd() . '/rector.php';
}

private function enableXdebug(InputInterface $input): void
{
$isXdebugAllowed = $input->hasParameterOption('--xdebug');
Expand Down
49 changes: 27 additions & 22 deletions src/Parallel/Command/WorkerCommandLineFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,27 +95,32 @@ public function create(
// @see https://github.com/symfony/symfony/issues/1238
$workerCommandArray[] = '--no-ansi';

// Only pass --config if explicitly set via command line
// If not set, the worker will resolve config using RectorConfigsResolver fallback mechanism
if ($input->hasOption(Option::CONFIG)) {
$workerCommandArray[] = '--config';
/**
* On parallel, the command is generated with `--config` addition
* Using escapeshellarg() to ensure the --config path escaped, even when it has a space.
*
* eg:
* --config /path/e2e/parallel with space/rector.php
*
* that can cause error:
*
* File /rector-src/e2e/parallel\" was not found
*
* the escaped result is:
*
* --config '/path/e2e/parallel with space/rector.php'
*
* tested in macOS and Ubuntu (github action)
*/
$config = (string) $input->getOption(Option::CONFIG);
$workerCommandArray[] = escapeshellarg($this->filePathHelper->relativePath($config));
$configValue = $input->getOption(Option::CONFIG);
if (is_string($configValue) && $configValue !== '') {
$workerCommandArray[] = '--config';
/**
* On parallel, the command is generated with `--config` addition
* Using escapeshellarg() to ensure the --config path escaped, even when it has a space.
*
* eg:
* --config /path/e2e/parallel with space/rector.php
*
* that can cause error:
*
* File /rector-src/e2e/parallel\" was not found
*
* the escaped result is:
*
* --config '/path/e2e/parallel with space/rector.php'
*
* tested in macOS and Ubuntu (github action)
*/
$config = $configValue;
$workerCommandArray[] = escapeshellarg($this->filePathHelper->relativePath($config));
}
}

if ($input->getOption(Option::ONLY) !== null) {
Expand All @@ -132,8 +137,8 @@ private function shouldSkipOption(InputInterface $input, string $optionName): bo
return true;
}

// skip output format, not relevant in parallel worker command
return $optionName === Option::OUTPUT_FORMAT;
// skip output format and config, handled separately in create()
return $optionName === Option::OUTPUT_FORMAT || $optionName === Option::CONFIG;
}

/**
Expand Down