Skip to content
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
69 changes: 51 additions & 18 deletions src/CLI/Command/Check.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Arkitect\CLI\Command;

use Arkitect\CLI\Config;
use Arkitect\CLI\Printer\Printer;
use Arkitect\CLI\Progress\DebugProgress;
use Arkitect\CLI\Progress\ProgressBarProgress;
use Arkitect\CLI\Runner;
Expand All @@ -26,6 +27,7 @@ class Check extends Command
private const USE_BASELINE_PARAM = 'use-baseline';
private const SKIP_BASELINE_PARAM = 'skip-baseline';
private const IGNORE_BASELINE_LINENUMBERS_PARAM = 'ignore-baseline-linenumbers';
private const FORMAT_PARAM = 'format';

private const GENERATE_BASELINE_PARAM = 'generate-baseline';
private const DEFAULT_RULES_FILENAME = 'phparkitect.php';
Expand Down Expand Up @@ -87,6 +89,13 @@ protected function configure(): void
'i',
InputOption::VALUE_NONE,
'Ignore line numbers when checking the baseline'
)
->addOption(
self::FORMAT_PARAM,
'f',
InputOption::VALUE_OPTIONAL,
'Output format: json or text (default)',
'text'
);
}

Expand All @@ -102,6 +111,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$useBaseline = (string) $input->getOption(self::USE_BASELINE_PARAM);
$skipBaseline = (bool) $input->getOption(self::SKIP_BASELINE_PARAM);
$ignoreBaselineLinenumbers = (bool) $input->getOption(self::IGNORE_BASELINE_LINENUMBERS_PARAM);
$format = $input->getOption(self::FORMAT_PARAM);
$onlyErrors = Printer::FORMAT_JSON === $format;

if (true !== $skipBaseline && !$useBaseline && file_exists(self::DEFAULT_BASELINE_FILENAME)) {
$useBaseline = self::DEFAULT_BASELINE_FILENAME;
Expand All @@ -112,7 +123,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int

return self::ERROR_CODE;
}
$output->writeln('<info>Baseline found: '.$useBaseline.'</info>');

if (!$onlyErrors) {
$output->writeln('<info>Baseline found: '.$useBaseline.'</info>');
}

$generateBaseline = $input->getOption(self::GENERATE_BASELINE_PARAM);

Expand All @@ -122,18 +136,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$progress = $verbose ? new DebugProgress($output) : new ProgressBarProgress($output);

$this->printHeadingLine($output);
if (!$onlyErrors) {
$this->printHeadingLine($output);
}

$rulesFilename = $this->getConfigFilename($input);
$output->writeln(sprintf("Config file: %s\n", $rulesFilename));
if (!$onlyErrors) {
$output->writeln(sprintf("Config file: %s\n", $rulesFilename));
}

$config = new Config();

$this->readRules($config, $rulesFilename);

$runner = new Runner($stopOnFailure);
try {
$runner->run($config, $progress, $targetPhpVersion);
$runner->run($config, $progress, $targetPhpVersion, $onlyErrors);
} catch (FailOnFirstViolationException $e) {
}
$violations = $runner->getViolations();
Expand All @@ -146,7 +164,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$this->saveBaseline($generateBaseline, $violations);

$output->writeln('<info>Baseline file \''.$generateBaseline.'\'created!</info>');
$this->printExecutionTime($output, $startTime);
if (!$onlyErrors) {
$this->printExecutionTime($output, $startTime);
}

return self::SUCCESS_CODE;
}
Expand All @@ -158,15 +178,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}

if ($violations->count() > 0) {
$this->printViolations($violations, $output);
$this->printExecutionTime($output, $startTime);
$this->printViolations($violations, $output, $format, $onlyErrors);
if (!$onlyErrors) {
$this->printExecutionTime($output, $startTime);
}

return self::ERROR_CODE;
}

$parsedErrors = $runner->getParsingErrors();
if ($parsedErrors->count() > 0) {
$this->printParsedErrors($parsedErrors, $output);
$this->printParsedErrors($parsedErrors, $output, $onlyErrors);
$this->printExecutionTime($output, $startTime);

return self::ERROR_CODE;
Expand All @@ -178,8 +200,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return self::ERROR_CODE;
}

