Skip to content

Commit

Permalink
Allow to implement custom reporters
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet committed Nov 22, 2023
1 parent e5be674 commit 7780aac
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 46 deletions.
15 changes: 12 additions & 3 deletions src/Command/TwigCsFixerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
use TwigCsFixer\Config\ConfigResolver;
use TwigCsFixer\Environment\StubbedEnvironment;
use TwigCsFixer\Exception\CannotResolveConfigException;
use TwigCsFixer\Report\Reporter\TextReporter;
use TwigCsFixer\Report\Report;
use TwigCsFixer\Report\TextFormatter;
use TwigCsFixer\Report\ReporterFactory;
use TwigCsFixer\Runner\Fixer;
use TwigCsFixer\Runner\Linter;
use TwigCsFixer\Token\Tokenizer;
Expand Down Expand Up @@ -50,6 +51,13 @@ protected function configure(): void
InputOption::VALUE_REQUIRED,
'Path to a `.twig-cs-fixer.php` config file'
),
new InputOption(
'report',
'r',
InputOption::VALUE_REQUIRED,
'Report format',
TextReporter::NAME
),
new InputOption(
'fix',
'f',
Expand Down Expand Up @@ -119,8 +127,9 @@ private function runLinter(Config $config, InputInterface $input, OutputInterfac
$input->getOption('fix') ? new Fixer($tokenizer) : null
);

$reporter = new TextFormatter($input, $output);
$reporter->display($report, $input->getOption('level'));
$reporterFactory = new ReporterFactory();
$reporter = $reporterFactory->getReporter($input->getOption('report'));
$reporter->display($output, $report, $input->getOption('level'));

return $report;
}
Expand Down
18 changes: 18 additions & 0 deletions src/Report/Reporter/NullReporter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace TwigCsFixer\Report\Reporter;

use Symfony\Component\Console\Output\OutputInterface;
use TwigCsFixer\Report\Report;

/**
* Reporter without output.
*/
final class NullReporter implements ReporterInterface
{
public const NAME = 'null';

public function display(OutputInterface $output, Report $report, ?string $level = null): void
{
}
}
11 changes: 11 additions & 0 deletions src/Report/Reporter/ReporterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace TwigCsFixer\Report\Reporter;

use Symfony\Component\Console\Output\OutputInterface;
use TwigCsFixer\Report\Report;

