diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index 7e7991eab12..99fd7d063be 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -19,12 +19,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = '7584d25d55cd0a2e7c11dbc865c93a029c6047c3'; + public const PACKAGE_VERSION = '955a5de414501f77b80b321a90ee35d4fe49e9e2'; /** * @api * @var string */ - public const RELEASE_DATE = '2024-01-24 19:44:16'; + public const RELEASE_DATE = '2024-01-24 21:24:18'; /** * @var int */ diff --git a/src/Console/Command/SetupCICommand.php b/src/Console/Command/SetupCICommand.php index 2c41e09592a..b609c3e12b3 100644 --- a/src/Console/Command/SetupCICommand.php +++ b/src/Console/Command/SetupCICommand.php @@ -4,13 +4,12 @@ declare (strict_types=1); namespace Rector\Console\Command; use RectorPrefix202401\Nette\Utils\FileSystem; -use RectorPrefix202401\Nette\Utils\Strings; use RectorPrefix202401\OndraM\CiDetector\CiDetector; +use Rector\Git\RepositoryHelper; use RectorPrefix202401\Symfony\Component\Console\Command\Command; use RectorPrefix202401\Symfony\Component\Console\Input\InputInterface; use RectorPrefix202401\Symfony\Component\Console\Output\OutputInterface; use RectorPrefix202401\Symfony\Component\Console\Style\SymfonyStyle; -use RectorPrefix202401\Symfony\Component\Process\Process; use function sprintf; final class SetupCICommand extends Command { @@ -19,11 +18,6 @@ final class SetupCICommand extends Command * @var \Symfony\Component\Console\Style\SymfonyStyle */ private $symfonyStyle; - /** - * @var string - * @see https://regex101.com/r/etcmog/2 - */ - private const GITHUB_REPOSITORY_REGEX = '#github\\.com[:\\/](?.*?)\\.git#'; public function __construct(SymfonyStyle $symfonyStyle) { $this->symfonyStyle = $symfonyStyle; @@ -38,40 +32,15 @@ final class SetupCICommand extends Command { // detect current CI $ci = $this->resolveCurrentCI(); - if ($ci === null) { - $this->symfonyStyle->error('No CI detected'); - return self::FAILURE; + if ($ci === CiDetector::CI_GITLAB) { + return $this->handleGitlabCi(); } - if ($ci !== CiDetector::CI_GITHUB_ACTIONS) { - $noteMessage = sprintf('Only Github Action is supported for now.%sCreate an issue to add your CI %s', \PHP_EOL, 'https://github.com/rectorphp/rector/issues/'); - $this->symfonyStyle->note($noteMessage); - return self::SUCCESS; + if ($ci === CiDetector::CI_GITHUB_ACTIONS) { + return $this->handleGithubActions(); } - $rectorWorkflowFilePath = \getcwd() . '/.github/workflows/rector.yaml'; - if (\file_exists($rectorWorkflowFilePath)) { - $response = $this->symfonyStyle->ask('The "rector.yaml" workflow already exists. Overwrite it?', 'Yes'); - if (!\in_array($response, ['y', 'yes', 'Yes'], \true)) { - $this->symfonyStyle->note('Nothing changed'); - return self::SUCCESS; - } - } - $currentRepository = $this->resolveCurrentRepositoryName(\getcwd()); - if ($currentRepository === null) { - $this->symfonyStyle->error('Current repository name could not be resolved'); - return self::FAILURE; - } - $workflowTemplate = FileSystem::read(__DIR__ . '/../../../templates/rector-github-action-check.yaml'); - $workflowContents = \strtr($workflowTemplate, ['__CURRENT_REPOSITORY__' => $currentRepository]); - FileSystem::write($rectorWorkflowFilePath, $workflowContents); - $this->symfonyStyle->newLine(); - $this->symfonyStyle->success('The ".github/workflows/rector.yaml" file was added'); - $this->symfonyStyle->writeln('2 more steps to run Rector in CI:'); - $this->symfonyStyle->newLine(); - $this->symfonyStyle->writeln('1) Generate token with "repo" scope:' . \PHP_EOL . 'https://github.com/settings/tokens/new'); - $this->symfonyStyle->newLine(); - $repositoryNewSecretsLink = sprintf('https://github.com/%s/settings/secrets/actions/new', $currentRepository); - $this->symfonyStyle->writeln('2) Add the token to Action secrets as "ACCESS_TOKEN":' . \PHP_EOL . $repositoryNewSecretsLink); - return Command::SUCCESS; + $noteMessage = sprintf('Only Github and GitLab are currently supported.%s Contribute your CI template to Rector to make this work: %s', \PHP_EOL, 'https://github.com/rectorphp/rector-src/'); + $this->symfonyStyle->note($noteMessage); + return self::SUCCESS; } /** * @return CiDetector::CI_*|null @@ -81,15 +50,70 @@ final class SetupCICommand extends Command if (\file_exists(\getcwd() . '/.github')) { return CiDetector::CI_GITHUB_ACTIONS; } + if (\file_exists(\getcwd() . '/.gitlab-ci.yml')) { + return CiDetector::CI_GITLAB; + } return null; } - private function resolveCurrentRepositoryName(string $currentDirectory) : ?string + private function addGithubActionsWorkflow(string $currentRepository, string $targetWorkflowFilePath) : void { - // resolve current repository name - $process = new Process(['git', 'remote', 'get-url', 'origin'], $currentDirectory, null, null, null); - $process->run(); - $output = $process->getOutput(); - $match = Strings::match($output, self::GITHUB_REPOSITORY_REGEX); - return $match['repository_name'] ?? null; + $workflowTemplate = FileSystem::read(__DIR__ . '/../../../templates/rector-github-action-check.yaml'); + $workflowContents = \strtr($workflowTemplate, ['__CURRENT_REPOSITORY__' => $currentRepository]); + FileSystem::write($targetWorkflowFilePath, $workflowContents); + $this->symfonyStyle->newLine(); + $this->symfonyStyle->success('The ".github/workflows/rector.yaml" file was added'); + $this->symfonyStyle->writeln('2 more steps to run Rector in CI:'); + $this->symfonyStyle->newLine(); + $this->symfonyStyle->writeln('1) Generate token with "repo" scope:' . \PHP_EOL . 'https://github.com/settings/tokens/new'); + $this->symfonyStyle->newLine(); + $repositoryNewSecretsLink = sprintf('https://github.com/%s/settings/secrets/actions/new', $currentRepository); + $this->symfonyStyle->writeln('2) Add the token to Action secrets as "ACCESS_TOKEN":' . \PHP_EOL . $repositoryNewSecretsLink); + } + private function addGitlabFile(string $targetGitlabFilePath) : void + { + $gitlabTemplate = FileSystem::read(__DIR__ . '/../../../templates/rector-gitlab-check.yaml'); + FileSystem::write($targetGitlabFilePath, $gitlabTemplate); + $this->symfonyStyle->newLine(); + $this->symfonyStyle->success('The "gitlab/rector.yaml" file was added'); + $this->symfonyStyle->newLine(); + $this->symfonyStyle->writeln('1) Register it in your ".gitlab-ci.yml" file:' . \PHP_EOL . 'include:' . \PHP_EOL . ' - local: gitlab/rector.yaml'); + } + /** + * @return self::SUCCESS + */ + private function handleGitlabCi() : int + { + // add snippet in the end of file or include it? + $ciRectorFilePath = \getcwd() . '/gitlab/rector.yaml'; + if (\file_exists($ciRectorFilePath)) { + $response = $this->symfonyStyle->ask('The "gitlab/rector.yaml" workflow already exists. Overwrite it?', 'Yes'); + if (!\in_array($response, ['y', 'yes', 'Yes'], \true)) { + $this->symfonyStyle->note('Nothing changed'); + return self::SUCCESS; + } + } + $this->addGitlabFile($ciRectorFilePath); + return self::SUCCESS; + } + /** + * @return self::SUCCESS|self::FAILURE + */ + private function handleGithubActions() : int + { + $rectorWorkflowFilePath = \getcwd() . '/.github/workflows/rector.yaml'; + if (\file_exists($rectorWorkflowFilePath)) { + $response = $this->symfonyStyle->ask('The "rector.yaml" workflow already exists. Overwrite it?', 'Yes'); + if (!\in_array($response, ['y', 'yes', 'Yes'], \true)) { + $this->symfonyStyle->note('Nothing changed'); + return self::SUCCESS; + } + } + $currentRepository = RepositoryHelper::resolveGithubRepositoryName(\getcwd()); + if ($currentRepository === null) { + $this->symfonyStyle->error('Current repository name could not be resolved'); + return self::FAILURE; + } + $this->addGithubActionsWorkflow($currentRepository, $rectorWorkflowFilePath); + return self::SUCCESS; } } diff --git a/src/Git/RepositoryHelper.php b/src/Git/RepositoryHelper.php new file mode 100644 index 00000000000..9101688b458 --- /dev/null +++ b/src/Git/RepositoryHelper.php @@ -0,0 +1,24 @@ +.*?)\\.git#'; + public static function resolveGithubRepositoryName(string $currentDirectory) : ?string + { + // resolve current repository name + $process = new Process(['git', 'remote', 'get-url', 'origin'], $currentDirectory, null, null, null); + $process->run(); + $output = $process->getOutput(); + $match = Strings::match($output, self::GITHUB_REPOSITORY_REGEX); + return $match['repository_name'] ?? null; + } +} diff --git a/templates/rector-github-action-check.yaml b/templates/rector-github-action-check.yaml index 08fa6f7ea3a..4f2260f3be6 100644 --- a/templates/rector-github-action-check.yaml +++ b/templates/rector-github-action-check.yaml @@ -25,6 +25,7 @@ jobs: - uses: "ramsey/composer-install@v2" - run: vendor/bin/rector --ansi + # @todo apply coding standard if used - # commit only to core contributors who have repository access diff --git a/templates/rector-gitlab-check.yaml b/templates/rector-gitlab-check.yaml new file mode 100644 index 00000000000..36581f2a303 --- /dev/null +++ b/templates/rector-gitlab-check.yaml @@ -0,0 +1,27 @@ +stages: + - setup + - rector + - commit_changes + +setup: + stage: setup + # see https://github.com/thecodingmachine/docker-images-php + image: thecodingmachine/php:8.2-v4-slim-cli + +rector: + stage: rector + script: + - vendor/bin/rector --ansi + # @todo apply coding standard if used + +commit_changes: + stage: commit_changes + script: + - git config --global user.email "ci@gitlab.com" + - git config --global user.name "GitLab CI + # - git checkout $CI_COMMIT_REF_NAME + - git add . + - git commit -m "[rector] Rector fixes" + - git push origin $CI_COMMIT_REF_NAME + only: + - merge_requests diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index e460ae2dca9..f3d2a878a9c 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -1448,6 +1448,7 @@ return array( 'Rector\\FileSystem\\FilesystemTweaker' => $baseDir . '/src/FileSystem/FilesystemTweaker.php', 'Rector\\FileSystem\\InitFilePathsResolver' => $baseDir . '/src/FileSystem/InitFilePathsResolver.php', 'Rector\\FileSystem\\JsonFileSystem' => $baseDir . '/src/FileSystem/JsonFileSystem.php', + 'Rector\\Git\\RepositoryHelper' => $baseDir . '/src/Git/RepositoryHelper.php', 'Rector\\Instanceof_\\Rector\\Ternary\\FlipNegatedTernaryInstanceofRector' => $baseDir . '/rules/Instanceof_/Rector/Ternary/FlipNegatedTernaryInstanceofRector.php', 'Rector\\Naming\\AssignVariableNameResolver\\NewAssignVariableNameResolver' => $baseDir . '/rules/Naming/AssignVariableNameResolver/NewAssignVariableNameResolver.php', 'Rector\\Naming\\AssignVariableNameResolver\\PropertyFetchAssignVariableNameResolver' => $baseDir . '/rules/Naming/AssignVariableNameResolver/PropertyFetchAssignVariableNameResolver.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 5b63560e32b..eedbc3765df 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -1662,6 +1662,7 @@ class ComposerStaticInit0408599c96f445821212bfb9798860ca 'Rector\\FileSystem\\FilesystemTweaker' => __DIR__ . '/../..' . '/src/FileSystem/FilesystemTweaker.php', 'Rector\\FileSystem\\InitFilePathsResolver' => __DIR__ . '/../..' . '/src/FileSystem/InitFilePathsResolver.php', 'Rector\\FileSystem\\JsonFileSystem' => __DIR__ . '/../..' . '/src/FileSystem/JsonFileSystem.php', + 'Rector\\Git\\RepositoryHelper' => __DIR__ . '/../..' . '/src/Git/RepositoryHelper.php', 'Rector\\Instanceof_\\Rector\\Ternary\\FlipNegatedTernaryInstanceofRector' => __DIR__ . '/../..' . '/rules/Instanceof_/Rector/Ternary/FlipNegatedTernaryInstanceofRector.php', 'Rector\\Naming\\AssignVariableNameResolver\\NewAssignVariableNameResolver' => __DIR__ . '/../..' . '/rules/Naming/AssignVariableNameResolver/NewAssignVariableNameResolver.php', 'Rector\\Naming\\AssignVariableNameResolver\\PropertyFetchAssignVariableNameResolver' => __DIR__ . '/../..' . '/rules/Naming/AssignVariableNameResolver/PropertyFetchAssignVariableNameResolver.php',