From e082a03d0c7d0448cd4fce9b6faa39601ce78819 Mon Sep 17 00:00:00 2001 From: Frank Verhoeven Date: Fri, 10 Dec 2021 12:00:29 +0100 Subject: [PATCH] Symfony linters (#2) * feat: Add Symfony linters * fixup! feat: Add Symfony linters * Add lint YAML * Add roave infection * Disable command timeout * chore: Update PHP ^7.4 * fixup! chore: Update PHP ^7.4 --- composer.json | 2 +- src/Command/AnalyzeCommand.php | 3 +- src/Command/CodesnifferCommand.php | 15 +++---- src/Command/DevToolsCommand.php | 19 +++++---- src/Command/LintSymfonyContainerCommand.php | 39 ++++++++++++++++++ src/Command/LintYamlCommand.php | 44 +++++++++++++++++++++ src/Command/ListPhpVersionsCommand.php | 5 +-- src/Command/ListToolsCommand.php | 5 +-- src/Command/PhpUnitCommand.php | 15 +++---- src/Command/PsalmCommand.php | 15 +++---- src/Command/RoaveInfectionCommand.php | 36 +++++++++++++++++ src/Configuration.php | 29 +++++++------- src/DevTools.php | 9 ++++- tests/DevToolsTest.php | 13 +++--- 14 files changed, 185 insertions(+), 64 deletions(-) create mode 100644 src/Command/LintSymfonyContainerCommand.php create mode 100644 src/Command/LintYamlCommand.php create mode 100644 src/Command/RoaveInfectionCommand.php diff --git a/composer.json b/composer.json index 0213dab..1e35c57 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } }, "require": { - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "symfony/console": "^5.3", "composer/semver": "^3.2", "symfony/process": "^5.3" diff --git a/src/Command/AnalyzeCommand.php b/src/Command/AnalyzeCommand.php index 41b1b48..8504d8b 100644 --- a/src/Command/AnalyzeCommand.php +++ b/src/Command/AnalyzeCommand.php @@ -16,8 +16,7 @@ final class AnalyzeCommand extends Command /** @var string|null */ protected static $defaultDescription = 'Run all enabled tools.'; - /** @var Configuration */ - private $configuration; + private Configuration $configuration; public function __construct(Configuration $configuration) { diff --git a/src/Command/CodesnifferCommand.php b/src/Command/CodesnifferCommand.php index fde36bf..eae7a1a 100644 --- a/src/Command/CodesnifferCommand.php +++ b/src/Command/CodesnifferCommand.php @@ -3,6 +3,8 @@ namespace MyOnlineStore\DevTools\Command; +use MyOnlineStore\DevTools\Configuration; + final class CodesnifferCommand extends DevToolsCommand { /** @var string|null */ @@ -17,18 +19,13 @@ final class CodesnifferCommand extends DevToolsCommand protected function getCommand(): array { return [ - $this->withBinPath('phpcs'), + $this->withVendorBinPath('phpcs'), ]; } - /** - * @inheritDoc - */ - public static function getPossibleConfigurationFiles(): array + public static function isAvailable(Configuration $configuration): bool { - return [ - 'phpcs.xml.dist', - 'phpcs.xml', - ]; + return \is_file($configuration->getRootDir() . 'phpcs.xml.dist') + || \is_file($configuration->getRootDir() . 'phpcs.xml'); } } diff --git a/src/Command/DevToolsCommand.php b/src/Command/DevToolsCommand.php index de51273..67b6590 100644 --- a/src/Command/DevToolsCommand.php +++ b/src/Command/DevToolsCommand.php @@ -11,8 +11,7 @@ abstract class DevToolsCommand extends Command { - /** @var Configuration */ - protected $configuration; + protected Configuration $configuration; public function __construct(Configuration $configuration) { @@ -27,7 +26,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int \array_merge( $this->getCommand(), (array) ($input->getArguments()['args'] ?? []) - ) + ), + null, + null, + null, + null ); $process->start(); @@ -39,14 +42,16 @@ static function (string $_type, string $buffer) use ($output): void { } protected function withBinPath(string $command): string + { + return $this->configuration->getRootDir() . 'bin/' . $command; + } + + protected function withVendorBinPath(string $command): string { return $this->configuration->getRootDir() . 'vendor/bin/' . $command; } - /** - * @return list - */ - abstract public static function getPossibleConfigurationFiles(): array; + abstract public static function isAvailable(Configuration $configuration): bool; /** * @return list diff --git a/src/Command/LintSymfonyContainerCommand.php b/src/Command/LintSymfonyContainerCommand.php new file mode 100644 index 0000000..6495e72 --- /dev/null +++ b/src/Command/LintSymfonyContainerCommand.php @@ -0,0 +1,39 @@ +withBinPath('console'), + 'lint:container', + ]; + } + + public static function isAvailable(Configuration $configuration): bool + { + if (!\is_file($configuration->getRootDir() . 'bin/console')) { + return false; + } + + $process = new Process([$configuration->getRootDir() . 'bin/console', 'list']); + $process->run(); + + return \str_contains($process->getOutput(), 'lint:container'); + } +} diff --git a/src/Command/LintYamlCommand.php b/src/Command/LintYamlCommand.php new file mode 100644 index 0000000..522dd6d --- /dev/null +++ b/src/Command/LintYamlCommand.php @@ -0,0 +1,44 @@ +withBinPath('console'), + 'lint:yaml', + 'config', + '--parse-tags', + ]; + } + + public static function isAvailable(Configuration $configuration): bool + { + if ( + !\is_file($configuration->getRootDir() . 'bin/console') || + !\is_dir($configuration->getRootDir() . 'config') + ) { + return false; + } + + $process = new Process([$configuration->getRootDir() . 'bin/console', 'list']); + $process->run(); + + return \str_contains($process->getOutput(), 'lint:yaml'); + } +} diff --git a/src/Command/ListPhpVersionsCommand.php b/src/Command/ListPhpVersionsCommand.php index 4f16b11..65b7a55 100644 --- a/src/Command/ListPhpVersionsCommand.php +++ b/src/Command/ListPhpVersionsCommand.php @@ -16,8 +16,7 @@ final class ListPhpVersionsCommand extends Command /** @var string|null */ protected static $defaultDescription = 'Lists PHP versions allowed by composer.json (in JSON format).'; - /** @var Configuration */ - private $configuration; + private Configuration $configuration; public function __construct(Configuration $configuration) { @@ -28,7 +27,7 @@ public function __construct(Configuration $configuration) protected function execute(InputInterface $input, OutputInterface $output): int { - $output->write(\json_encode($this->configuration->getPhpVersions())); + $output->write(\json_encode($this->configuration->getPhpVersions(), \JSON_THROW_ON_ERROR)); return 0; } diff --git a/src/Command/ListToolsCommand.php b/src/Command/ListToolsCommand.php index 78dd750..8eb2c76 100644 --- a/src/Command/ListToolsCommand.php +++ b/src/Command/ListToolsCommand.php @@ -16,8 +16,7 @@ final class ListToolsCommand extends Command /** @var string|null */ protected static $defaultDescription = 'Lists enabled tools (in JSON).'; - /** @var Configuration */ - private $configuration; + private Configuration $configuration; public function __construct(Configuration $configuration) { @@ -28,7 +27,7 @@ public function __construct(Configuration $configuration) protected function execute(InputInterface $input, OutputInterface $output): int { - $output->write(\json_encode(\array_keys($this->configuration->getEnabledTools()))); + $output->write(\json_encode(\array_keys($this->configuration->getEnabledTools()), \JSON_THROW_ON_ERROR)); return 0; } diff --git a/src/Command/PhpUnitCommand.php b/src/Command/PhpUnitCommand.php index 2ae9373..a48f214 100644 --- a/src/Command/PhpUnitCommand.php +++ b/src/Command/PhpUnitCommand.php @@ -3,6 +3,8 @@ namespace MyOnlineStore\DevTools\Command; +use MyOnlineStore\DevTools\Configuration; + final class PhpUnitCommand extends DevToolsCommand { /** @var string|null */ @@ -17,18 +19,13 @@ final class PhpUnitCommand extends DevToolsCommand protected function getCommand(): array { return [ - $this->withBinPath('phpunit'), + $this->withVendorBinPath('phpunit'), ]; } - /** - * @inheritDoc - */ - public static function getPossibleConfigurationFiles(): array + public static function isAvailable(Configuration $configuration): bool { - return [ - 'phpunit.xml.dist', - 'phpunit.xml', - ]; + return \is_file($configuration->getRootDir() . 'phpunit.xml.dist') + || \is_file($configuration->getRootDir() . 'phpunit.xml'); } } diff --git a/src/Command/PsalmCommand.php b/src/Command/PsalmCommand.php index 248ba36..37db63d 100644 --- a/src/Command/PsalmCommand.php +++ b/src/Command/PsalmCommand.php @@ -3,6 +3,8 @@ namespace MyOnlineStore\DevTools\Command; +use MyOnlineStore\DevTools\Configuration; + final class PsalmCommand extends DevToolsCommand { /** @var string|null */ @@ -17,18 +19,13 @@ final class PsalmCommand extends DevToolsCommand protected function getCommand(): array { return [ - $this->withBinPath('psalm'), + $this->withVendorBinPath('psalm'), ]; } - /** - * @inheritDoc - */ - public static function getPossibleConfigurationFiles(): array + public static function isAvailable(Configuration $configuration): bool { - return [ - 'psalm.xml.dist', - 'psalm.xml', - ]; + return \is_file($configuration->getRootDir() . 'psalm.xml.dist') + || \is_file($configuration->getRootDir() . 'psalm.xml'); } } diff --git a/src/Command/RoaveInfectionCommand.php b/src/Command/RoaveInfectionCommand.php new file mode 100644 index 0000000..f0f8266 --- /dev/null +++ b/src/Command/RoaveInfectionCommand.php @@ -0,0 +1,36 @@ +withVendorBinPath('roave-infection-static-analysis-plugin'), + '--only-covered', + '--show-mutations', + ]; + } + + public static function isAvailable(Configuration $configuration): bool + { + return \is_file($configuration->getRootDir() . 'vendor/bin/roave-infection-static-analysis-plugin') + && ( + \is_file($configuration->getRootDir() . 'infection.json.dist') || + \is_file($configuration->getRootDir() . 'infection.json') + ); + } +} diff --git a/src/Configuration.php b/src/Configuration.php index 27bce0c..ee97188 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -9,7 +9,6 @@ final class Configuration { private const PHP_VERSIONS = [ - '7.2', '7.4', '8.0', '8.1', @@ -21,8 +20,7 @@ final class Configuration /** @var list|null */ private $phpVersions; - /** @var string */ - private $rootDir; + private string $rootDir; public function __construct() { @@ -49,7 +47,12 @@ public function __construct() private function gatherPhpVersions(): array { /** @var array $composer */ - $composer = \json_decode(\file_get_contents($this->rootDir . 'composer.json'), true); + $composer = \json_decode( + \file_get_contents($this->rootDir . 'composer.json'), + true, + 512, + \JSON_THROW_ON_ERROR + ); if (!isset($composer['require']['php'])) { throw new \RuntimeException('Required PHP version not specified in composer.json'); @@ -94,19 +97,17 @@ private function gatherEnabledTools(): array $enabledTools = []; foreach ($this->gatherAvailableCommands() as $command) { - foreach ($command::getPossibleConfigurationFiles() as $configurationFile) { - if (!\is_file($this->rootDir . $configurationFile)) { - continue; - } - - $commandName = $command::getDefaultName(); + if (!$command::isAvailable($this)) { + continue; + } - if (!\is_string($commandName)) { - throw new \RuntimeException(\sprintf('Command "%s" has not configured a name', $command)); - } + $commandName = $command::getDefaultName(); - $enabledTools[$commandName] = $command; + if (!\is_string($commandName)) { + throw new \RuntimeException(\sprintf('Command "%s" has not configured a name', $command)); } + + $enabledTools[$commandName] = $command; } return $enabledTools; diff --git a/src/DevTools.php b/src/DevTools.php index bc52a6f..3c476f8 100644 --- a/src/DevTools.php +++ b/src/DevTools.php @@ -5,16 +5,18 @@ use MyOnlineStore\DevTools\Command\AnalyzeCommand; use MyOnlineStore\DevTools\Command\CodesnifferCommand; +use MyOnlineStore\DevTools\Command\LintSymfonyContainerCommand; +use MyOnlineStore\DevTools\Command\LintYamlCommand; use MyOnlineStore\DevTools\Command\ListPhpVersionsCommand; use MyOnlineStore\DevTools\Command\ListToolsCommand; use MyOnlineStore\DevTools\Command\PhpUnitCommand; use MyOnlineStore\DevTools\Command\PsalmCommand; +use MyOnlineStore\DevTools\Command\RoaveInfectionCommand; use Symfony\Component\Console\Command\Command; final class DevTools { - /** @var Configuration */ - private $configuration; + private Configuration $configuration; public function __construct(Configuration $configuration) { @@ -29,10 +31,13 @@ public function getCommands(): array return [ new AnalyzeCommand($this->configuration), new CodesnifferCommand($this->configuration), + new LintSymfonyContainerCommand($this->configuration), + new LintYamlCommand($this->configuration), new ListToolsCommand($this->configuration), new ListPhpVersionsCommand($this->configuration), new PhpUnitCommand($this->configuration), new PsalmCommand($this->configuration), + new RoaveInfectionCommand($this->configuration), ]; } } diff --git a/tests/DevToolsTest.php b/tests/DevToolsTest.php index a94fc47..2d3c77a 100644 --- a/tests/DevToolsTest.php +++ b/tests/DevToolsTest.php @@ -5,21 +5,21 @@ use MyOnlineStore\DevTools\Command\AnalyzeCommand; use MyOnlineStore\DevTools\Command\CodesnifferCommand; +use MyOnlineStore\DevTools\Command\LintSymfonyContainerCommand; +use MyOnlineStore\DevTools\Command\LintYamlCommand; use MyOnlineStore\DevTools\Command\ListPhpVersionsCommand; use MyOnlineStore\DevTools\Command\ListToolsCommand; use MyOnlineStore\DevTools\Command\PhpUnitCommand; use MyOnlineStore\DevTools\Command\PsalmCommand; +use MyOnlineStore\DevTools\Command\RoaveInfectionCommand; use MyOnlineStore\DevTools\Configuration; use MyOnlineStore\DevTools\DevTools; use PHPUnit\Framework\TestCase; final class DevToolsTest extends TestCase { - /** @var Configuration */ - private $configuration; - - /** @var DevTools */ - private $devTools; + private Configuration $configuration; + private DevTools $devTools; protected function setUp(): void { @@ -34,10 +34,13 @@ public function testGetCommands(): void [ new AnalyzeCommand($this->configuration), new CodesnifferCommand($this->configuration), + new LintSymfonyContainerCommand($this->configuration), + new LintYamlCommand($this->configuration), new ListToolsCommand($this->configuration), new ListPhpVersionsCommand($this->configuration), new PhpUnitCommand($this->configuration), new PsalmCommand($this->configuration), + new RoaveInfectionCommand($this->configuration), ], $this->devTools->getCommands() );