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

[TASK] Improve CLI output #211

Merged
merged 1 commit into from
Aug 26, 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
2 changes: 1 addition & 1 deletion e2e/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ do
echo
set -x

diff -u --color=auto $TEST_DIR/expected-output.txt $TEST_DIR/output.txt
diff -u --ignore-trailing-space --color=auto $TEST_DIR/expected-output.txt $TEST_DIR/output.txt
done
11 changes: 10 additions & 1 deletion e2e/typo3-typoscript/expected-output.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@

1 file with changes
===================

1) typo3-typoscript/result/cache-hash.typoscript

---------- begin diff ----------
@@ @@
page.10.value = Link to page 23
Expand All @@ -13,5 +19,8 @@
----------- end diff -----------

Applied rules:
RemoveUseCacheHashFromTypolinkTypoScriptFractor (https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/10.0/Deprecation-88406-SetCacheHashnoCacheHashOptionsInViewHelpersAndUriBuilder.html)
* RemoveUseCacheHashFromTypolinkTypoScriptFractor (https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/10.0/Deprecation-88406-SetCacheHashnoCacheHashOptionsInViewHelpersAndUriBuilder.html)


[OK] 1 file has been changed by Fractor

11 changes: 10 additions & 1 deletion e2e/typo3-yaml/expected-output.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@

1 file with changes
===================

1) typo3-yaml/result/my_form.form.yaml

---------- begin diff ----------
@@ @@
-
Expand Down Expand Up @@ -64,5 +70,8 @@
----------- end diff -----------

Applied rules:
EmailFinisherYamlFractor (https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/10.0/Feature-80420-AllowMultipleRecipientsInEmailFinisher.html)
* EmailFinisherYamlFractor (https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/10.0/Feature-80420-AllowMultipleRecipientsInEmailFinisher.html)


[OK] 1 file has been changed by Fractor

9 changes: 9 additions & 0 deletions packages/fractor/config/application.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

use a9f\Fractor\Application\Contract\FileProcessor;
use a9f\Fractor\Application\FractorRunner;
use a9f\Fractor\ChangesReporting\Contract\Output\OutputFormatterInterface;
use a9f\Fractor\Configuration\AllowedFileExtensionsResolver;
use a9f\Fractor\Configuration\SkipConfigurationFactory;
use a9f\Fractor\Configuration\ValueObject\SkipConfiguration;
use a9f\Fractor\Console\Output\OutputFormatterCollector;
use a9f\Fractor\Differ\ConsoleDiffer;
use a9f\Fractor\Differ\Contract\Differ;
use a9f\Fractor\FractorApplication;
Expand Down Expand Up @@ -88,6 +90,13 @@ static function (ChildDefinition $definition, AsCommand $attribute): void {
$services->set(SkipConfiguration::class)->factory([service(SkipConfigurationFactory::class), 'create']);
$services->set(FractorRunner::class)->arg('$processors', tagged_iterator('fractor.file_processor'));
$services->set(AllowedFileExtensionsResolver::class)->arg('$processors', tagged_iterator('fractor.file_processor'));
$services->set(OutputFormatterCollector::class)->arg(
'$outputFormatters',
tagged_iterator('fractor.output_formatter')
);
$services->set(Filesystem::class);
$containerBuilder->registerForAutoconfiguration(FileProcessor::class)->addTag('fractor.file_processor');
$containerBuilder->registerForAutoconfiguration(OutputFormatterInterface::class)->addTag(
'fractor.output_formatter'
);
};
30 changes: 15 additions & 15 deletions packages/fractor/src/Application/FractorRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
use a9f\Fractor\Application\ValueObject\File;
use a9f\Fractor\Configuration\ValueObject\Configuration;
use a9f\Fractor\Console\Contract\Output;
use a9f\Fractor\Differ\ValueObject\FileDiff;
use a9f\Fractor\Differ\ValueObjectFactory\FileDiffFactory;
use a9f\Fractor\FileSystem\FilesFinder;
use a9f\Fractor\Reporting\FractorsChangelogLinesResolver;
use a9f\Fractor\ValueObject\FileProcessResult;
use a9f\Fractor\ValueObject\ProcessResult;
use Nette\Utils\FileSystem;
use Webmozart\Assert\Assert;

