decouple ChangesReporting package

This commit is contained in:
TomasVotruba 2020-03-19 01:07:07 +01:00
parent 25510354c9
commit 97f5ff545c
22 changed files with 289 additions and 78 deletions

13
abz/DeadCode.php Normal file
View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
final class DeadCode
{
public function run()
{
return 1;
return 2;
}
}

View File

@ -61,6 +61,7 @@
"Rector\\CodeQuality\\": "rules/code-quality/src",
"Rector\\CodingStyle\\": "rules/coding-style/src",
"Rector\\ConsoleDiffer\\": "packages/console-differ/src",
"Rector\\ChangesReporting\\": "packages/changes-reporting/src",
"Rector\\DeadCode\\": "rules/dead-code/src",
"Rector\\DoctrineCodeQuality\\": "rules/doctrine-code-quality/src",
"Rector\\DoctrineGedmoToKnplabs\\": "rules/doctrine-gedmo-to-knplabs/src",

View File

@ -0,0 +1,11 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: true
Rector\ChangesReporting\:
resource: '../src'
exclude:
- '../src/Contract/*'
- '../src/ValueObject/*'

View File

@ -2,10 +2,11 @@
declare(strict_types=1);
namespace Rector\Core\Application;
namespace Rector\ChangesReporting\Application;
use PhpParser\Node;
use PHPStan\AnalysedCodeException;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\ConsoleDiffer\DifferAndFormatter;
use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector;
use Rector\Core\Error\ExceptionCorrector;
@ -33,9 +34,9 @@ final class ErrorAndDiffCollector
private $differAndFormatter;
/**
* @var AppliedRectorCollector
* @var RectorChangeCollector
*/
private $appliedRectorCollector;
private $rectorChangeCollector;
/**
* @var ExceptionCorrector
@ -54,13 +55,13 @@ final class ErrorAndDiffCollector
public function __construct(
DifferAndFormatter $differAndFormatter,
AppliedRectorCollector $appliedRectorCollector,
RectorChangeCollector $rectorChangeCollector,
ExceptionCorrector $exceptionCorrector,
RemovedAndAddedFilesCollector $removedAndAddedFilesCollector,
NodeRemovingCommander $nodeRemovingCommander
) {
$this->differAndFormatter = $differAndFormatter;
$this->appliedRectorCollector = $appliedRectorCollector;
$this->rectorChangeCollector = $rectorChangeCollector;
$this->exceptionCorrector = $exceptionCorrector;
$this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector;
$this->nodeRemovingCommander = $nodeRemovingCommander;
@ -103,14 +104,14 @@ final class ErrorAndDiffCollector
return;
}
$appliedRectors = $this->appliedRectorCollector->getRectorClasses($smartFileInfo);
$rectorChanges = $this->rectorChangeCollector->getRectorChangesByFileInfo($smartFileInfo);
// always keep the most recent diff
$this->fileDiffs[$smartFileInfo->getRealPath()] = new FileDiff(
$smartFileInfo,
$this->differAndFormatter->diff($oldContent, $newContent),
$this->differAndFormatter->diffAndFormat($oldContent, $newContent),
$appliedRectors
$rectorChanges
);
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Rector\ChangesReporting\Collector;
use Rector\ChangesReporting\ValueObject\RectorWithFileAndLineChange;
use Symplify\SmartFileSystem\SmartFileInfo;
final class RectorChangeCollector
{
/**
* @var RectorWithFileAndLineChange[]
*/
private $rectorWithFileAndLineChanges = [];
public function addRectorClassWithLine(string $rectorClass, SmartFileInfo $smartFileInfo, int $line): void
{
$this->rectorWithFileAndLineChanges[] = new RectorWithFileAndLineChange(
$rectorClass,
$smartFileInfo->getRealPath(),
$line
);
}
/**
* @return RectorWithFileAndLineChange[]
*/
public function getRectorChangesByFileInfo(SmartFileInfo $smartFileInfo): array
{
return array_filter(
$this->rectorWithFileAndLineChanges,
function (RectorWithFileAndLineChange $rectorWithFileAndLineChange) use ($smartFileInfo) {
return $rectorWithFileAndLineChange->getRealPath() === $smartFileInfo->getRealPath();
}
);
}
}

