From 51262f21b07b12e2748643236d130739a93ca75f Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 5 Dec 2025 23:45:33 +0100 Subject: [PATCH 1/3] fixup! tv bump 2 (#7) --- rector.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rector.php b/rector.php index 6b47995..deb230e 100644 --- a/rector.php +++ b/rector.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector; return RectorConfig::configure() ->withPaths([__DIR__ . '/bin', __DIR__ . '/src', __DIR__ . '/tests']) @@ -23,5 +24,6 @@ \Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector::class => [ __DIR__ . '/src/Composer/ComposerJsonResolver.php', ], + DeclareStrictTypesRector::class, ]) ->withImportNames(removeUnusedImports: true); From 902caaf6edac622f47c1c3a43f01ed09f0c43427 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 5 Dec 2025 23:48:55 +0100 Subject: [PATCH 2/3] misc --- .github/workflows/code_analysis.yaml | 8 +++ README.md | 52 +++++++++++---- monitor.php | 5 +- src/Config/MonitorConfig.php | 4 ++ src/Git/RepositoryMetafilesResolver.php | 88 ++++++++++++++----------- src/Matrix/Command/MatrixCommand.php | 15 +++-- 6 files changed, 113 insertions(+), 59 deletions(-) diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 25024c1..bdaefc8 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -40,6 +40,14 @@ jobs: 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: 'Run "Matrix"' + run: php bin/monitor matrix --ansi + + - + name: 'Run "Analyze"' + run: php bin/monitor analyze --ansi + - name: 'Composer dependency Analyser' run: vendor/bin/composer-dependency-analyser diff --git a/README.md b/README.md index d040268..0e51996 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,48 @@ composer require rector/monitor --dev
-## Usage - -
- -### 1. Quality control for `composer.json` in multiple repositories +## 1. Single place to Quality control Multiple repositories ```bash vendor/bin/monitor analyze ``` +This command will load `monitor.php` configuration file from project root. There you define repositories and requirements to meet. + +```php +use Rector\Monitor\Config\MonitorConfig; + +return MonitorConfig::configure() + ->addRepositories([ + '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('https://github.com/rectorphp/rector-src', 'main') + // ->addRepositoryBranch('...', 'stage') + + // composer rules + // ->disallowPackages(['symfony/phpunit-bridge']) + ->requirePackages([ + 'rector/rector', + 'phpecs/phpecs', + 'phpstan/phpstan', + 'phpstan/extension-installer', + 'symplify/phpstan-rules', + ]) + + // version requirements + ->minPackageVersion('phpstan/phpstan', '2.1') + ->minPackageVersion('rector/rector', '2.2') + + // other rules + ->noPhpstanBaseline(); +``` + +
+ +The repositories are cached to get fast performance. To refresh them: ```bash vendor/bin/monitor analyze --clear-cache @@ -37,24 +69,22 @@ vendor/bin/monitor analyze --clear-cache
-### 2. See full Matrix of repositories's dependencies +## 2. See full Matrix of Repositories' Dependencies ```bash vendor/bin/monitor matrix ``` ---- -## Merge many projects to one Monorepo +
-Automate micro-services merge to one macro project, to make coding saint again. +## 3. See Difference between Two Projects +Automate micro-services merge to one macro project, to make coding saint again.
-### Use - See how the monorepo project and the merge one are different. Use this knowledge to fill gaps in monorepo project. Only then create a final merge pull-request. ```bash diff --git a/monitor.php b/monitor.php index 11370d2..c034bac 100644 --- a/monitor.php +++ b/monitor.php @@ -7,20 +7,19 @@ return MonitorConfig::configure() ->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') + ->addRepositoryBranch('https://github.com/rectorphp/rector-src', 'main') // composer rules // ->disallowPackages(['symfony/phpunit-bridge']) ->requirePackages([ 'phpstan/phpstan', 'phpecs/phpecs', - 'rector/rector', + 'rector/rector-src', 'phpstan/phpstan-deprecation-rules', 'phpstan/extension-installer', 'symplify/phpstan-rules', diff --git a/src/Config/MonitorConfig.php b/src/Config/MonitorConfig.php index 9ca5260..c564aea 100644 --- a/src/Config/MonitorConfig.php +++ b/src/Config/MonitorConfig.php @@ -129,6 +129,10 @@ public function getMinPackagesVersions(): array public function addRepositoryBranch(string $repository, string $branch): self { + if (! str_ends_with($repository, '.git')) { + $repository .= '.git'; + } + MonitorAssert::assertRepositoryUrl($repository); $this->repositoriesWithBranches[$repository] = $branch; diff --git a/src/Git/RepositoryMetafilesResolver.php b/src/Git/RepositoryMetafilesResolver.php index b5d8d85..aa203e7 100644 --- a/src/Git/RepositoryMetafilesResolver.php +++ b/src/Git/RepositoryMetafilesResolver.php @@ -22,42 +22,36 @@ public function __construct( ) { } - public function decorateRepositories(RepositoryCollection $repositoryCollection, bool $clearCache = false): void - { + public function decorateRepositories( + RepositoryCollection $repositoryCollection, + bool $clearCache = false, + bool $isDebug = false + ): void { foreach ($repositoryCollection->all() as $repository) { $repositoryCacheDirectory = sys_get_temp_dir() . '/rector-monitor-cache/repository-' . md5( $repository->getRepositoryUrl() ); - if (file_exists($repositoryCacheDirectory) && $this->hasDirectorySomeFiles($repositoryCacheDirectory)) { - if ($clearCache) { - // clear old files - FileSystem::delete($repositoryCacheDirectory); - } else { - $rootFiles = $this->findRootFilesInDirectory($repositoryCacheDirectory); - $repository->decorateRootFiles($rootFiles); - - $composerJsonFile = $this->matchComposerJsonFile($rootFiles, $repository); - - $composerJson = $this->composerJsonFactory->create($composerJsonFile, $repository); - $repository->decorateComposerJson($composerJson); - - $this->symfonyStyle->writeln(sprintf( - ' * loading "%s" repository from cache', - $repository->getComposerJson() - ->getRepositoryName() - )); - - continue; - } + if ($clearCache) { + // clear old files + FileSystem::delete($repositoryCacheDirectory); } - $this->symfonyStyle->writeln(sprintf( - ' * loading files from "%s" remote repository', - $repository->getRepositoryUrl() - )); + if ($this->hasDirectorySomeFiles($repositoryCacheDirectory)) { + $this->symfonyStyle->writeln(sprintf( + ' * loading "%s" repository from cache', + $repository->getRepositoryUrl() + )); + } else { + $this->symfonyStyle->writeln(sprintf( + ' * loading files from "%s" remote repository', + $repository->getRepositoryUrl() + )); + + $this->downloadRepository($repository, $repositoryCacheDirectory, $isDebug); + } - $rootFiles = $this->loadRootFilesFromRepository($repository, $repositoryCacheDirectory); + $rootFiles = $this->findRootFilesInDirectory($repositoryCacheDirectory); $repository->decorateRootFiles($rootFiles); $composerJsonFile = $this->matchComposerJsonFile($rootFiles, $repository); @@ -77,20 +71,33 @@ private function findRootFilesInDirectory(string $repositoryCacheDirectory): arr return iterator_to_array($repositoryRootFilesFinder->getIterator()); } - /** - * @return SplFileInfo[] - */ - private function loadRootFilesFromRepository(Repository $repository, string $repositoryCacheDirectory): array + private function downloadRepository(Repository $repository, string $repositoryCacheDirectory, bool $isDebug): void { FileSystem::createDir($repositoryCacheDirectory); - Process::fromShellCommandline('git init', $repositoryCacheDirectory) - ->mustRun(); + $process = Process::fromShellCommandline('git init', $repositoryCacheDirectory); + if ($isDebug) { + $this->symfonyStyle->writeln('Running command: ' . $process->getCommandLine()); + } - Process::fromShellCommandline( + $process->mustRun(); + if ($isDebug) { + $this->symfonyStyle->writeln('Cloning repository:' . PHP_EOL . $process->getOutput()); + } + + $process = Process::fromShellCommandline( 'git remote add origin ' . $repository->getClonableRepositoryUrl(), $repositoryCacheDirectory - )->mustRun(); + ); + + if ($isDebug) { + $this->symfonyStyle->writeln('Running command: ' . $process->getCommandLine()); + } + + $process->mustRun(); + if ($isDebug) { + $this->symfonyStyle->writeln('Cloning repository:' . PHP_EOL . $process->getOutput()); + } // might be a bit longer for large repositories Process::fromShellCommandline('git fetch origin --depth 1', $repositoryCacheDirectory, timeout: 120) @@ -98,11 +105,9 @@ private function loadRootFilesFromRepository(Repository $repository, string $rep // Fetch the latest changes from the remote repository Process::fromShellCommandline( - sprintf('git checkout %s', $repository->getBranch() ?: 'FETCH_HEAD'), + sprintf('git checkout %s', $repository->getBranch() ?: 'main'), $repositoryCacheDirectory )->mustRun(); - - return $this->findRootFilesInDirectory($repositoryCacheDirectory); } /** @@ -126,8 +131,11 @@ private function matchComposerJsonFile(array $rootFiles, Repository $repository) private function hasDirectorySomeFiles(string $repositoryCacheDirectory): bool { - $fileCountInDirectory = Finder::create()->in($repositoryCacheDirectory)->files()->count(); + if (! is_dir($repositoryCacheDirectory)) { + return false; + } + $fileCountInDirectory = Finder::create()->in($repositoryCacheDirectory)->files()->count(); return $fileCountInDirectory > 0; } } diff --git a/src/Matrix/Command/MatrixCommand.php b/src/Matrix/Command/MatrixCommand.php index c26ed2d..7aac740 100644 --- a/src/Matrix/Command/MatrixCommand.php +++ b/src/Matrix/Command/MatrixCommand.php @@ -44,6 +44,9 @@ protected function configure(): void InputOption::VALUE_NONE, 'Remove cached repositories composer.json files' ); + + // add --debug option + $this->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode for more verbose output'); } protected function execute(InputInterface $input, OutputInterface $output): int @@ -54,14 +57,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $monitorConfig = $this->monitorConfigProvider->provide(); $shouldClearCache = (bool) $input->getOption('clear-cache'); + $isDebug = (bool) $input->getOption('debug'); - $this->symfonyStyle->title('Showing Dependency Matrix'); + $this->symfonyStyle->title('Composer Dependency Matrix'); $this->repositoryMetafilesResolver->decorateRepositories( $monitorConfig->getRepositoryCollection(), - $shouldClearCache + $shouldClearCache, + $isDebug ); + $this->symfonyStyle->newLine(2); + $repositoryCollection = $monitorConfig->getRepositoryCollection(); $requiredPackageNames = $monitorConfig->getComposerRequiredPackageNames(); @@ -70,8 +77,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->renderTable($tableHeadlines, $tableRows); - $this->symfonyStyle->newLine(); - return self::SUCCESS; } @@ -112,7 +117,7 @@ private function createTableRows(array $requiredPackageNames, RepositoryCollecti } $dataRow = SymfonyColumnStyler::styleHighsAndLows($dataRow); - $shortRequiredPackageName = Strings::truncate($requiredPackageName, 25); + $shortRequiredPackageName = Strings::truncate($requiredPackageName, 35); $tableRow = array_merge([$shortRequiredPackageName], $dataRow); $tableRows[] = $tableRow; From 04a577e9c88603faf55163605e8e806de60ea2fb Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 6 Dec 2025 10:00:20 +0100 Subject: [PATCH 3/3] fix sort by package count --- src/Matrix/Command/MatrixCommand.php | 3 +-- src/ValueObject/RepositoryCollection.php | 14 +++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Matrix/Command/MatrixCommand.php b/src/Matrix/Command/MatrixCommand.php index 7aac740..53b6e1e 100644 --- a/src/Matrix/Command/MatrixCommand.php +++ b/src/Matrix/Command/MatrixCommand.php @@ -72,7 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $repositoryCollection = $monitorConfig->getRepositoryCollection(); $requiredPackageNames = $monitorConfig->getComposerRequiredPackageNames(); - $tableHeadlines = array_merge(['dependency'], $repositoryCollection->getRepositoryNames()); + $tableHeadlines = array_merge(['dependency'], $repositoryCollection->getRepositoryNamesByPackageCount()); $tableRows = $this->createTableRows($requiredPackageNames, $repositoryCollection); $this->renderTable($tableHeadlines, $tableRows); @@ -98,7 +98,6 @@ private function createTableRows(array $requiredPackageNames, RepositoryCollecti $dataRow = []; foreach ($repositoryCollection->allSorterByPackageCount() as $composerJson) { - $packageVersion = $composerJson->getPackageVersion($requiredPackageName); if ($packageVersion !== null) { ++$knownValuesCount; diff --git a/src/ValueObject/RepositoryCollection.php b/src/ValueObject/RepositoryCollection.php index bd9c04c..4e87991 100644 --- a/src/ValueObject/RepositoryCollection.php +++ b/src/ValueObject/RepositoryCollection.php @@ -26,7 +26,6 @@ public function getComposerRequiredPackageNames(): array $requiredPackageNames = []; foreach ($this->repositories as $repository) { $composerJson = $repository->getComposerJson(); - $requiredPackageNames = array_merge($requiredPackageNames, $composerJson->getRequiredPackageNames()); } @@ -49,6 +48,19 @@ public function getRepositoryNames(): array return $repositoryNames; } + /** + * @return string[] + */ + public function getRepositoryNamesByPackageCount(): array + { + $repositoryNames = []; + foreach ($this->allSorterByPackageCount() as $composerJson) { + $repositoryNames[] = $composerJson->getRepositoryName(); + } + + return $repositoryNames; + } + public function count(): int { return count($this->repositories);