Expand All @@ -26,7 +28,6 @@
* @param iterable<FileProcessor<FractorRule>> $processors
*/
public function __construct(
private FractorsChangelogLinesResolver $fractorsChangelogLinesResolver,
private FilesFinder $fileFinder,
private FilesCollector $fileCollector,
private iterable $processors,
Expand All @@ -37,14 +38,17 @@ public function __construct(
Assert::allIsInstanceOf($this->processors, FileProcessor::class);
}

public function run(Output $output, Configuration $configuration): void
public function run(Output $output, Configuration $configuration): ProcessResult
{
$filePaths = $this->fileFinder->findFiles($configuration->getPaths(), $configuration->getFileExtensions());

if (! $configuration->isQuiet()) {
$output->progressStart(count($filePaths));
}

/** @var FileDiff[] $fileDiffs */
$fileDiffs = [];

foreach ($filePaths as $filePath) {
$file = new File($filePath, FileSystem::read($filePath));
$this->fileCollector->addFile($file);
Expand All @@ -67,6 +71,12 @@ public function run(Output $output, Configuration $configuration): void
}

$file->setFileDiff($this->fileDiffFactory->createFileDiff($file));

$fileProcessResult = new FileProcessResult($file->getFileDiff());
$currentFileDiff = $fileProcessResult->getFileDiff();
if ($currentFileDiff instanceof FileDiff) {
$fileDiffs[] = $currentFileDiff;
}
}

if (! $configuration->isQuiet()) {
Expand All @@ -78,24 +88,14 @@ public function run(Output $output, Configuration $configuration): void
continue;
}

if (! $configuration->isQuiet()) {
$output->write($file->getFileDiff()->getDiffConsoleFormatted());
if ($file->getAppliedRules() !== []) {
$fractorsChangelogsLines = $this->fractorsChangelogLinesResolver->createFractorChangelogLines(
$file->getAppliedRules()
);
$output->write('<options=underscore>Applied rules:</>');
$output->listing($fractorsChangelogsLines);
$output->newLine();
}
}

if ($configuration->isDryRun()) {
continue;
}

$this->fileWriter->write($file);
}

return new ProcessResult($fileDiffs);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace a9f\Fractor\ChangesReporting\Contract\Output;

use a9f\Fractor\Configuration\ValueObject\Configuration;
use a9f\Fractor\ValueObject\ProcessResult;
use Symfony\Component\Console\Style\SymfonyStyle;

interface OutputFormatterInterface
{
public function getName(): string;

public function report(ProcessResult $processResult, Configuration $configuration): void;

public function setSymfonyStyle(SymfonyStyle $symfonyStyle): void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);

namespace a9f\Fractor\ChangesReporting\Output;

use a9f\Fractor\ChangesReporting\Contract\Output\OutputFormatterInterface;
use a9f\Fractor\Configuration\ValueObject\Configuration;
use a9f\Fractor\Differ\ValueObject\FileDiff;
use a9f\Fractor\ValueObject\ProcessResult;
use Symfony\Component\Console\Style\SymfonyStyle;