$this->printNoViolationsDetectedMessage($output);
$this->printExecutionTime($output, $startTime);
$this->printNoViolationsDetectedMessage($output, $onlyErrors);

if (!$onlyErrors) {
$this->printExecutionTime($output, $startTime);
}

return self::SUCCESS_CODE;
}
Expand Down Expand Up @@ -236,21 +261,29 @@ private function getConfigFilename(InputInterface $input): string
return $filename;
}

private function printViolations(Violations $violations, OutputInterface $output): void
private function printViolations(Violations $violations, OutputInterface $output, string $format, bool $onlyErrors = false): void
{
$output->writeln('<error>ERRORS!</error>');
$output->writeln(sprintf('%s', $violations->toString()));
$output->writeln(sprintf('<error>%s VIOLATIONS DETECTED!</error>', \count($violations)));
if (!$onlyErrors) {
$output->writeln('<error>ERRORS!</error>');
}
$output->writeln(sprintf('%s', $violations->toString($format)));
if (!$onlyErrors) {
$output->writeln(sprintf('<error>%s VIOLATIONS DETECTED!</error>', \count($violations)));
}
}

private function printParsedErrors(ParsingErrors $parsingErrors, OutputInterface $output): void
private function printParsedErrors(ParsingErrors $parsingErrors, OutputInterface $output, bool $onlyErrors = false): void
{
$output->writeln('<error>ERROR ON PARSING THESE FILES:</error>');
if (!$onlyErrors) {
$output->writeln('<error>ERROR ON PARSING THESE FILES:</error>');
}
$output->writeln(sprintf('%s', $parsingErrors->toString()));
}

private function printNoViolationsDetectedMessage(OutputInterface $output): void
private function printNoViolationsDetectedMessage(OutputInterface $output, bool $onlyErrors = false): void
{
$output->writeln('<info>NO VIOLATIONS DETECTED!</info>');
if (!$onlyErrors) {
$output->writeln('<info>NO VIOLATIONS DETECTED!</info>');
}
}
}
41 changes: 41 additions & 0 deletions src/CLI/Printer/JsonPrinter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);

namespace Arkitect\CLI\Printer;

use Arkitect\Rules\Violation;

class JsonPrinter implements Printer
{
public function print(array $violationsCollection): string
{
$totalViolations = 0;
$details = [];

/**
* @var string $key
* @var Violation[] $violationsByFqcn
*/
foreach ($violationsCollection as $class => $violationsByFqcn) {
$violationForThisFqcn = \count($violationsByFqcn);
$totalViolations += $violationForThisFqcn;

$details[$class] = [];

foreach ($violationsByFqcn as $key => $violation) {
$details[$class][$key]['error'] = $violation->getError();

if (null !== $violation->getLine()) {
$details[$class][$key]['line'] = $violation->getLine();
}
}
}

$errors = [
'totalViolations' => $totalViolations,
'details' => $details,
];

return json_encode($errors);
}
}
13 changes: 13 additions & 0 deletions src/CLI/Printer/Printer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);

namespace Arkitect\CLI\Printer;

interface Printer
{
public const FORMAT_TEXT = 'text';

public const FORMAT_JSON = 'json';

public function print(array $violationsCollection): string;
}
17 changes: 17 additions & 0 deletions src/CLI/Printer/PrinterFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);

namespace Arkitect\CLI\Printer;

final class PrinterFactory
{
public function create(string $format): Printer
{
switch ($format) {
case 'json':
return new JsonPrinter();
default:
return new TextPrinter();
}
}
}
34 changes: 34 additions & 0 deletions src/CLI/Printer/TextPrinter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);

namespace Arkitect\CLI\Printer;

use Arkitect\Rules\Violation;

class TextPrinter implements Printer
{
public function print(array $violationsCollection): string
{
$errors = '';

/**
* @var string $key
* @var Violation[] $violationsByFqcn
*/
foreach ($violationsCollection as $key => $violationsByFqcn) {
$violationForThisFqcn = \count($violationsByFqcn);
$errors .= "\n$key has {$violationForThisFqcn} violations";

foreach ($violationsByFqcn as $violation) {
$errors .= "\n ".$violation->getError();

if (null !== $violation->getLine()) {
$errors .= ' (on line '.$violation->getLine().')';
}
}
$errors .= "\n";
}

return $errors;
}
}
24 changes: 16 additions & 8 deletions src/CLI/Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,22 @@ public function __construct(bool $stopOnFailure = false)
$this->parsingErrors = new ParsingErrors();
}