interface ReporterInterface
{
public function display(OutputInterface $output, Report $report, ?string $level = null): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,43 @@

declare(strict_types=1);

namespace TwigCsFixer\Report;
namespace TwigCsFixer\Report\Reporter;

use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use TwigCsFixer\Report\Report;
use TwigCsFixer\Report\SniffViolation;

/**
* Human-readable output with context.
*/
final class TextFormatter
final class TextReporter implements ReporterInterface
{
public const NAME = 'text';

private const ERROR_CURSOR_CHAR = '>>';
private const ERROR_LINE_FORMAT = '%-5s| %s';
private const ERROR_LINE_WIDTH = 120;

private SymfonyStyle $io;

public function __construct(InputInterface $input, OutputInterface $output)
public function display(OutputInterface $output, Report $report, ?string $level = null): void
{
$this->io = new SymfonyStyle($input, $output);
}
$io = new SymfonyStyle(new ArrayInput([]), $output);

public function display(Report $report, ?string $level = null): void
{
if (
$this->io->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE
$io->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE
&& [] !== $report->getFixedFiles()
) {
$this->io->text('Changed:');
$this->io->listing($report->getFixedFiles());
$io->text('Changed:');
$io->listing($report->getFixedFiles());
}

foreach ($report->getFiles() as $file) {
$fileMessages = $report->getMessages($file, $level);
if (\count($fileMessages) > 0) {
$this->io->text(sprintf('<fg=red>KO</fg=red> %s', $file));
$io->text(sprintf('<fg=red>KO</fg=red> %s', $file));
}

$content = @file_get_contents($file);
Expand Down Expand Up @@ -77,7 +76,7 @@ public function display(Report $report, ?string $level = null): void
}

if (\count($rows) > 0) {
$this->io->table([], $rows);
$io->table([], $rows);
}
}

Expand All @@ -90,11 +89,11 @@ public function display(Report $report, ?string $level = null): void
);

if (0 < $report->getTotalErrors()) {
$this->io->error($summaryString);
$io->error($summaryString);
} elseif (0 < $report->getTotalWarnings()) {
$this->io->warning($summaryString);
$io->warning($summaryString);
} else {
$this->io->success($summaryString);
$io->success($summaryString);
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/Report/ReporterFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace TwigCsFixer\Report;

use InvalidArgumentException;
use TwigCsFixer\Report\Reporter\NullReporter;
use TwigCsFixer\Report\Reporter\ReporterInterface;
use TwigCsFixer\Report\Reporter\TextReporter;

final class ReporterFactory
{
public function getReporter(?string $format = TextReporter::NAME): ReporterInterface
{
return match ($format) {
NullReporter::NAME => new NullReporter(),
TextReporter::NAME => new TextReporter(),
default => throw new InvalidArgumentException(
sprintf('No reporter supports the format "%s".', $format)

Check failure on line 20 in src/Report/ReporterFactory.php

View workflow job for this annotation

GitHub Actions / Psalm

PossiblyNullArgument

src/Report/ReporterFactory.php:20:66: PossiblyNullArgument: Argument 2 of sprintf cannot be null, possibly null value provided (see https://psalm.dev/078)
),
};
}
}
15 changes: 15 additions & 0 deletions tests/Command/TwigCsFixerCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ public function testExecuteWithReportErrorsFixedVerbose(): void
static::assertSame(Command::FAILURE, $commandTester->getStatusCode());
}

public function testExecuteWithReportOption(): void
{
$command = new TwigCsFixerCommand();

$commandTester = new CommandTester($command);
$commandTester->execute([
'paths' => [$this->getTmpPath(__DIR__.'/Fixtures/file.twig')],
'--no-cache' => true, // To avoid cache output
'--report' => 'null',
]);

static::assertSame('', $commandTester->getDisplay());
static::assertSame(Command::SUCCESS, $commandTester->getStatusCode());
}

public function testExecuteWithConfig(): void
{
$command = new TwigCsFixerCommand();
Expand Down
File renamed without changes.
File renamed without changes.
54 changes: 54 additions & 0 deletions tests/Report/Formatter/NullReporterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace TwigCsFixer\Tests\Report\Formatter;

use PHPUnit\Framework\TestCase;
use SplFileInfo;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use TwigCsFixer\Report\Reporter\NullReporter;
use TwigCsFixer\Report\Report;
use TwigCsFixer\Report\SniffViolation;

final class NullReporterTest extends TestCase
{
/**
* @dataProvider displayDataProvider
*/
public function testDisplayErrors(?string $level): void
{
$textFormatter = new NullReporter();

$file = __DIR__.'/Fixtures/file.twig';
$report = new Report([new SplFileInfo($file)]);

$violation0 = new SniffViolation(SniffViolation::LEVEL_NOTICE, 'Notice', $file, 1);
$report->addMessage($violation0);
$violation1 = new SniffViolation(SniffViolation::LEVEL_WARNING, 'Warning', $file, 2);
$report->addMessage($violation1);
$violation2 = new SniffViolation(SniffViolation::LEVEL_ERROR, 'Error', $file, 3);
$report->addMessage($violation2);
$violation3 = new SniffViolation(SniffViolation::LEVEL_FATAL, 'Fatal', $file);
$report->addMessage($violation3);

$output = new BufferedOutput(OutputInterface::VERBOSITY_NORMAL, true);
$textFormatter->display($output, $report, $level);

$text = $output->fetch();
static::assertSame('', $text);
}

/**
* @return iterable<array-key, array{string|null}>
*/
public static function displayDataProvider(): iterable
{
yield [null];
yield [Report::MESSAGE_TYPE_NOTICE];
yield [Report::MESSAGE_TYPE_WARNING];
yield [Report::MESSAGE_TYPE_ERROR];
yield [Report::MESSAGE_TYPE_FATAL];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,24 @@

declare(strict_types=1);

namespace TwigCsFixer\Tests\Report;
namespace TwigCsFixer\Tests\Report\Formatter;

use PHPUnit\Framework\TestCase;
use SplFileInfo;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Output\OutputInterface;
use TwigCsFixer\Report\Reporter\TextReporter;
use TwigCsFixer\Report\Report;
use TwigCsFixer\Report\SniffViolation;
use TwigCsFixer\Report\TextFormatter;

final class TextFormatterTest extends TestCase
final class TextReporterTest extends TestCase
{
/**
* @dataProvider displayDataProvider
*/
public function testDisplayErrors(string $expected, ?string $level): void
{
$input = new ArrayInput([]);
$output = new BufferedOutput(Output::VERBOSITY_NORMAL, true);
$textFormatter = new TextFormatter($input, $output);
$textFormatter = new TextReporter();

$file = __DIR__.'/Fixtures/file.twig';
$report = new Report([new SplFileInfo($file)]);
Expand All @@ -36,7 +33,8 @@ public function testDisplayErrors(string $expected, ?string $level): void
$violation3 = new SniffViolation(SniffViolation::LEVEL_FATAL, 'Fatal', $file);
$report->addMessage($violation3);

$textFormatter->display($report, $level);
$output = new BufferedOutput(OutputInterface::VERBOSITY_NORMAL, true);
$textFormatter->display($output, $report, $level);

$text = $output->fetch();
static::assertStringContainsString($expected, $text);
Expand Down Expand Up @@ -96,14 +94,13 @@ public static function displayDataProvider(): iterable

public function testDisplaySuccess(): void
{
$input = new ArrayInput([]);
$output = new BufferedOutput();
$textFormatter = new TextFormatter($input, $output);
$textFormatter = new TextReporter();

$file = __DIR__.'/Fixtures/file.twig';
$report = new Report([new SplFileInfo($file)]);

$textFormatter->display($report);
$output = new BufferedOutput();
$textFormatter->display($output, $report);

$text = $output->fetch();
static::assertStringNotContainsString(sprintf('KO %s/Fixtures/file.twig', __DIR__), $text);
Expand All @@ -112,9 +109,7 @@ public function testDisplaySuccess(): void

public function testDisplayMultipleFiles(): void
{
$input = new ArrayInput([]);
$output = new BufferedOutput();
$textFormatter = new TextFormatter($input, $output);
$textFormatter = new TextReporter();

$file = __DIR__.'/Fixtures/file.twig';
$file2 = __DIR__.'/Fixtures/file2.twig';
Expand All @@ -123,7 +118,8 @@ public function testDisplayMultipleFiles(): void
$violation = new SniffViolation(SniffViolation::LEVEL_ERROR, 'Error', $file, 3);
$report->addMessage($violation);

$textFormatter->display($report);
$output = new BufferedOutput();
$textFormatter->display($output, $report);

static::assertStringContainsString(
sprintf(
Expand All @@ -146,17 +142,16 @@ public function testDisplayMultipleFiles(): void

public function testDisplayNotFoundFile(): void
{
$input = new ArrayInput([]);
$output = new BufferedOutput();
$textFormatter = new TextFormatter($input, $output);
$textFormatter = new TextReporter();

$file = __DIR__.'/Fixtures/fileNotFound.twig';

$report = new Report([new SplFileInfo($file)]);
$violation = new SniffViolation(SniffViolation::LEVEL_ERROR, 'Error', $file, 1);
$report->addMessage($violation);

$textFormatter->display($report);
$output = new BufferedOutput();
$textFormatter->display($output, $report);

static::assertStringContainsString(
sprintf(
Expand All @@ -177,17 +172,16 @@ public function testDisplayNotFoundFile(): void
*/
public function testDisplayBlock(string $expected, int $level): void
{
$input = new ArrayInput([]);
$output = new BufferedOutput(Output::VERBOSITY_NORMAL, true);
$textFormatter = new TextFormatter($input, $output);
$textFormatter = new TextReporter();

$file = __DIR__.'/Fixtures/file.twig';
$report = new Report([new SplFileInfo($file)]);

$violation = new SniffViolation($level, 'Message', $file, 1);
$report->addMessage($violation);

$textFormatter->display($report);
$output = new BufferedOutput(OutputInterface::VERBOSITY_NORMAL, true);
$textFormatter->display($output, $report);

$text = $output->fetch();
static::assertStringContainsString($expected, $text);
Expand Down
Loading

0 comments on commit 7780aac

Please sign in to comment.