diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index c735702..25024c1 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -36,6 +36,10 @@ jobs: name: 'Check Active Classes' run: vendor/bin/class-leak check bin src tests --ansi + - + name: 'Run "Compare Projects" command' + run: php bin/monitor compare-projects tests/project-fixture/first-project --merge-project tests/project-fixture/second-project --ansi + - name: 'Composer dependency Analyser' run: vendor/bin/composer-dependency-analyser @@ -48,7 +52,7 @@ jobs: # see https://github.com/shivammathur/setup-php - uses: shivammathur/setup-php@v2 with: - php-version: 8.2 + php-version: 8.3 coverage: none # composer install cache - https://github.com/ramsey/composer-install diff --git a/LICENSE b/LICENSE index bd1ea72..a8fc2ae 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The MIT License --------------- -Copyright (c) 2020 Tomas Votruba (https://tomasvotruba.com) +Copyright (c) 2025 Tomas Votruba (https://tomasvotruba.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -22,4 +22,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 85da66d..d040268 100644 --- a/README.md +++ b/README.md @@ -27,15 +27,14 @@ composer require rector/monitor --dev ### 1. Quality control for `composer.json` in multiple repositories ```bash -vendor/bin/monitor quality-control +vendor/bin/monitor analyze ``` ```bash -vendor/bin/monitor quality-control --clear-cache +vendor/bin/monitor analyze --clear-cache ``` -
### 2. See full Matrix of repositories's dependencies diff --git a/bin/monitor.php b/bin/monitor.php index dfe4e1e..65977be 100755 --- a/bin/monitor.php +++ b/bin/monitor.php @@ -4,8 +4,6 @@ use Rector\Monitor\DependencyInjection\ContainerFactory; use Symfony\Component\Console\Application; -use Symfony\Component\Console\Input\ArgvInput; -use Symfony\Component\Console\Output\ConsoleOutput; $scoperAutoloadFilepath = __DIR__ . '/../vendor/scoper-autoload.php'; if (file_exists($scoperAutoloadFilepath)) { @@ -33,6 +31,4 @@ $container = $containerFactory->create(); $application = $container->make(Application::class); - -$exitCode = $application->run(new ArgvInput(), new ConsoleOutput()); -exit($exitCode); +exit($application->run()); diff --git a/composer.json b/composer.json index 6aa992c..00147bc 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "bin/monitor" ], "require": { - "php": ">=8.2", + "php": ">=8.3", "composer/semver": "^3.4", "illuminate/container": "12.40.*", "nette/neon": "^3.4", diff --git a/monitor.php b/monitor.php index 815ff6c..11370d2 100644 --- a/monitor.php +++ b/monitor.php @@ -5,21 +5,25 @@ use Rector\Monitor\Config\MonitorConfig; return MonitorConfig::configure() - ->addRepositories(['git@bitbucket.org:arestravelinc/lib-client.git']) - ->addRepositoryBranch('git@bitbucket.org:arestravelinc/legacy-appserver-service.git', 'stage') - ->addRepositoryBranch('git@bitbucket.org:arestravelinc/be5.git', 'stage') - ->addRepositoryBranch('git@bitbucket.org:arestravelinc/ares-admin.git', 'stage') - ->addRepositoryBranch('git@bitbucket.org:arestravelinc/content-service.git', 'stage') - ->addRepositoryBranch('git@bitbucket.org:arestravelinc/payment-service.git', 'stage') + ->addRepositories([ + // rector repositories + 'https://github.com/rectorphp/rector-src', + 'https://github.com/rectorphp/rector-symfony', + 'https://github.com/rectorphp/rector-doctrine', + 'https://github.com/rectorphp/rector-phpunit', + 'https://github.com/rectorphp/rector-downgrade-php', + ]) + // ->addRepositoryBranch('...', 'stage') // composer rules - ->disallowPackages(['symfony/phpunit-bridge']) + // ->disallowPackages(['symfony/phpunit-bridge']) ->requirePackages([ 'phpstan/phpstan', 'phpecs/phpecs', 'rector/rector', 'phpstan/phpstan-deprecation-rules', 'phpstan/extension-installer', + 'symplify/phpstan-rules', ]) // version requirements diff --git a/phpstan.neon b/phpstan.neon index ad1dc96..6fde2e3 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,9 @@ +includes: + - vendor/symplify/phpstan-rules/config/code-complexity-rules.neon + - vendor/symplify/phpstan-rules/config/configurable-rules.neon + - vendor/symplify/phpstan-rules/config/naming-rules.neon + - vendor/symplify/phpstan-rules/config/static-rules.neon + parameters: level: 8 diff --git a/src/Command/AnalyzeCommand.php b/src/Analyze/Command/AnalyzeCommand.php similarity index 85% rename from src/Command/AnalyzeCommand.php rename to src/Analyze/Command/AnalyzeCommand.php index be2ee9b..edc119a 100644 --- a/src/Command/AnalyzeCommand.php +++ b/src/Analyze/Command/AnalyzeCommand.php @@ -2,17 +2,17 @@ declare(strict_types=1); -namespace Rector\Monitor\Command; - +namespace Rector\Monitor\Analyze\Command; + +use Rector\Monitor\Analyze\Contract\RuleProcessorInterface; +use Rector\Monitor\Analyze\Reporting\ErrorCollector; +use Rector\Monitor\Analyze\RuleProcessor\DisallowedPackagesRuleProcessor; +use Rector\Monitor\Analyze\RuleProcessor\MetafileProcessor\NoPHPStanBaselineMetafileProcessor; +use Rector\Monitor\Analyze\RuleProcessor\MissingPackagesRuleProcessor; +use Rector\Monitor\Analyze\RuleProcessor\TooLowPackagesRulesProcessor; +use Rector\Monitor\Config\ConfigInitializer; use Rector\Monitor\Config\MonitorConfigProvider; -use Rector\Monitor\Configuration\ConfigInitializer; -use Rector\Monitor\Contract\RuleProcessorInterface; use Rector\Monitor\Git\RepositoryMetafilesResolver; -use Rector\Monitor\Reporting\ErrorCollector; -use Rector\Monitor\RuleProcessor\DisallowedPackagesRuleProcessor; -use Rector\Monitor\RuleProcessor\MetafileProcessor\NoPHPStanBaselineMetafileProcessor; -use Rector\Monitor\RuleProcessor\MissingPackagesRuleProcessor; -use Rector\Monitor\RuleProcessor\TooLowPackagesRulesProcessor; use Rector\Monitor\ValueObject\RepositoryCollection; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -51,7 +51,7 @@ protected function configure(): void $this->setAliases(['analyse']); $this->setDescription( - 'Check repositoryCollection composer.json files, assess "require" section, root files, tooling setup and min PHP version with defined quality control rules' + 'Check repositories composer.json files, assess "require" section, root files, tooling setup and min PHP version with defined quality control rules' ); $this->addOption( @@ -117,7 +117,7 @@ private function printAnalysisSummary(RepositoryCollection $repositoryCollection $this->symfonyStyle->writeln(sprintf( ' Summary: %d %s analyzed, %d with issues', $repositoryCollection->count(), - $repositoryCollection->count() === 1 ? 'repository' : 'repositoryCollection', + $repositoryCollection->count() === 1 ? 'repository' : 'repositories', $erroredRepositoryCount )); diff --git a/src/Contract/RuleProcessorInterface.php b/src/Analyze/Contract/RuleProcessorInterface.php similarity index 76% rename from src/Contract/RuleProcessorInterface.php rename to src/Analyze/Contract/RuleProcessorInterface.php index 8d01c61..6c093b7 100644 --- a/src/Contract/RuleProcessorInterface.php +++ b/src/Analyze/Contract/RuleProcessorInterface.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Rector\Monitor\Contract; +namespace Rector\Monitor\Analyze\Contract; +use Rector\Monitor\Analyze\Reporting\ErrorCollector; use Rector\Monitor\Config\MonitorConfig; -use Rector\Monitor\Reporting\ErrorCollector; use Rector\Monitor\ValueObject\ComposerJson; interface RuleProcessorInterface diff --git a/src/Reporting/ErrorCollector.php b/src/Analyze/Reporting/ErrorCollector.php similarity index 91% rename from src/Reporting/ErrorCollector.php rename to src/Analyze/Reporting/ErrorCollector.php index 324c90e..bf0c512 100644 --- a/src/Reporting/ErrorCollector.php +++ b/src/Analyze/Reporting/ErrorCollector.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Monitor\Reporting; +namespace Rector\Monitor\Analyze\Reporting; final class ErrorCollector { diff --git a/src/RuleProcessor/DisallowedPackagesRuleProcessor.php b/src/Analyze/RuleProcessor/DisallowedPackagesRuleProcessor.php similarity index 85% rename from src/RuleProcessor/DisallowedPackagesRuleProcessor.php rename to src/Analyze/RuleProcessor/DisallowedPackagesRuleProcessor.php index f1bba29..1345cdd 100644 --- a/src/RuleProcessor/DisallowedPackagesRuleProcessor.php +++ b/src/Analyze/RuleProcessor/DisallowedPackagesRuleProcessor.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Rector\Monitor\RuleProcessor; +namespace Rector\Monitor\Analyze\RuleProcessor; +use Rector\Monitor\Analyze\Contract\RuleProcessorInterface; +use Rector\Monitor\Analyze\Reporting\ErrorCollector; use Rector\Monitor\Config\MonitorConfig; -use Rector\Monitor\Contract\RuleProcessorInterface; -use Rector\Monitor\Reporting\ErrorCollector; use Rector\Monitor\ValueObject\ComposerJson; final class DisallowedPackagesRuleProcessor implements RuleProcessorInterface diff --git a/src/RuleProcessor/MetafileProcessor/NoPHPStanBaselineMetafileProcessor.php b/src/Analyze/RuleProcessor/MetafileProcessor/NoPHPStanBaselineMetafileProcessor.php similarity index 87% rename from src/RuleProcessor/MetafileProcessor/NoPHPStanBaselineMetafileProcessor.php rename to src/Analyze/RuleProcessor/MetafileProcessor/NoPHPStanBaselineMetafileProcessor.php index 7a0c87f..0b604f3 100644 --- a/src/RuleProcessor/MetafileProcessor/NoPHPStanBaselineMetafileProcessor.php +++ b/src/Analyze/RuleProcessor/MetafileProcessor/NoPHPStanBaselineMetafileProcessor.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Rector\Monitor\RuleProcessor\MetafileProcessor; +namespace Rector\Monitor\Analyze\RuleProcessor\MetafileProcessor; +use Rector\Monitor\Analyze\Contract\RuleProcessorInterface; +use Rector\Monitor\Analyze\Reporting\ErrorCollector; use Rector\Monitor\Config\MonitorConfig; -use Rector\Monitor\Contract\RuleProcessorInterface; -use Rector\Monitor\Reporting\ErrorCollector; use Rector\Monitor\ValueObject\ComposerJson; final readonly class NoPHPStanBaselineMetafileProcessor implements RuleProcessorInterface diff --git a/src/RuleProcessor/MissingPackagesRuleProcessor.php b/src/Analyze/RuleProcessor/MissingPackagesRuleProcessor.php similarity index 85% rename from src/RuleProcessor/MissingPackagesRuleProcessor.php rename to src/Analyze/RuleProcessor/MissingPackagesRuleProcessor.php index db0e001..b458600 100644 --- a/src/RuleProcessor/MissingPackagesRuleProcessor.php +++ b/src/Analyze/RuleProcessor/MissingPackagesRuleProcessor.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Rector\Monitor\RuleProcessor; +namespace Rector\Monitor\Analyze\RuleProcessor; +use Rector\Monitor\Analyze\Contract\RuleProcessorInterface; +use Rector\Monitor\Analyze\Reporting\ErrorCollector; use Rector\Monitor\Config\MonitorConfig; -use Rector\Monitor\Contract\RuleProcessorInterface; -use Rector\Monitor\Reporting\ErrorCollector; use Rector\Monitor\ValueObject\ComposerJson; final class MissingPackagesRuleProcessor implements RuleProcessorInterface diff --git a/src/RuleProcessor/TooLowPackagesRulesProcessor.php b/src/Analyze/RuleProcessor/TooLowPackagesRulesProcessor.php similarity index 91% rename from src/RuleProcessor/TooLowPackagesRulesProcessor.php rename to src/Analyze/RuleProcessor/TooLowPackagesRulesProcessor.php index 5b4ce96..1b4900d 100644 --- a/src/RuleProcessor/TooLowPackagesRulesProcessor.php +++ b/src/Analyze/RuleProcessor/TooLowPackagesRulesProcessor.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Rector\Monitor\RuleProcessor; +namespace Rector\Monitor\Analyze\RuleProcessor; use Composer\Semver\Semver; +use Rector\Monitor\Analyze\Contract\RuleProcessorInterface; +use Rector\Monitor\Analyze\Reporting\ErrorCollector; use Rector\Monitor\Config\MonitorConfig; -use Rector\Monitor\Contract\RuleProcessorInterface; -use Rector\Monitor\Reporting\ErrorCollector; use Rector\Monitor\ValueObject\ComposerJson; /** diff --git a/src/Configuration/ConfigInitializer.php b/src/Config/ConfigInitializer.php similarity index 94% rename from src/Configuration/ConfigInitializer.php rename to src/Config/ConfigInitializer.php index f3361cf..726ff76 100644 --- a/src/Configuration/ConfigInitializer.php +++ b/src/Config/ConfigInitializer.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Rector\Monitor\Configuration; +namespace Rector\Monitor\Config; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Filesystem\Filesystem; -final class ConfigInitializer +final readonly class ConfigInitializer { public function __construct( private SymfonyStyle $symfonyStyle, diff --git a/src/Config/MonitorConfig.php b/src/Config/MonitorConfig.php index f5ecf21..9ca5260 100644 --- a/src/Config/MonitorConfig.php +++ b/src/Config/MonitorConfig.php @@ -53,8 +53,12 @@ public function addRepositories(array $repositories): self Assert::allString($repositories); foreach ($repositories as $repository) { + if (! str_ends_with($repository, '.git')) { + $repository .= '.git'; + } + MonitorAssert::assertRepositoryUrl($repository); - $repositories[] = $repository; + $this->repositories[] = $repository; } return $this; diff --git a/src/Console/Command/CleanListCommand.php b/src/Console/Command/CleanListCommand.php index 4801f1f..c61ec4e 100644 --- a/src/Console/Command/CleanListCommand.php +++ b/src/Console/Command/CleanListCommand.php @@ -4,6 +4,7 @@ namespace Rector\Monitor\Console\Command; +use Override; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\ListCommand; @@ -17,6 +18,7 @@ */ final class CleanListCommand extends ListCommand { + #[Override] protected function execute(InputInterface $input, OutputInterface $output): int { Assert::isInstanceOf($this->getApplication(), Application::class); diff --git a/src/Console/MonitorConsoleApplication.php b/src/Console/MonitorConsoleApplication.php index 65a83c7..727fa45 100644 --- a/src/Console/MonitorConsoleApplication.php +++ b/src/Console/MonitorConsoleApplication.php @@ -4,6 +4,7 @@ namespace Rector\Monitor\Console; +use Override; use Rector\Monitor\Console\Command\CleanListCommand; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\CompleteCommand; @@ -12,6 +13,7 @@ final class MonitorConsoleApplication extends Application { + #[Override] protected function getDefaultCommands(): array { return [ diff --git a/src/DependencyInjection/ContainerFactory.php b/src/DependencyInjection/ContainerFactory.php index 67eff0c..5ddc928 100644 --- a/src/DependencyInjection/ContainerFactory.php +++ b/src/DependencyInjection/ContainerFactory.php @@ -5,13 +5,14 @@ namespace Rector\Monitor\DependencyInjection; use Illuminate\Container\Container; +use Rector\Monitor\Analyze\Command\AnalyzeCommand; use Rector\Monitor\Console\MonitorConsoleApplication; +use Rector\Monitor\Macro\Command\CompareProjectsCommand; +use Rector\Monitor\Matrix\Command\MatrixCommand; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\Finder\Finder; -use Webmozart\Assert\Assert; final class ContainerFactory { @@ -26,7 +27,7 @@ public function create(): Container $container->singleton(Application::class, function (Container $container): MonitorConsoleApplication { $monitorConsoleApplication = new MonitorConsoleApplication('Rector Monitor'); - $commandClasses = $this->findCommandClasses(); + $commandClasses = [AnalyzeCommand::class, MatrixCommand::class, CompareProjectsCommand::class]; // register commands foreach ($commandClasses as $commandClass) { @@ -57,27 +58,4 @@ public function hideDefaultCommands(Application $application): void $application->get('help') ->setHidden(true); } - - /** - * @return string[] - */ - private function findCommandClasses(): array - { - $commandFinder = Finder::create() - ->files() - ->name('*Command.php') - ->in(__DIR__ . '/../Command'); - - $commandClasses = []; - foreach ($commandFinder as $commandFile) { - $commandClass = 'Rector\\Monitor\\Command\\' . $commandFile->getBasename('.php'); - - // make sure it exists - Assert::classExists($commandClass); - - $commandClasses[] = $commandClass; - } - - return $commandClasses; - } } diff --git a/src/Git/RepositoryMetafilesResolver.php b/src/Git/RepositoryMetafilesResolver.php index 6926a26..b5d8d85 100644 --- a/src/Git/RepositoryMetafilesResolver.php +++ b/src/Git/RepositoryMetafilesResolver.php @@ -25,7 +25,9 @@ public function __construct( public function decorateRepositories(RepositoryCollection $repositoryCollection, bool $clearCache = false): void { foreach ($repositoryCollection->all() as $repository) { - $repositoryCacheDirectory = getcwd() . '/monitor-cache/repository-' . md5($repository->getRepositoryUrl()); + $repositoryCacheDirectory = sys_get_temp_dir() . '/rector-monitor-cache/repository-' . md5( + $repository->getRepositoryUrl() + ); if (file_exists($repositoryCacheDirectory) && $this->hasDirectorySomeFiles($repositoryCacheDirectory)) { if ($clearCache) { diff --git a/src/Helper/SymfonyColumnStyler.php b/src/Helper/SymfonyColumnStyler.php index 436ff26..f529074 100644 --- a/src/Helper/SymfonyColumnStyler.php +++ b/src/Helper/SymfonyColumnStyler.php @@ -20,7 +20,7 @@ final class SymfonyColumnStyler public static function styleHighsAndLows(array $tableRow): array { // set highs and lows - $stringValues = array_filter($tableRow, 'is_string'); + $stringValues = array_filter($tableRow, is_string(...)); $stringValues = array_unique($stringValues); if (count($stringValues) < 2) { diff --git a/src/Macro/Command/CompareProjectsCommand.php b/src/Macro/Command/CompareProjectsCommand.php index fd70861..d6e69fd 100644 --- a/src/Macro/Command/CompareProjectsCommand.php +++ b/src/Macro/Command/CompareProjectsCommand.php @@ -5,10 +5,10 @@ namespace Rector\Monitor\Macro\Command; use Rector\Monitor\Macro\Comparator\ComposerAutoloadComparator; -use Rector\Monitor\Macro\Comparator\ConfigFilesComparator; use Rector\Monitor\Macro\Comparator\MutuallyMissingPackagesComparator; use Rector\Monitor\Macro\Comparator\PHPStanExtensionsComparator; use Rector\Monitor\Macro\Comparator\PHPStanPathsComparator; +use Rector\Monitor\Macro\Comparator\SymfonyConfigFilesComparator; use Rector\Monitor\Macro\Contract\ComparatorInterface; use Rector\Monitor\Macro\ValueObject\ProjectMetadata; use Symfony\Component\Console\Command\Command; @@ -29,7 +29,7 @@ public function __construct( private readonly SymfonyStyle $symfonyStyle, ComposerAutoloadComparator $composerComparator, MutuallyMissingPackagesComparator $mutuallyMissingPackagesComparator, - ConfigFilesComparator $configFilesComparator, + SymfonyConfigFilesComparator $configFilesComparator, PHPStanExtensionsComparator $phpStanExtensionsComparator, PHPStanPathsComparator $phpStanPathsComparator ) { @@ -66,9 +66,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->symfonyStyle->writeln('Both directories found. Comparing 2 projects'); - foreach ($this->comparators as $key => $comparator) { - $comparator->compare($key + 1, $monorepoProjectMetadata, $mergeProjectMetadata); - $this->symfonyStyle->newLine(); + foreach ($this->comparators as $comparator) { + $comparator->compare($monorepoProjectMetadata, $mergeProjectMetadata); } return self::SUCCESS; diff --git a/src/Macro/Comparator/ComposerAutoloadComparator.php b/src/Macro/Comparator/ComposerAutoloadComparator.php index 5ac1b6a..22618c1 100644 --- a/src/Macro/Comparator/ComposerAutoloadComparator.php +++ b/src/Macro/Comparator/ComposerAutoloadComparator.php @@ -15,7 +15,7 @@ /** * @var string[] */ - private const AUTOLOAD_KEYS = ['autoload', 'autoload-dev']; + private const array AUTOLOAD_KEYS = ['autoload', 'autoload-dev']; public function __construct( private SymfonyStyle $symfonyStyle @@ -23,11 +23,10 @@ public function __construct( } public function compare( - int $step, ProjectMetadata $monorepoProjectMetadata, ProjectMetadata $mergeProjectMetadata ): void { - $this->symfonyStyle->title(sprintf('%d) PSR-4 autoload differences', $step)); + $this->symfonyStyle->title('PSR-4 autoload differences'); $hasDifference = false; @@ -71,5 +70,7 @@ public function compare( if ($hasDifference === false) { $this->symfonyStyle->success('Autoloads are identical, nothing spotted'); } + + $this->symfonyStyle->newLine(); } } diff --git a/src/Macro/Comparator/MutuallyMissingPackagesComparator.php b/src/Macro/Comparator/MutuallyMissingPackagesComparator.php index f70a7d0..e4e9925 100644 --- a/src/Macro/Comparator/MutuallyMissingPackagesComparator.php +++ b/src/Macro/Comparator/MutuallyMissingPackagesComparator.php @@ -13,7 +13,7 @@ /** * @var string[] */ - private const REQUIRE_KEYS = ['require', 'require-dev']; + private const array REQUIRE_KEYS = ['require', 'require-dev']; public function __construct( private SymfonyStyle $symfonyStyle @@ -21,11 +21,10 @@ public function __construct( } public function compare( - int $step, ProjectMetadata $monorepoProjectMetadata, ProjectMetadata $mergeProjectMetadata ): void { - $this->symfonyStyle->title(sprintf('%d. Composer dependencies', $step)); + $this->symfonyStyle->title('Composer dependencies'); $hasDifference = false; @@ -65,5 +64,7 @@ public function compare( if ($hasDifference === false) { $this->symfonyStyle->success('Monorepo project has all required dependencies from the merge project'); } + + $this->symfonyStyle->newLine(); } } diff --git a/src/Macro/Comparator/PHPStanExtensionsComparator.php b/src/Macro/Comparator/PHPStanExtensionsComparator.php index ff8f09b..3723013 100644 --- a/src/Macro/Comparator/PHPStanExtensionsComparator.php +++ b/src/Macro/Comparator/PHPStanExtensionsComparator.php @@ -16,11 +16,15 @@ public function __construct( } public function compare( - int $step, ProjectMetadata $monorepoProjectMetadata, ProjectMetadata $mergeProjectMetadata ): void { - $this->symfonyStyle->title(sprintf('%d) PHPStan extensions differences', $step)); + if (! $monorepoProjectMetadata->hasPHPStanConfig() && ! $mergeProjectMetadata->hasPHPStanConfig()) { + // nothing to compare + return; + } + + $this->symfonyStyle->title('PHPStan extensions differences'); $monorepoPHPStanPackageNames = $monorepoProjectMetadata->getPackagesMatchingName('phpstan'); $mergePHPStanPackageNames = $mergeProjectMetadata->getPackagesMatchingName('phpstan'); diff --git a/src/Macro/Comparator/PHPStanPathsComparator.php b/src/Macro/Comparator/PHPStanPathsComparator.php index 1bf2229..b614dcf 100644 --- a/src/Macro/Comparator/PHPStanPathsComparator.php +++ b/src/Macro/Comparator/PHPStanPathsComparator.php @@ -16,11 +16,15 @@ public function __construct( } public function compare( - int $step, ProjectMetadata $monorepoProjectMetadata, ProjectMetadata $mergeProjectMetadata ): void { - $this->symfonyStyle->title(sprintf('%d) PHPStan paths differences', $step)); + if (! $monorepoProjectMetadata->hasPHPStanConfig() && ! $mergeProjectMetadata->hasPHPStanConfig()) { + // nothing to compare + return; + } + + $this->symfonyStyle->title('PHPStan paths differences'); $monorepoPHPStanConfig = $monorepoProjectMetadata->getPHPStanConfig(); $mergePHPStanConfig = $mergeProjectMetadata->getPHPStanConfig(); diff --git a/src/Macro/Comparator/ConfigFilesComparator.php b/src/Macro/Comparator/SymfonyConfigFilesComparator.php similarity index 88% rename from src/Macro/Comparator/ConfigFilesComparator.php rename to src/Macro/Comparator/SymfonyConfigFilesComparator.php index 33a2af9..396d381 100644 --- a/src/Macro/Comparator/ConfigFilesComparator.php +++ b/src/Macro/Comparator/SymfonyConfigFilesComparator.php @@ -8,7 +8,7 @@ use Rector\Monitor\Macro\ValueObject\ProjectMetadata; use Symfony\Component\Console\Style\SymfonyStyle; -final readonly class ConfigFilesComparator implements ComparatorInterface +final readonly class SymfonyConfigFilesComparator implements ComparatorInterface { public function __construct( private SymfonyStyle $symfonyStyle @@ -16,7 +16,6 @@ public function __construct( } public function compare( - int $step, ProjectMetadata $monorepoProjectMetadata, ProjectMetadata $mergeProjectMetadata ): void { @@ -24,7 +23,12 @@ public function compare( $monorepoConfigDirectory = $monorepoProjectMetadata->getConfigDirectory(); $mergeConfigDirectory = $mergeProjectMetadata->getConfigDirectory(); - $this->symfonyStyle->title(sprintf('%d. Comparing config directories', $step)); + if ($monorepoConfigDirectory === null && $mergeConfigDirectory === null) { + // both projects do not have config directories + return; + } + + $this->symfonyStyle->title('Comparing Symfony config directories'); if ($monorepoConfigDirectory !== $mergeConfigDirectory) { $this->symfonyStyle->warning('Projects have different /config directory location'); diff --git a/src/Macro/Contract/ComparatorInterface.php b/src/Macro/Contract/ComparatorInterface.php index f81a0e4..262ef5b 100644 --- a/src/Macro/Contract/ComparatorInterface.php +++ b/src/Macro/Contract/ComparatorInterface.php @@ -8,9 +8,5 @@ interface ComparatorInterface { - public function compare( - int $step, - ProjectMetadata $monorepoProjectMetadata, - ProjectMetadata $mergeProjectMetadata - ): void; + public function compare(ProjectMetadata $monorepoProjectMetadata, ProjectMetadata $mergeProjectMetadata): void; } diff --git a/src/Macro/DependencyInjection/ContainerFactory.php b/src/Macro/DependencyInjection/ContainerFactory.php index d892359..8419c42 100644 --- a/src/Macro/DependencyInjection/ContainerFactory.php +++ b/src/Macro/DependencyInjection/ContainerFactory.php @@ -34,11 +34,11 @@ static function (): SymfonyStyle { ); $container->singleton(Application::class, function (Container $container): Application { - /** @var CompareProjectsCommand $addTypesCommand */ - $addTypesCommand = $container->make(CompareProjectsCommand::class); + /** @var CompareProjectsCommand $compareProjectsCommand */ + $compareProjectsCommand = $container->make(CompareProjectsCommand::class); $application = new Application(); - $application->add($addTypesCommand); + $application->add($compareProjectsCommand); $this->hideDefaultCommands($application); diff --git a/src/Macro/ValueObject/ProjectMetadata.php b/src/Macro/ValueObject/ProjectMetadata.php index 3cfbcaa..75efcc7 100644 --- a/src/Macro/ValueObject/ProjectMetadata.php +++ b/src/Macro/ValueObject/ProjectMetadata.php @@ -8,7 +8,9 @@ use Nette\Utils\FileSystem; use Nette\Utils\Strings; use Rector\Monitor\Macro\Utils\JsonLoader; +use RuntimeException; use Symfony\Component\Finder\Finder; +use Throwable; use Webmozart\Assert\Assert; final readonly class ProjectMetadata @@ -85,13 +87,19 @@ public function getConfigFiles(): array ->sortByName(); $configFiles = []; - foreach ($configFilesFinder as $configFileInfo) { - $configFiles[] = $configFileInfo->getRelativePathname(); + foreach ($configFilesFinder as $configFileFinder) { + $configFiles[] = $configFileFinder->getRelativePathname(); } return $configFiles; } + public function hasPHPStanConfig(): bool + { + $phpstanConfigPath = $this->projectDirectory . '/phpstan.neon'; + return file_exists($phpstanConfigPath); + } + /** * @return mixed[]|null */ @@ -104,9 +112,9 @@ public function getPHPStanConfig(): ?array try { return Neon::decodeFile($phpstanConfigPath); - } catch (\Throwable $throwable) { + } catch (Throwable $throwable) { // give more context about the file path and its contents - throw new \RuntimeException(sprintf( + throw new RuntimeException(sprintf( 'Failed to decode NEON file "%s" with contents:%s%s %s', $phpstanConfigPath, PHP_EOL, diff --git a/src/Command/MatrixCommand.php b/src/Matrix/Command/MatrixCommand.php similarity index 96% rename from src/Command/MatrixCommand.php rename to src/Matrix/Command/MatrixCommand.php index 3ba01e8..c26ed2d 100644 --- a/src/Command/MatrixCommand.php +++ b/src/Matrix/Command/MatrixCommand.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace Rector\Monitor\Command; +namespace Rector\Monitor\Matrix\Command; use Nette\Utils\Strings; -use Rector\Monitor\Composer\PackageSorter; +use Rector\Monitor\Config\ConfigInitializer; use Rector\Monitor\Config\MonitorConfigProvider; -use Rector\Monitor\Configuration\ConfigInitializer; use Rector\Monitor\Git\RepositoryMetafilesResolver; use Rector\Monitor\Helper\SymfonyColumnStyler; +use Rector\Monitor\Matrix\Composer\PackageSorter; use Rector\Monitor\ValueObject\RepositoryCollection; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\TableStyle; @@ -20,10 +20,7 @@ final class MatrixCommand extends Command { - /** - * @var string - */ - private const MISSING_LABEL = '*MISSING*'; + private const string MISSING_LABEL = '*MISSING*'; public function __construct( private readonly SymfonyStyle $symfonyStyle, diff --git a/src/Composer/PackageSorter.php b/src/Matrix/Composer/PackageSorter.php similarity index 93% rename from src/Composer/PackageSorter.php rename to src/Matrix/Composer/PackageSorter.php index def4c5c..b967228 100644 --- a/src/Composer/PackageSorter.php +++ b/src/Matrix/Composer/PackageSorter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Monitor\Composer; +namespace Rector\Monitor\Matrix\Composer; final class PackageSorter { diff --git a/src/Validation/MonitorAssert.php b/src/Validation/MonitorAssert.php index c67103b..4e37034 100644 --- a/src/Validation/MonitorAssert.php +++ b/src/Validation/MonitorAssert.php @@ -24,7 +24,7 @@ public static function assertRepositoryUrl(string $repository): void { Assert::regex( $repository, - '#git@[\w.-]+:[\w.-]+/[\w.-]+\.git#', + '#^(git@[\w.-]+:[\w.-]+/[\w.-]+\.git|https://[\w.-]+/[\w.-]+/[\w.-]+\.git)$#', sprintf('"%s" is not a valid repository URL', $repository) ); } diff --git a/src/ValueObject/Repository.php b/src/ValueObject/Repository.php index a042421..f8b6b67 100644 --- a/src/ValueObject/Repository.php +++ b/src/ValueObject/Repository.php @@ -4,6 +4,7 @@ namespace Rector\Monitor\ValueObject; +use Rector\Monitor\Helper\JsonFileSystem; use Symfony\Component\Finder\SplFileInfo; use Webmozart\Assert\Assert; @@ -38,7 +39,7 @@ public function getClonableRepositoryUrl(): string return $this->repositoryUrl; } - $authJson = \Rector\Monitor\Helper\JsonFileSystem::readFilePath($bitbucketAuthJson); + $authJson = JsonFileSystem::readFilePath($bitbucketAuthJson); // access bitbucket-oauth, bitbucket.org, consumer-key $username = $authJson['bitbucket-oauth']['bitbucket.org']['consumer-key'] ?? null; diff --git a/tests/RuleProcessor/TooLowPackagesRulesProcessor/TooLowPackagesRulesProcessorTest.php b/tests/Analyze/RuleProcessor/TooLowPackagesRulesProcessor/TooLowPackagesRulesProcessorTest.php similarity index 81% rename from tests/RuleProcessor/TooLowPackagesRulesProcessor/TooLowPackagesRulesProcessorTest.php rename to tests/Analyze/RuleProcessor/TooLowPackagesRulesProcessor/TooLowPackagesRulesProcessorTest.php index 787c538..8963eeb 100644 --- a/tests/RuleProcessor/TooLowPackagesRulesProcessor/TooLowPackagesRulesProcessorTest.php +++ b/tests/Analyze/RuleProcessor/TooLowPackagesRulesProcessor/TooLowPackagesRulesProcessorTest.php @@ -2,11 +2,12 @@ declare(strict_types=1); -namespace Rector\Monitor\Tests\RuleProcessor\TooLowPackagesRulesProcessor; +namespace Rector\Monitor\Tests\Analyze\RuleProcessor\TooLowPackagesRulesProcessor; +use Override; +use Rector\Monitor\Analyze\Reporting\ErrorCollector; +use Rector\Monitor\Analyze\RuleProcessor\TooLowPackagesRulesProcessor; use Rector\Monitor\Config\MonitorConfig; -use Rector\Monitor\Reporting\ErrorCollector; -use Rector\Monitor\RuleProcessor\TooLowPackagesRulesProcessor; use Rector\Monitor\Tests\AbstractTestCase; use Rector\Monitor\ValueObject\ComposerJson; @@ -14,6 +15,7 @@ final class TooLowPackagesRulesProcessorTest extends AbstractTestCase { private TooLowPackagesRulesProcessor $tooLowPackagesRulesProcessor; + #[Override] protected function setUp(): void { parent::setUp(); diff --git a/tests/project-fixture/first-project/composer.json b/tests/project-fixture/first-project/composer.json new file mode 100644 index 0000000..58a1c5e --- /dev/null +++ b/tests/project-fixture/first-project/composer.json @@ -0,0 +1,7 @@ +{ + "require": { + "php": ">=8.2", + "symfony/console": "^6.4", + "symfony/filesystem": "^7.4" + } +} diff --git a/tests/project-fixture/second-project/composer.json b/tests/project-fixture/second-project/composer.json new file mode 100644 index 0000000..e8459e4 --- /dev/null +++ b/tests/project-fixture/second-project/composer.json @@ -0,0 +1,6 @@ +{ + "require": { + "php": ">=8.0", + "symfony/http-kernel": "^8.0" + } +}