public function run(Config $config, Progress $progress, TargetPhpVersion $targetPhpVersion): void
public function run(Config $config, Progress $progress, TargetPhpVersion $targetPhpVersion, bool $onlyErrors): void
{
/** @var FileParser $fileParser */
$fileParser = FileParserFactory::createFileParser($targetPhpVersion, $config->isParseCustomAnnotationsEnabled());

/** @var ClassSetRules $classSetRule */
foreach ($config->getClassSetRules() as $classSetRule) {
$progress->startFileSetAnalysis($classSetRule->getClassSet());
if (!$onlyErrors) {
$progress->startFileSetAnalysis($classSetRule->getClassSet());
}

$this->check($classSetRule, $progress, $fileParser, $this->violations, $this->parsingErrors);
$this->check($classSetRule, $progress, $fileParser, $this->violations, $this->parsingErrors, $onlyErrors);

$progress->endFileSetAnalysis($classSetRule->getClassSet());
if (!$onlyErrors) {
$progress->endFileSetAnalysis($classSetRule->getClassSet());
}
}
}

Expand All @@ -48,11 +52,14 @@ public function check(
Progress $progress,
Parser $fileParser,
Violations $violations,
ParsingErrors $parsingErrors
ParsingErrors $parsingErrors,
bool $onlyErrors = false
): void {
/** @var SplFileInfo $file */
foreach ($classSetRule->getClassSet() as $file) {
$progress->startParsingFile($file->getRelativePathname());
if (!$onlyErrors) {
$progress->startParsingFile($file->getRelativePathname());
}

$fileParser->parse($file->getContents(), $file->getRelativePathname());
$parsedErrors = $fileParser->getParsingErrors();
Expand All @@ -67,8 +74,9 @@ public function check(
$rule->check($classDescription, $violations);
}
}

$progress->endParsingFile($file->getRelativePathname());
if (!$onlyErrors) {
$progress->endParsingFile($file->getRelativePathname());
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/PHPUnit/ArchRuleCheckerConstraintAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Arkitect\Analyzer\FileParserFactory;
use Arkitect\ClassSet;
use Arkitect\ClassSetRules;
use Arkitect\CLI\Printer\Printer;
use Arkitect\CLI\Progress\VoidProgress;
use Arkitect\CLI\Runner;
use Arkitect\CLI\TargetPhpVersion;
Expand Down Expand Up @@ -78,6 +79,6 @@ protected function failureDescription($other): string
return "\n".$this->parsingErrors->toString();
}

return "\n".$this->violations->toString();
return "\n".$this->violations->toString(Printer::FORMAT_TEXT);
}
}
26 changes: 4 additions & 22 deletions src/Rules/Violations.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Arkitect\Rules;

use Arkitect\CLI\Printer\PrinterFactory;
use Arkitect\Exceptions\FailOnFirstViolationException;
use Arkitect\Exceptions\IndexNotFoundException;

Expand Down Expand Up @@ -79,30 +80,11 @@ public function groupedByFqcn(): array
}, []);
}

public function toString(): string
public function toString(string $format): string
{
$errors = '';
$violationsCollection = $this->groupedByFqcn();

/**
* @var string $key
* @var Violation[] $violationsByFqcn
*/
foreach ($violationsCollection as $key => $violationsByFqcn) {
$violationForThisFqcn = \count($violationsByFqcn);
$errors .= "\n$key has {$violationForThisFqcn} violations";

foreach ($violationsByFqcn as $violation) {
$errors .= "\n ".$violation->getError();

if (null !== $violation->getLine()) {
$errors .= ' (on line '.$violation->getLine().')';
}
}
$errors .= "\n";
}
$printer = (new PrinterFactory())->create($format);

return $errors;
return $printer->print($this->groupedByFqcn());
}

public function toArray(): array
Expand Down
Loading