Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gitlab to "setup-ci" command #5497

Merged
merged 3 commits into from
Jan 24, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,11 @@ public function refactor(Node $node): ?Node
return null;
}

private function inferParam(Class_ $class, int $parameterPosition, PhpDocTagNode | Attribute $dataProviderNode): Type
{
private function inferParam(
Class_ $class,
int $parameterPosition,
PhpDocTagNode | Attribute $dataProviderNode
): Type {
$dataProviderClassMethod = $this->resolveDataProviderClassMethod($class, $dataProviderNode);
if (! $dataProviderClassMethod instanceof ClassMethod) {
return new MixedType();
Expand Down
128 changes: 80 additions & 48 deletions src/Console/Command/SetupCICommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,16 @@
namespace Rector\Console\Command;

use Nette\Utils\FileSystem;
use Nette\Utils\Strings;
use OndraM\CiDetector\CiDetector;
use Rector\Git\RepositoryHelper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\Process;
use function sprintf;

final class SetupCICommand extends Command
{
/**
* @var string
* @see https://regex101.com/r/etcmog/2
*/
private const GITHUB_REPOSITORY_REGEX = '#github\.com[:\/](?<repository_name>.*?)\.git#';

public function __construct(
private readonly SymfonyStyle $symfonyStyle
) {
Expand All @@ -38,48 +31,51 @@ protected function execute(InputInterface $input, OutputInterface $output): int
{
// detect current CI
$ci = $this->resolveCurrentCI();
if ($ci === null) {
$this->symfonyStyle->error('No CI detected');
return self::FAILURE;
}

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_GITLAB) {
return $this->handleGitlabCi();
}

$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;
}
if ($ci === CiDetector::CI_GITHUB_ACTIONS) {
return $this->handleGithubActions();
}

$currentRepository = $this->resolveCurrentRepositoryName(getcwd());
if ($currentRepository === null) {
$this->symfonyStyle->error('Current repository name could not be resolved');
$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/'
);

return self::FAILURE;
$this->symfonyStyle->note($noteMessage);
return self::SUCCESS;
}

/**
* @return CiDetector::CI_*|null
*/
private function resolveCurrentCI(): ?string
{
if (file_exists(getcwd() . '/.github')) {
return CiDetector::CI_GITHUB_ACTIONS;
}

$workflowTemplate = FileSystem::read(__DIR__ . '/../../../templates/rector-github-action-check.yaml');
if (file_exists(getcwd() . '/.gitlab-ci.yml')) {
return CiDetector::CI_GITLAB;
}

return null;
}

private function addGithubActionsWorkflow(string $currentRepository, string $targetWorkflowFilePath): void
{
$workflowTemplate = FileSystem::read(__DIR__ . '/../../../templates/rector-github-action-check.yaml');
$workflowContents = strtr($workflowTemplate, [
'__CURRENT_REPOSITORY__' => $currentRepository,
]);

FileSystem::write($rectorWorkflowFilePath, $workflowContents);
FileSystem::write($targetWorkflowFilePath, $workflowContents);

$this->symfonyStyle->newLine();

$this->symfonyStyle->success('The ".github/workflows/rector.yaml" file was added');

$this->symfonyStyle->writeln('<comment>2 more steps to run Rector in CI:</comment>');
Expand All @@ -95,31 +91,67 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$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');

return Command::SUCCESS;
$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 CiDetector::CI_*|null
* @return self::SUCCESS
*/
private function resolveCurrentCI(): ?string
private function handleGitlabCi(): int
{
if (file_exists(getcwd() . '/.github')) {
return CiDetector::CI_GITHUB_ACTIONS;
// 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;
}
}

return null;
$this->addGitlabFile($ciRectorFilePath);
return self::SUCCESS;
}

private function resolveCurrentRepositoryName(string $currentDirectory): ?string
/**
* @return self::SUCCESS|self::FAILURE
*/
private function handleGithubActions(): int
{
// resolve current repository name
$process = new Process(['git', 'remote', 'get-url', 'origin'], $currentDirectory, null, null, null);
$process->run();
$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');

$output = $process->getOutput();
return self::FAILURE;
}

$match = Strings::match($output, self::GITHUB_REPOSITORY_REGEX);
return $match['repository_name'] ?? null;
$this->addGithubActionsWorkflow($currentRepository, $rectorWorkflowFilePath);
return self::SUCCESS;
}
}
29 changes: 29 additions & 0 deletions src/Git/RepositoryHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Rector\Git;

use Nette\Utils\Strings;
use Symfony\Component\Process\Process;

final class RepositoryHelper
{
/**
* @var string
* @see https://regex101.com/r/etcmog/2
*/
private const GITHUB_REPOSITORY_REGEX = '#github\.com[:\/](?<repository_name>.*?)\.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;
}
}
1 change: 1 addition & 0 deletions templates/rector-github-action-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions templates/rector-gitlab-check.yaml
Original file line number Diff line number Diff line change
@@ -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
Loading