diff --git a/packages-tests/ChangesReporting/Annotation/AnnotationExtractorTest.php b/packages-tests/ChangesReporting/Annotation/AnnotationExtractorTest.php index 43c6dc8e7108..c177e5b3736c 100644 --- a/packages-tests/ChangesReporting/Annotation/AnnotationExtractorTest.php +++ b/packages-tests/ChangesReporting/Annotation/AnnotationExtractorTest.php @@ -6,8 +6,8 @@ use Iterator; use PHPUnit\Framework\TestCase; use Rector\ChangesReporting\Annotation\AnnotationExtractor; -use Rector\Tests\ChangesReporting\ValueObject\Source\RectorWithChangelog; -use Rector\Tests\ChangesReporting\ValueObject\Source\RectorWithOutChangelog; +use Rector\Tests\ChangesReporting\Annotation\AppliedRectorsChangelogResolver\Source\RectorWithChangelog; +use Rector\Tests\ChangesReporting\Annotation\AppliedRectorsChangelogResolver\Source\RectorWithOutChangelog; final class AnnotationExtractorTest extends TestCase { diff --git a/packages-tests/ChangesReporting/Annotation/AppliedRectorsChangelogResolver/RectorsChangelogResolverTest.php b/packages-tests/ChangesReporting/Annotation/AppliedRectorsChangelogResolver/RectorsChangelogResolverTest.php new file mode 100644 index 000000000000..843054e1687e --- /dev/null +++ b/packages-tests/ChangesReporting/Annotation/AppliedRectorsChangelogResolver/RectorsChangelogResolverTest.php @@ -0,0 +1,75 @@ +bootKernel(RectorKernel::class); + $this->rectorsChangelogResolver = $this->getService(RectorsChangelogResolver::class); + + $this->fileDiff = $this->createFileDiff(); + } + + public function test(): void + { + $rectorsChangelogs = $this->rectorsChangelogResolver->resolve($this->fileDiff->getRectorClasses()); + + $expectedRectorsChangelogs = [ + RectorWithChangelog::class => 'https://github.com/rectorphp/rector/blob/master/docs/rector_rules_overview.md', + ]; + $this->assertSame($expectedRectorsChangelogs, $rectorsChangelogs); + } + + private function createFileDiff(): FileDiff + { + // This is by intention to test the array_unique functionality + $rectorWithFileAndLineChange1 = new RectorWithFileAndLineChange( + new RectorWithChangelog(), + __DIR__ . '/Source/RectorWithChangelog.php', + 1 + ); + + $rectorWithFileAndLineChange2 = new RectorWithFileAndLineChange( + new RectorWithChangelog(), + __DIR__ . '/Source/RectorWithChangelog.php', + 1 + ); + + $rectorWithFileAndLineChange3 = new RectorWithFileAndLineChange( + new RectorWithOutChangelog(), + __DIR__ . '/Source/RectorWithOutChangelog.php', + 1 + ); + + $rectorWithFileAndLineChanges = [ + $rectorWithFileAndLineChange1, + $rectorWithFileAndLineChange2, + $rectorWithFileAndLineChange3, + ]; + + return new FileDiff(new SmartFileInfo(__FILE__), 'foo', 'foo', $rectorWithFileAndLineChanges); + } +} diff --git a/packages-tests/ChangesReporting/ValueObject/Source/RectorWithChangelog.php b/packages-tests/ChangesReporting/Annotation/AppliedRectorsChangelogResolver/Source/RectorWithChangelog.php similarity index 82% rename from packages-tests/ChangesReporting/ValueObject/Source/RectorWithChangelog.php rename to packages-tests/ChangesReporting/Annotation/AppliedRectorsChangelogResolver/Source/RectorWithChangelog.php index 653cf60f729e..4d5513218783 100644 --- a/packages-tests/ChangesReporting/ValueObject/Source/RectorWithChangelog.php +++ b/packages-tests/ChangesReporting/Annotation/AppliedRectorsChangelogResolver/Source/RectorWithChangelog.php @@ -1,8 +1,8 @@ createFileDiff(); - $this->assertSame([RectorWithChangelog::class, RectorWithOutChangelog::class], $fileDiff->getRectorClasses()); - } - - public function testGetRectorClassesWithChangelogUrlAndRectorClassAsKey(): void - { - $fileDiff = $this->createFileDiff(); - $this->assertSame( - [ - 'Rector\Tests\ChangesReporting\ValueObject\Source\RectorWithChangelog' => 'https://github.com/rectorphp/rector/blob/master/docs/rector_rules_overview.md', - ], - $fileDiff->getRectorClassesWithChangelogUrlAndRectorClassAsKey(new AnnotationExtractor()) - ); - } - - public function testGetRectorClassesWithChangelogUrl(): void - { - $fileDiff = $this->createFileDiff(); - $this->assertSame( - [ - 'Rector\Tests\ChangesReporting\ValueObject\Source\RectorWithChangelog (https://github.com/rectorphp/rector/blob/master/docs/rector_rules_overview.md)', - 'Rector\Tests\ChangesReporting\ValueObject\Source\RectorWithOutChangelog', - ], - $fileDiff->getRectorClassesWithChangelogUrl(new AnnotationExtractor()) - ); - } - - private function createFileDiff(): FileDiff - { - // This is by intention to test the array_unique functionality - $rectorWithFileAndLineChange1 = new RectorWithFileAndLineChange( - new RectorWithChangelog(), - __DIR__ . '/Source/RectorWithChangelog.php', - 1 - ); - - $rectorWithFileAndLineChange2 = new RectorWithFileAndLineChange( - new RectorWithChangelog(), - __DIR__ . '/Source/RectorWithChangelog.php', - 1 - ); - - $rectorWithFileAndLineChange3 = new RectorWithFileAndLineChange( - new RectorWithOutChangelog(), - __DIR__ . '/Source/RectorWithOutChangelog.php', - 1 - ); - - $rectorWithFileAndLineChanges = [ - $rectorWithFileAndLineChange1, - $rectorWithFileAndLineChange2, - $rectorWithFileAndLineChange3, - ]; - - return new FileDiff(new SmartFileInfo(__FILE__), 'foo', 'foo', $rectorWithFileAndLineChanges); - } -} diff --git a/packages-tests/ChangesReporting/ValueObject/RectorWithFileAndLineChangeTest.php b/packages-tests/ChangesReporting/ValueObject/RectorWithFileAndLineChangeTest.php deleted file mode 100644 index efdda477331e..000000000000 --- a/packages-tests/ChangesReporting/ValueObject/RectorWithFileAndLineChangeTest.php +++ /dev/null @@ -1,43 +0,0 @@ -assertSame( - $expected, - $rectorWithFileAndLineChange->getRectorClassWithChangelogUrl(new AnnotationExtractor()) - ); - } - - /** - * @return Iterator>> - */ - public function rectorsWithFileAndLineChange(): Iterator - { - yield 'Rector with link' => [ - 'Rector\Tests\ChangesReporting\ValueObject\Source\RectorWithChangelog (https://github.com/rectorphp/rector/blob/master/docs/rector_rules_overview.md)', - new RectorWithFileAndLineChange(new RectorWithChangelog(), __DIR__ . '/Source/RectorWithLink.php', 1), - ]; - - yield 'Rector without link' => [ - 'Rector\Tests\ChangesReporting\ValueObject\Source\RectorWithOutChangelog', - new RectorWithFileAndLineChange(new RectorWithOutChangelog(), __DIR__ . '/Source/RectorWithLink.php', 1), - ]; - } -} diff --git a/packages/ChangesReporting/Annotation/AnnotationExtractor.php b/packages/ChangesReporting/Annotation/AnnotationExtractor.php index f25814c88b12..418b163014f8 100644 --- a/packages/ChangesReporting/Annotation/AnnotationExtractor.php +++ b/packages/ChangesReporting/Annotation/AnnotationExtractor.php @@ -1,9 +1,11 @@ $className + * @param class-string $className */ public function extractAnnotationFromClass(string $className, string $annotation): ?string { @@ -26,7 +28,6 @@ public function extractAnnotationFromClass(string $className, string $annotation // @see https://regex101.com/r/oYGaWU/1 $pattern = '#' . preg_quote($annotation, '#') . '\s+(?.*?)$#m'; $matches = Strings::match($docComment, $pattern); - return $matches['content'] ?? null; } } diff --git a/packages/ChangesReporting/Annotation/RectorsChangelogResolver.php b/packages/ChangesReporting/Annotation/RectorsChangelogResolver.php new file mode 100644 index 000000000000..58924de97a42 --- /dev/null +++ b/packages/ChangesReporting/Annotation/RectorsChangelogResolver.php @@ -0,0 +1,45 @@ +annotationExtractor = $annotationExtractor; + } + + /** + * @param array> $rectorClasses + * @return array + */ + public function resolve(array $rectorClasses): array + { + $rectorClassesToChangelogUrls = $this->resolveIncludingMissing($rectorClasses); + return array_filter($rectorClassesToChangelogUrls); + } + + /** + * @param array> $rectorClasses + * @return array + */ + public function resolveIncludingMissing(array $rectorClasses): array + { + $rectorClassesToChangelogUrls = []; + foreach ($rectorClasses as $rectorClass) { + $changelogUrl = $this->annotationExtractor->extractAnnotationFromClass($rectorClass, '@changelog'); + $rectorClassesToChangelogUrls[$rectorClass] = $changelogUrl; + } + + return $rectorClassesToChangelogUrls; + } +} diff --git a/packages/ChangesReporting/Output/ConsoleOutputFormatter.php b/packages/ChangesReporting/Output/ConsoleOutputFormatter.php index 8fdbb236baf1..d2da450eca3c 100644 --- a/packages/ChangesReporting/Output/ConsoleOutputFormatter.php +++ b/packages/ChangesReporting/Output/ConsoleOutputFormatter.php @@ -5,7 +5,7 @@ namespace Rector\ChangesReporting\Output; use Nette\Utils\Strings; -use Rector\ChangesReporting\Annotation\AnnotationExtractor; +use Rector\ChangesReporting\Annotation\RectorsChangelogResolver; use Rector\ChangesReporting\Application\ErrorAndDiffCollector; use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface; use Rector\Core\Configuration\Configuration; @@ -46,20 +46,20 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface private $betterStandardPrinter; /** - * @var AnnotationExtractor + * @var RectorsChangelogResolver */ - private $annotationExtractor; + private $rectorsChangelogResolver; public function __construct( BetterStandardPrinter $betterStandardPrinter, Configuration $configuration, SymfonyStyle $symfonyStyle, - AnnotationExtractor $annotationExtractor + RectorsChangelogResolver $rectorsChangelogResolver ) { $this->symfonyStyle = $symfonyStyle; $this->betterStandardPrinter = $betterStandardPrinter; $this->configuration = $configuration; - $this->annotationExtractor = $annotationExtractor; + $this->rectorsChangelogResolver = $rectorsChangelogResolver; } public function report(ErrorAndDiffCollector $errorAndDiffCollector): void @@ -119,10 +119,12 @@ private function reportFileDiffs(array $fileDiffs): void $this->symfonyStyle->writeln($fileDiff->getDiffConsoleFormatted()); $this->symfonyStyle->newLine(); + $rectorsChangelogsLines = $this->createRectorChangelogLines($fileDiff); + if ($fileDiff->getRectorChanges() !== []) { $this->symfonyStyle->writeln('Applied rules:'); $this->symfonyStyle->newLine(); - $this->symfonyStyle->listing($fileDiff->getRectorClassesWithChangelogUrl($this->annotationExtractor)); + $this->symfonyStyle->listing($rectorsChangelogsLines); $this->symfonyStyle->newLine(); } } @@ -232,4 +234,19 @@ private function createSuccessMessage(ErrorAndDiffCollector $errorAndDiffCollect $this->configuration->isDryRun() ? 'would have changed (dry-run)' : ($changeCount === 1 ? 'has' : 'have') . ' been changed' ); } + + /** + * @return string[] + */ + private function createRectorChangelogLines(FileDiff $fileDiff): array + { + $rectorsChangelogs = $this->rectorsChangelogResolver->resolveIncludingMissing($fileDiff->getRectorClasses()); + + $rectorsChangelogsLines = []; + foreach ($rectorsChangelogs as $rectorClass => $changelog) { + $rectorsChangelogsLines[] = $changelog === null ? $rectorClass : $rectorClass . ' ' . $changelog; + } + + return $rectorsChangelogsLines; + } } diff --git a/packages/ChangesReporting/Output/JsonOutputFormatter.php b/packages/ChangesReporting/Output/JsonOutputFormatter.php index a5a44d431905..3d4f852b53ad 100644 --- a/packages/ChangesReporting/Output/JsonOutputFormatter.php +++ b/packages/ChangesReporting/Output/JsonOutputFormatter.php @@ -5,7 +5,7 @@ namespace Rector\ChangesReporting\Output; use Nette\Utils\Json; -use Rector\ChangesReporting\Annotation\AnnotationExtractor; +use Rector\ChangesReporting\Annotation\RectorsChangelogResolver; use Rector\ChangesReporting\Application\ErrorAndDiffCollector; use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface; use Rector\Core\Configuration\Configuration; @@ -29,18 +29,18 @@ final class JsonOutputFormatter implements OutputFormatterInterface private $smartFileSystem; /** - * @var AnnotationExtractor + * @var RectorsChangelogResolver */ - private $annotationExtractor; + private $rectorsChangelogResolver; public function __construct( Configuration $configuration, SmartFileSystem $smartFileSystem, - AnnotationExtractor $annotationExtractor + RectorsChangelogResolver $rectorsChangelogResolver ) { $this->configuration = $configuration; $this->smartFileSystem = $smartFileSystem; - $this->annotationExtractor = $annotationExtractor; + $this->rectorsChangelogResolver = $rectorsChangelogResolver; } public function getName(): string @@ -67,9 +67,7 @@ public function report(ErrorAndDiffCollector $errorAndDiffCollector): void foreach ($fileDiffs as $fileDiff) { $relativeFilePath = $fileDiff->getRelativeFilePath(); - $appliedRectorsWithChangelog = $fileDiff->getRectorClassesWithChangelogUrlAndRectorClassAsKey( - $this->annotationExtractor - ); + $appliedRectorsWithChangelog = $this->rectorsChangelogResolver->resolve($fileDiff->getRectorClasses()); $errorsArray['file_diffs'][] = [ 'file' => $relativeFilePath, diff --git a/packages/ChangesReporting/ValueObject/RectorWithFileAndLineChange.php b/packages/ChangesReporting/ValueObject/RectorWithFileAndLineChange.php index 21eb898fc39b..9aceabb04fcd 100644 --- a/packages/ChangesReporting/ValueObject/RectorWithFileAndLineChange.php +++ b/packages/ChangesReporting/ValueObject/RectorWithFileAndLineChange.php @@ -4,7 +4,6 @@ namespace Rector\ChangesReporting\ValueObject; -use Rector\ChangesReporting\Annotation\AnnotationExtractor; use Rector\Core\Contract\Rector\RectorInterface; final class RectorWithFileAndLineChange @@ -37,30 +36,14 @@ public function getRectorDefinitionsDescription(): string return $ruleDefinition->getDescription(); } + /** + * @return class-string + */ public function getRectorClass(): string { return get_class($this->rector); } - public function getRectorClassWithChangelogUrl(AnnotationExtractor $annotationExtractor): string - { - $rectorClass = get_class($this->rector); - $changeLogUrl = $this->getChangelogUrl($annotationExtractor); - - if ($changeLogUrl === null) { - return $rectorClass; - } - - return sprintf('%s (%s)', $rectorClass, $changeLogUrl); - } - - public function getChangelogUrl(AnnotationExtractor $annotationExtractor): ?string - { - $rectorClass = get_class($this->rector); - - return $annotationExtractor->extractAnnotationFromClass($rectorClass, '@changelog'); - } - public function getLine(): int { return $this->line; diff --git a/src/ValueObject/Reporting/FileDiff.php b/src/ValueObject/Reporting/FileDiff.php index aad994684258..aa9180fd9850 100644 --- a/src/ValueObject/Reporting/FileDiff.php +++ b/src/ValueObject/Reporting/FileDiff.php @@ -4,8 +4,8 @@ namespace Rector\Core\ValueObject\Reporting; -use Rector\ChangesReporting\Annotation\AnnotationExtractor; use Rector\ChangesReporting\ValueObject\RectorWithFileAndLineChange; +use Rector\Core\Contract\Rector\RectorInterface; use Symplify\SmartFileSystem\SmartFileInfo; final class FileDiff @@ -74,7 +74,7 @@ public function getRectorChanges(): array } /** - * @return string[] + * @return array> */ public function getRectorClasses(): array { @@ -87,45 +87,13 @@ public function getRectorClasses(): array } /** - * @return string[] - */ - public function getRectorClassesWithChangelogUrl(AnnotationExtractor $annotationExtractor): array - { - $rectorClasses = []; - foreach ($this->rectorWithFileAndLineChanges as $rectorWithFileAndLineChange) { - $rectorClasses[] = $rectorWithFileAndLineChange->getRectorClassWithChangelogUrl($annotationExtractor); - } - - return $this->sortClasses($rectorClasses); - } - - /** - * @return array - */ - public function getRectorClassesWithChangelogUrlAndRectorClassAsKey(AnnotationExtractor $annotationExtractor): array - { - $rectorClasses = []; - foreach ($this->rectorWithFileAndLineChanges as $rectorWithFileAndLineChange) { - $changelogUrl = $rectorWithFileAndLineChange->getChangelogUrl($annotationExtractor); - if ($changelogUrl !== null) { - $rectorClasses[$rectorWithFileAndLineChange->getRectorClass()] = $changelogUrl; - } - } - $rectorClasses = array_unique($rectorClasses); - - ksort($rectorClasses); - - return $rectorClasses; - } - - /** - * @param string[] $rectorClasses - * @return string[] + * @template TType as object + * @param array> $rectorClasses + * @return array> */ private function sortClasses(array $rectorClasses): array { $rectorClasses = array_unique($rectorClasses); - sort($rectorClasses); return $rectorClasses;