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
25 changes: 15 additions & 10 deletions src/CLI/Baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,30 @@ public function applyTo(Violations $violations, bool $ignoreBaselineLinenumbers)
$violations->remove($this->violations, $ignoreBaselineLinenumbers);
}

/**
* @psalm-suppress RiskyTruthyFalsyComparison
*/
public static function resolveFilePath(?string $filePath, string $defaultFilePath): ?string
{
if (!$filePath && file_exists($defaultFilePath)) {
$filePath = $defaultFilePath;
}

return $filePath ?: null;
}

public static function empty(): self
{
return new self(new Violations(), '');
}

/**
* @psalm-suppress RiskyTruthyFalsyComparison
*/
public static function create(bool $skipBaseline, ?string $baselineFilePath, string $defaultFilePath): self
public static function create(bool $skipBaseline, ?string $baselineFilePath): self
{
if ($skipBaseline) {
if ($skipBaseline || null === $baselineFilePath) {
return self::empty();
}

if (!$baselineFilePath && file_exists($defaultFilePath)) {
$baselineFilePath = $defaultFilePath;
}

return $baselineFilePath ? self::loadFromFile($baselineFilePath) : self::empty();
return self::loadFromFile($baselineFilePath);
}

public static function loadFromFile(string $filename): self
Expand Down
73 changes: 23 additions & 50 deletions src/CLI/Command/Check.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,17 @@
namespace Arkitect\CLI\Command;

use Arkitect\CLI\Baseline;
use Arkitect\CLI\Config;
use Arkitect\CLI\ConfigBuilder;
use Arkitect\CLI\Printer\PrinterFactory;
use Arkitect\CLI\Progress\DebugProgress;
use Arkitect\CLI\Progress\ProgressBarProgress;
use Arkitect\CLI\Runner;
use Arkitect\CLI\TargetPhpVersion;
use Arkitect\Rules\Violations;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Webmozart\Assert\Assert;

class Check extends Command
{
Expand Down Expand Up @@ -51,7 +49,8 @@ protected function configure(): void
self::CONFIG_FILENAME_PARAM,
'c',
InputOption::VALUE_OPTIONAL,
'File containing configs, such as rules to be matched'
'File containing configs, such as rules to be matched',
self::DEFAULT_RULES_FILENAME
)
->addOption(
self::TARGET_PHP_PARAM,
Expand Down Expand Up @@ -107,6 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

try {
$verbose = (bool) $input->getOption('verbose');
$rulesFilename = $input->getOption(self::CONFIG_FILENAME_PARAM);
$stopOnFailure = (bool) $input->getOption(self::STOP_ON_FAILURE_PARAM);
$useBaseline = (string) $input->getOption(self::USE_BASELINE_PARAM);
$skipBaseline = (bool) $input->getOption(self::SKIP_BASELINE_PARAM);
Expand All @@ -120,46 +120,44 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$stdOut = $output;
$output = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;

$targetPhpVersion = TargetPhpVersion::create($phpVersion);
$this->printHeadingLine($output);

$progress = $verbose ? new DebugProgress($output) : new ProgressBarProgress($output);
$config = ConfigBuilder::loadFromFile($rulesFilename)
->stopOnFailure($stopOnFailure)
->targetPhpVersion(TargetPhpVersion::create($phpVersion))
->baselineFilePath(Baseline::resolveFilePath($useBaseline, self::DEFAULT_BASELINE_FILENAME))
->ignoreBaselineLinenumbers($ignoreBaselineLinenumbers)
->skipBaseline($skipBaseline)
->format($format);

$baseline = Baseline::create($skipBaseline, $useBaseline, self::DEFAULT_BASELINE_FILENAME);
$printer = PrinterFactory::create($config->getFormat());

$printer = (new PrinterFactory())->create($format);
$progress = $verbose ? new DebugProgress($output) : new ProgressBarProgress($output);

$this->printHeadingLine($output);
$baseline = Baseline::create($config->isSkipBaseline(), $config->getBaselineFilePath());

$baseline->getFilename() && $output->writeln("Baseline file '{$baseline->getFilename()}' found");

$rulesFilename = $this->getConfigFilename($input);

$output->writeln("Config file '$rulesFilename' found\n");

$config = new Config();

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

$runner = new Runner($stopOnFailure);
$result = $runner->run($config, $progress, $targetPhpVersion);

$violations = $result->getViolations();
$runner = new Runner();

if (false !== $generateBaseline) {
$baselineFilePath = Baseline::save($generateBaseline, self::DEFAULT_BASELINE_FILENAME, $violations);
$result = $runner->baseline($config, $progress);

$baselineFilePath = Baseline::save($generateBaseline, self::DEFAULT_BASELINE_FILENAME, $result->getViolations());

$output->writeln("ℹ️ Baseline file '$baselineFilePath' created!");

return self::SUCCESS_CODE;
}

$baseline->applyTo($violations, $ignoreBaselineLinenumbers);
$result = $runner->run($config, $baseline, $progress);

// we always print this so we do not have to do additional ifs later
$stdOut->writeln($printer->print($violations->groupedByFqcn()));
$stdOut->writeln($printer->print($result->getViolations()->groupedByFqcn()));

if ($violations->count() > 0) {
$output->writeln("⚠️ {$violations->count()} violations detected!");
if ($result->hasViolations()) {
$output->writeln("⚠️ {$result->getViolations()->count()} violations detected!");
}

if ($result->hasParsingErrors()) {
Expand All @@ -179,18 +177,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
}

protected function readRules(Config $ruleChecker, string $rulesFilename): void
{
\Closure::fromCallable(function () use ($ruleChecker, $rulesFilename): ?bool {
/** @psalm-suppress UnresolvableInclude $config */
$config = require $rulesFilename;

Assert::isCallable($config);

return $config($ruleChecker);
})();
}

protected function printHeadingLine(OutputInterface $output): void
{
$app = $this->getApplication();
Expand All @@ -207,17 +193,4 @@ protected function printExecutionTime(OutputInterface $output, float $startTime)

$output->writeln("⏱️ Execution time: $executionTime\n");
}

private function getConfigFilename(InputInterface $input): string
{
$filename = $input->getOption(self::CONFIG_FILENAME_PARAM);

if (null === $filename) {
$filename = self::DEFAULT_RULES_FILENAME;
}

Assert::file($filename, "Config file '$filename' not found");

return $filename;
}
}
91 changes: 91 additions & 0 deletions src/CLI/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use Arkitect\ClassSet;
use Arkitect\ClassSetRules;
use Arkitect\CLI\Printer\PrinterFactory;
use Arkitect\Rules\DSL\ArchRule;

class Config
Expand All @@ -16,11 +17,29 @@ class Config

private bool $parseCustomAnnotations;

private bool $stopOnFailure;

private bool $skipBaseline;

private ?string $baselineFilePath;

private bool $ignoreBaselineLinenumbers;

private string $format;

private TargetPhpVersion $targetPhpVersion;

public function __construct()
{
$this->classSetRules = [];
$this->runOnlyARule = false;
$this->parseCustomAnnotations = true;
$this->stopOnFailure = false;
$this->skipBaseline = false;
$this->baselineFilePath = null;
$this->ignoreBaselineLinenumbers = false;
$this->format = PrinterFactory::default();
$this->targetPhpVersion = TargetPhpVersion::latest();
}

public function add(ClassSet $classSet, ArchRule ...$rules): self
Expand Down Expand Up @@ -61,4 +80,76 @@ public function isParseCustomAnnotationsEnabled(): bool
{
return $this->parseCustomAnnotations;
}

public function targetPhpVersion(TargetPhpVersion $targetPhpVersion): self
{
$this->targetPhpVersion = $targetPhpVersion;

return $this;
}

public function getTargetPhpVersion(): TargetPhpVersion
{
return $this->targetPhpVersion;
}

public function stopOnFailure(bool $stopOnFailure): self
{
$this->stopOnFailure = $stopOnFailure;

return $this;
}

public function isStopOnFailure(): bool
{
return $this->stopOnFailure;
}

public function baselineFilePath(?string $baselineFilePath): self
{
$this->baselineFilePath = $baselineFilePath;

return $this;
}

public function getBaselineFilePath(): ?string
{
return $this->baselineFilePath;
}

public function ignoreBaselineLinenumbers(bool $ignoreBaselineLinenumbers): self
{
$this->ignoreBaselineLinenumbers = $ignoreBaselineLinenumbers;

return $this;
}

public function isIgnoreBaselineLinenumbers(): bool
{
return $this->ignoreBaselineLinenumbers;
}

public function format(string $format): self
{
$this->format = $format;

return $this;
}

public function getFormat(): string
{
return $this->format;
}

public function skipBaseline(bool $skipBaseline): self
{
$this->skipBaseline = $skipBaseline;

return $this;
}

public function isSkipBaseline(): bool
{
return $this->skipBaseline;
}
}
28 changes: 28 additions & 0 deletions src/CLI/ConfigBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Arkitect\CLI;

use Webmozart\Assert\Assert;

class ConfigBuilder
{
public static function loadFromFile(string $filePath): Config
{
Assert::file($filePath, "Config file '$filePath' not found");

$config = new Config();

\Closure::fromCallable(function () use ($config, $filePath): ?bool {
/** @psalm-suppress UnresolvableInclude $config */
$configFunction = require $filePath;

Assert::isCallable($configFunction);

return $configFunction($config);
})();

return $config;
}
}
7 changes: 6 additions & 1 deletion src/CLI/Printer/PrinterFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@

final class PrinterFactory
{
public function create(string $format): Printer
public static function default(): string
{
return Printer::FORMAT_TEXT;
}

public static function create(string $format): Printer
{
switch ($format) {
case Printer::FORMAT_GITLAB:
Expand Down
Loading