View File

@ -2,9 +2,9 @@
declare(strict_types=1);
namespace Rector\Core\Contract\Console\Output;
namespace Rector\ChangesReporting\Contract\Output;
use Rector\Core\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
interface OutputFormatterInterface
{

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace Rector\ChangesReporting\Output;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
use Rector\Core\ValueObject\Reporting\FileDiff;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Inspired by https://github.com/phpstan/phpstan-src/commit/fa1f416981438b80e2f39eabd9f1b62fca9a6803#diff-7a7d635d9f9cf3388e34d414731dece3
*/
final class CheckstyleOutputFormatter implements OutputFormatterInterface
{
/**
* @var string
*/
public const NAME = 'checkstyle';
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
public function __construct(SymfonyStyle $symfonyStyle)
{
$this->symfonyStyle = $symfonyStyle;
}
public function getName(): string
{
return self::NAME;
}
public function report(ErrorAndDiffCollector $errorAndDiffCollector): void
{
if ($errorAndDiffCollector->getErrors() === [] && $errorAndDiffCollector->getFileDiffsCount() === 0) {
return;
}
$this->symfonyStyle->writeln('<?xml version="1.0" encoding="UTF-8"?>');
$this->symfonyStyle->writeln('<checkstyle>');
foreach ($errorAndDiffCollector->getFileDiffs() as $fileDiff) {
$this->writeFileErrors($fileDiff);
}
$this->writeNonFileErrors($errorAndDiffCollector);
$this->symfonyStyle->writeln('</checkstyle>');
}
private function escape(string $string): string
{
return htmlspecialchars($string, ENT_XML1 | ENT_COMPAT, 'UTF-8');
}
private function writeNonFileErrors(ErrorAndDiffCollector $errorAndDiffCollector): void
{
if ($errorAndDiffCollector->getErrors() !== []) {
$this->symfonyStyle->writeln('<file>');
foreach ($errorAndDiffCollector->getErrors() as $error) {
$escapedMessage = $this->escape($error->getMessage());
$this->symfonyStyle->writeln(
sprintf(' <error severity="error" message="%s" />', $escapedMessage)
);
}
$this->symfonyStyle->writeln('</file>');
}
}
private function writeFileErrors(FileDiff $fileDiff): void
{
$this->symfonyStyle->writeln(sprintf('<file name="%s">', $this->escape($fileDiff->getRelativeFilePath())));
foreach ($fileDiff->getRectorChanges() as $rectorChange) {
$error = sprintf(
' <error line="%d" column="1" severity="error" message="%s" />',
$this->escape((string) $rectorChange->getLine()),
$this->escape((string) $rectorChange->getRectorClass())
);
$this->symfonyStyle->writeln($error);
}
$this->symfonyStyle->writeln('</file>');
}
}

View File

@ -2,13 +2,13 @@
declare(strict_types=1);
namespace Rector\Core\Console\Output;
namespace Rector\ChangesReporting\Output;
use Nette\Utils\Strings;
use Rector\Core\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
use Rector\Core\Configuration\Configuration;
use Rector\Core\Configuration\Option;
use Rector\Core\Contract\Console\Output\OutputFormatterInterface;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\ValueObject\Application\Error;
use Rector\Core\ValueObject\Reporting\FileDiff;
@ -112,10 +112,10 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface
$this->symfonyStyle->writeln($fileDiff->getDiffConsoleFormatted());
$this->symfonyStyle->newLine();
if ($fileDiff->getAppliedRectorClasses() !== []) {
if ($fileDiff->getRectorChanges() !== []) {
$this->symfonyStyle->writeln('Applied rules:');
$this->symfonyStyle->newLine();
$this->symfonyStyle->listing($fileDiff->getAppliedRectorClasses());
$this->symfonyStyle->listing($fileDiff->getRectorClasses());
$this->symfonyStyle->newLine();
}
}

View File

@ -2,13 +2,13 @@
declare(strict_types=1);
namespace Rector\Core\Console\Output;
namespace Rector\ChangesReporting\Output;
use Nette\Utils\FileSystem;
use Nette\Utils\Json;
use Rector\Core\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
use Rector\Core\Configuration\Configuration;
use Rector\Core\Contract\Console\Output\OutputFormatterInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
final class JsonOutputFormatter implements OutputFormatterInterface
@ -61,7 +61,7 @@ final class JsonOutputFormatter implements OutputFormatterInterface
$errorsArray['file_diffs'][] = [
'file' => $relativeFilePath,
'diff' => $fileDiff->getDiff(),
'applied_rectors' => $fileDiff->getAppliedRectorClasses(),
'applied_rectors' => $fileDiff->getRectorClasses(),
];
// for Rector CI

View File

@ -2,29 +2,29 @@
declare(strict_types=1);
namespace Rector\Core\Rector\AbstractRector;
namespace Rector\ChangesReporting\Rector\AbstractRector;
use PhpParser\Node;
use Rector\Core\Application\AppliedRectorCollector;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* This could be part of @see AbstractRector, but decopuling to trait
* makes clear what code has 1 purpose.
*/
trait AppliedRectorCollectorTrait
trait RectorChangeCollectorTrait
{
/**
* @var AppliedRectorCollector
* @var RectorChangeCollector
*/
private $appliedRectorCollector;
private $rectorChangeCollector;
/**
* @required
*/
public function setAppliedRectorCollector(AppliedRectorCollector $appliedRectorCollector): void
public function autowireAppliedRectorCollectorTrait(RectorChangeCollector $rectorChangeCollector): void
{
$this->appliedRectorCollector = $appliedRectorCollector;
$this->rectorChangeCollector = $rectorChangeCollector;
}
protected function notifyNodeChangeFileInfo(Node $node): void
@ -36,6 +36,6 @@ trait AppliedRectorCollectorTrait
return;
}
$this->appliedRectorCollector->addRectorClass(static::class, $fileInfo);
$this->rectorChangeCollector->addRectorClassWithLine(static::class, $fileInfo, $node->getLine());
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Rector\ChangesReporting\ValueObject;
final class RectorWithFileAndLineChange
{
/**
* @var string
*/
private $rectorClass;
/**
* @var int
*/
private $line;
/**
* @var string
*/
private $realPath;
public function __construct(string $rectorClass, string $realPath, int $line)
{
$this->rectorClass = $rectorClass;
$this->line = $line;
$this->realPath = $realPath;
}
public function getRectorClass(): string
{
return $this->rectorClass;
}
public function getLine(): int
{
return $this->line;
}
public function getRealPath(): string
{
return $this->realPath;
}
}

View File

@ -1,32 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Application;
use Symplify\SmartFileSystem\SmartFileInfo;
final class AppliedRectorCollector
{
/**
* @var string[][]
*/
private $rectorClassesByFile = [];
public function addRectorClass(string $rectorClass, SmartFileInfo $smartFileInfo): void
{
$this->rectorClassesByFile[$smartFileInfo->getRealPath()][] = $rectorClass;
}
/**
* @return string[]
*/
public function getRectorClasses(SmartFileInfo $smartFileInfo): array
{
if (! isset($this->rectorClassesByFile[$smartFileInfo->getRealPath()])) {
return [];
}
return array_unique($this->rectorClassesByFile[$smartFileInfo->getRealPath()]);
}
}

View File

@ -7,6 +7,7 @@ namespace Rector\Core\Application;
use OndraM\CiDetector\CiDetector;
use PHPStan\AnalysedCodeException;
use PHPStan\Analyser\NodeScopeResolver;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector;
use Rector\Core\Application\FileSystem\RemovedAndAddedFilesProcessor;
use Rector\Core\Configuration\Configuration;

View File

@ -6,7 +6,8 @@ namespace Rector\Core\Configuration;
use Jean85\PrettyVersions;
use Nette\Utils\Strings;
use Rector\Core\Console\Output\JsonOutputFormatter;
use Rector\ChangesReporting\Output\CheckstyleOutputFormatter;
use Rector\ChangesReporting\Output\JsonOutputFormatter;
use Rector\Core\Exception\Rector\RectorNotFoundOrNotValidRectorClassException;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Testing\PHPUnit\PHPUnitEnvironment;
@ -166,8 +167,14 @@ final class Configuration
private function canShowProgressBar(InputInterface $input): bool
{
$noProgressBar = (bool) $input->getOption(Option::OPTION_NO_PROGRESS_BAR);
if ($noProgressBar) {
return false;
}
return ! $noProgressBar && $input->getOption(Option::OPTION_OUTPUT_FORMAT) !== JsonOutputFormatter::NAME;
if ($input->getOption(Option::OPTION_OUTPUT_FORMAT) === JsonOutputFormatter::NAME) {
return false;
}
return $input->getOption(Option::OPTION_OUTPUT_FORMAT) !== CheckstyleOutputFormatter::NAME;
}
private function setOnlyRector(?string $rector): void

View File

@ -6,8 +6,9 @@ namespace Rector\Core\Console;
use Composer\XdebugHandler\XdebugHandler;
use Jean85\PrettyVersions;
use Rector\ChangesReporting\Output\CheckstyleOutputFormatter;
use Rector\ChangesReporting\Output\JsonOutputFormatter;
use Rector\Core\Configuration\Configuration;
use Rector\Core\Console\Output\JsonOutputFormatter;
use Rector\Core\Exception\Configuration\InvalidConfigurationException;
use Rector\Utils\DocumentationGenerator\Command\DumpNodesCommand;
use Rector\Utils\DocumentationGenerator\Command\DumpRectorsCommand;
@ -118,14 +119,28 @@ final class Application extends SymfonyApplication
private function shouldPrintMetaInformation(InputInterface $input): bool
{
$hasNoArguments = $input->getFirstArgument() === null;
if ($hasNoArguments) {
return false;
}
$hasVersionOption = $input->hasParameterOption('--version');
if ($hasVersionOption) {
return false;
}
$hasJsonOutput = (
$input->getParameterOption('--output-format') === JsonOutputFormatter::NAME ||
$input->getParameterOption('-o') === JsonOutputFormatter::NAME
);
if ($hasJsonOutput) {
return false;
}
return ! ($hasVersionOption || $hasNoArguments || $hasJsonOutput);
$hasCheckstyleOutput = (
$input->getParameterOption('--output-format') === CheckstyleOutputFormatter::NAME ||
$input->getParameterOption('-o') === CheckstyleOutputFormatter::NAME
);
return !$hasCheckstyleOutput;
}
private function removeUnusedOptions(InputDefinition $inputDefinition): void

View File

@ -4,12 +4,12 @@ declare(strict_types=1);
namespace Rector\Core\Console\Command;
use Rector\Core\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Output\ConsoleOutputFormatter;
use Rector\Core\Application\RectorApplication;
use Rector\Core\Autoloading\AdditionalAutoloader;
use Rector\Core\Configuration\Configuration;
use Rector\Core\Configuration\Option;
use Rector\Core\Console\Output\ConsoleOutputFormatter;
use Rector\Core\Console\Output\OutputFormatterCollector;
use Rector\Core\Console\Shell;
use Rector\Core\Extension\ReportingExtensionRunner;

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Rector\Core\Console\Output;
use Rector\Core\Contract\Console\Output\OutputFormatterInterface;
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
use Rector\Core\Exception\Console\Output\MissingOutputFormatterException;
final class OutputFormatterCollector

View File

@ -7,11 +7,12 @@ namespace Rector\Core\Rector\AbstractRector;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\ChangesReporting\Rector\AbstractRector\RectorChangeCollectorTrait;
use Rector\Doctrine\AbstractRector\DoctrineTrait;
trait AbstractRectorTrait
{
use AppliedRectorCollectorTrait;
use RectorChangeCollectorTrait;
use DoctrineTrait;
use NodeTypeResolverTrait;
use NameResolverTrait;

View File

@ -11,9 +11,9 @@ use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\CodingStyle\Application\NameImportingCommander;
use Rector\CodingStyle\Application\UseAddingCommander;
use Rector\Core\Application\AppliedRectorCollector;
use Rector\Core\PhpParser\Node\Commander\NodeAddingCommander;
use Rector\Core\PhpParser\Node\Commander\NodeRemovingCommander;
use Rector\Core\PhpParser\Node\Commander\NodeReplacingCommander;
@ -25,7 +25,7 @@ use Rector\PHPStan\Type\FullyQualifiedObjectType;
* This could be part of @see AbstractRector, but decopuling to trait
* makes clear what code has 1 purpose.
*
* @property-read AppliedRectorCollector $appliedRectorCollector
* @property-read RectorChangeCollector $rectorChangeCollector
*/
trait NodeCommandersTrait
{

View File

@ -17,7 +17,7 @@ use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocNode\JMS\JMSInjectTagValueNode;
use Rector\BetterPhpDocParser\PhpDocNode\PHPDI\PHPDIInjectTagValueNode;
use Rector\Core\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
use Rector\Core\Exception\NotImplementedException;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Rector\AbstractRector;

View File

@ -5,13 +5,13 @@ declare(strict_types=1);
namespace Rector\Core\Standalone;
use Psr\Container\ContainerInterface;
use Rector\Core\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Application\ErrorAndDiffCollector;
use Rector\ChangesReporting\Output\ConsoleOutputFormatter;
use Rector\Core\Application\RectorApplication;
use Rector\Core\Autoloading\AdditionalAutoloader;
use Rector\Core\Configuration\Configuration;
use Rector\Core\Configuration\Option;
use Rector\Core\Console\Command\ProcessCommand;
use Rector\Core\Console\Output\ConsoleOutputFormatter;
use Rector\Core\DependencyInjection\RectorContainerFactory;
use Rector\Core\Exception\FileSystem\FileNotFoundException;
use Rector\Core\Extension\FinishingExtensionRunner;

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Rector\Core\ValueObject\Reporting;
use Rector\ChangesReporting\ValueObject\RectorWithFileAndLineChange;
use Symplify\SmartFileSystem\SmartFileInfo;
final class FileDiff
@ -19,9 +20,9 @@ final class FileDiff
private $diffConsoleFormatted;
/**
* @var string[]
* @var RectorWithFileAndLineChange[]
*/
private $appliedRectorClasses = [];
private $rectorWithFileAndLineChanges = [];
/**
* @var SmartFileInfo
@ -29,17 +30,17 @@ final class FileDiff
private $smartFileInfo;
/**
* @param string[] $appliedRectorClasses
* @param RectorWithFileAndLineChange[] $rectorWithFileAndLineChanges
*/
public function __construct(
SmartFileInfo $smartFileInfo,
string $diff,
string $diffConsoleFormatted,
array $appliedRectorClasses = []
array $rectorWithFileAndLineChanges = []
) {
$this->smartFileInfo = $smartFileInfo;
$this->diff = $diff;
$this->appliedRectorClasses = $appliedRectorClasses;
$this->rectorWithFileAndLineChanges = $rectorWithFileAndLineChanges;
$this->diffConsoleFormatted = $diffConsoleFormatted;
}
@ -58,11 +59,28 @@ final class FileDiff
return $this->smartFileInfo->getRelativeFilePath();
}
/**
* @return RectorWithFileAndLineChange[]
*/
public function getRectorChanges(): array
{
return $this->rectorWithFileAndLineChanges;
}
/**
* @return string[]
*/
public function getAppliedRectorClasses(): array
public function getRectorClasses(): array
{
return $this->appliedRectorClasses;
$rectorClasses = [];
foreach ($this->rectorWithFileAndLineChanges as $rectorWithFileAndLineChange) {
$rectorClasses[] = $rectorWithFileAndLineChange->getRectorClass();
}
$rectorClasses = array_unique($rectorClasses);
sort($rectorClasses);
return $rectorClasses;
}
}