class ConsoleOutputFormatter implements OutputFormatterInterface
{
/**
* @var string
*/
public const NAME = 'console';

/**
* @readonly
*/
private SymfonyStyle $symfonyStyle;

public function setSymfonyStyle(SymfonyStyle $symfonyStyle): void
{
$this->symfonyStyle = $symfonyStyle;
}

public function getName(): string
{
return self::NAME;
}

public function report(ProcessResult $processResult, Configuration $configuration): void
{
$this->reportFileDiffs($processResult->getFileDiffs(), false);

// to keep space between progress bar and success message
if ($processResult->getFileDiffs() === []) {
$this->symfonyStyle->newLine();
}

$message = $this->createSuccessMessage($processResult, $configuration);
$this->symfonyStyle->success($message);
}

/**
* @param FileDiff[] $fileDiffs
*/
private function reportFileDiffs(array $fileDiffs, bool $absoluteFilePath): void
{
if (\count($fileDiffs) <= 0) {
return;
}
// normalize
\ksort($fileDiffs);
$message = \sprintf('%d file%s with changes', \count($fileDiffs), \count($fileDiffs) === 1 ? '' : 's');
$this->symfonyStyle->title($message);

$i = 0;
foreach ($fileDiffs as $fileDiff) {
$filePath = $absoluteFilePath ? $fileDiff->getAbsoluteFilePath() ?? '' : $fileDiff->getRelativeFilePath();
$message = \sprintf('<options=bold>%d) %s</>', ++$i, $filePath);
$this->symfonyStyle->writeln($message);
$this->symfonyStyle->newLine();
$this->symfonyStyle->writeln($fileDiff->getDiffConsoleFormatted());

if ($fileDiff->getAppliedRules() !== []) {
$this->symfonyStyle->writeln('<options=underscore>Applied rules:</>');
$this->symfonyStyle->listing($fileDiff->getAppliedRules());
$this->symfonyStyle->newLine();
}
}
}

private function createSuccessMessage(ProcessResult $processResult, Configuration $configuration): string
{
$changeCount = \count($processResult->getFileDiffs());
if ($changeCount === 0) {
return 'Fractor is done!';
}
return \sprintf(
'%d file%s %s by Fractor',
$changeCount,
$changeCount > 1 ? 's' : '',
$configuration->isDryRun()
? 'would have been changed (dry-run)'
: ($changeCount === 1 ? 'has' : 'have') . ' been changed'
);
}
}
33 changes: 30 additions & 3 deletions packages/fractor/src/Console/Command/ProcessCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@
use a9f\Fractor\Application\FractorRunner;
use a9f\Fractor\Configuration\ConfigurationFactory;
use a9f\Fractor\Configuration\Option;
use a9f\Fractor\Configuration\ValueObject\Configuration;
use a9f\Fractor\Console\ExitCode;
use a9f\Fractor\Console\Output\OutputFormatterCollector;
use a9f\Fractor\Console\Output\SymfonyConsoleOutput;
use a9f\Fractor\ValueObject\ProcessResult;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(name: 'process', description: 'Runs Fractor with the given configuration file')]
final class ProcessCommand extends Command
{
public function __construct(
private readonly FractorRunner $runner,
private readonly ConfigurationFactory $configurationFactory
private readonly ConfigurationFactory $configurationFactory,
private readonly OutputFormatterCollector $outputFormatterCollector
) {
parent::__construct();
}
Expand Down Expand Up @@ -49,8 +55,29 @@ protected function configure(): void

protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->runner->run(new SymfonyConsoleOutput($output), $this->configurationFactory->createFromInput($input));
$configuration = $this->configurationFactory->createFromInput($input);
$processResult = $this->runner->run(new SymfonyConsoleOutput($output), $configuration);

return Command::SUCCESS;
$outputFormat = 'console';
$outputFormatter = $this->outputFormatterCollector->getByName($outputFormat);
$outputFormatter->setSymfonyStyle(new SymfonyStyle($input, $output));
$outputFormatter->report($processResult, $configuration);

return $this->resolveReturnCode($processResult, $configuration);
}

/**
* @return ExitCode::*
*/
private function resolveReturnCode(ProcessResult $processResult, Configuration $configuration): int
{
// inverse error code for CI dry-run
if (! $configuration->isDryRun()) {
return ExitCode::SUCCESS;
}
if ($processResult->getFileDiffs() !== []) {
return ExitCode::CHANGED_CODE;
}
return ExitCode::SUCCESS;
}
}
17 changes: 17 additions & 0 deletions packages/fractor/src/Console/ExitCode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace a9f\Fractor\Console;

use Symfony\Component\Console\Command\Command;

final class ExitCode
{
public const SUCCESS = Command::SUCCESS;

/**
* @var int
*/
public const CHANGED_CODE = 2;
}
45 changes: 45 additions & 0 deletions packages/fractor/src/Console/Output/OutputFormatterCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace a9f\Fractor\Console\Output;

use a9f\Fractor\ChangesReporting\Contract\Output\OutputFormatterInterface;
use a9f\Fractor\Exception\Configuration\InvalidConfigurationException;

final class OutputFormatterCollector
{
/**
* @var array<string, OutputFormatterInterface>
*/
private array $outputFormatters = [];

/**
* @param OutputFormatterInterface[] $outputFormatters
*/
public function __construct(iterable $outputFormatters)
{
foreach ($outputFormatters as $outputFormatter) {
$this->outputFormatters[$outputFormatter->getName()] = $outputFormatter;
}
}

public function getByName(string $name): OutputFormatterInterface
{
$this->ensureOutputFormatExists($name);
return $this->outputFormatters[$name];
}

private function ensureOutputFormatExists(string $name): void
{
if (isset($this->outputFormatters[$name])) {
return;
}
$outputFormatterNames = \array_keys($this->outputFormatters);
throw new InvalidConfigurationException(\sprintf(
'Output formatter "%s" was not found. Pick one of "%s".',
$name,
\implode('", "', $outputFormatterNames)
));
}
}
Loading