diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 563ec60..99c93f2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -33,6 +33,9 @@ jobs: - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} + tools: cs2pr - uses: ramsey/composer-install@v2 + - run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - run: bin/devtools ${{ matrix.tool }} + - run: bin/devtools ${{ matrix.tool }} --format=github diff --git a/composer.json b/composer.json index 5048740..0fb0247 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ } }, "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "composer/semver": "^3.3", "symfony/console": "^5.4 || ^6.0", "symfony/process": "^5.4 || ^6.0" diff --git a/src/Command/AnalyzeCommand.php b/src/Command/AnalyzeCommand.php index 8504d8b..cc2e8fb 100644 --- a/src/Command/AnalyzeCommand.php +++ b/src/Command/AnalyzeCommand.php @@ -16,12 +16,9 @@ final class AnalyzeCommand extends Command /** @var string|null */ protected static $defaultDescription = 'Run all enabled tools.'; - private Configuration $configuration; - - public function __construct(Configuration $configuration) - { - $this->configuration = $configuration; - + public function __construct( + private Configuration $configuration, + ) { parent::__construct(); } diff --git a/src/Command/CodesnifferCommand.php b/src/Command/CodesnifferCommand.php index eae7a1a..09371ac 100644 --- a/src/Command/CodesnifferCommand.php +++ b/src/Command/CodesnifferCommand.php @@ -4,6 +4,8 @@ namespace MyOnlineStore\DevTools\Command; use MyOnlineStore\DevTools\Configuration; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Process\Process; final class CodesnifferCommand extends DevToolsCommand { @@ -13,14 +15,19 @@ final class CodesnifferCommand extends DevToolsCommand /** @var string|null */ protected static $defaultDescription = 'PHP_CodeSniffer'; - /** - * @inheritDoc - */ - protected function getCommand(): array + protected function getProcess(InputInterface $input): Process { - return [ - $this->withVendorBinPath('phpcs'), - ]; + if ($this->isGitHubFormat($input)) { + return Process::fromShellCommandline( + $this->withVendorBinPath('phpcs') . ' -q --report=checkstyle | cs2pr', + timeout: null, + ); + } + + return new Process( + [$this->withVendorBinPath('phpcs')], + timeout: null, + ); } public static function isAvailable(Configuration $configuration): bool diff --git a/src/Command/DevToolsCommand.php b/src/Command/DevToolsCommand.php index 7b24ecb..4fcd797 100644 --- a/src/Command/DevToolsCommand.php +++ b/src/Command/DevToolsCommand.php @@ -6,41 +6,39 @@ use MyOnlineStore\DevTools\Configuration; 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\Process\Process; abstract class DevToolsCommand extends Command { - protected Configuration $configuration; + public function __construct( + protected Configuration $configuration, + ) { + parent::__construct(); + } - public function __construct(Configuration $configuration) + protected function configure(): void { - $this->configuration = $configuration; - - parent::__construct(); + $this->addOption( + 'format', + null, + InputOption::VALUE_OPTIONAL, + 'Output format to use (by supported commands).' + ); } protected function execute(InputInterface $input, OutputInterface $output): int { - $commands = $this->getMultiCommand(); + $processes = $this->getMultiProcess($input); - if (0 === \count($commands)) { - $commands[] = $this->getCommand(); + if (0 === \count($processes)) { + $processes[] = $this->getProcess($input); } $exitCode = 0; - foreach ($commands as $command) { - $process = new Process( - \array_merge( - $command, - (array) ($input->getArguments()['args'] ?? []) - ), - null, - null, - null, - null - ); + foreach ($processes as $process) { $process->start(); $exitCode |= $process->wait( @@ -53,31 +51,33 @@ static function (string $_type, string $buffer) use ($output): void { return $exitCode; } - protected function withBinPath(string $command): string + protected function getProcess(InputInterface $input): Process { - return $this->configuration->getRootDir() . 'bin/' . $command; + throw new \RuntimeException('Either implement getProcess() or getMultiProcess()'); } - protected function withVendorBinPath(string $command): string + /** + * @return list + */ + protected function getMultiProcess(InputInterface $input): array { - return $this->configuration->getRootDir() . 'vendor/bin/' . $command; + return []; } abstract public static function isAvailable(Configuration $configuration): bool; - /** - * @return list - */ - protected function getCommand(): array + protected function isGitHubFormat(InputInterface $input): bool { - return []; + return 'github' === $input->getOption('format'); } - /** - * @return list> - */ - protected function getMultiCommand(): array + protected function withBinPath(string $command): string { - return []; + return $this->configuration->getRootDir() . 'bin/' . $command; + } + + protected function withVendorBinPath(string $command): string + { + return $this->configuration->getRootDir() . 'vendor/bin/' . $command; } } diff --git a/src/Command/DoctrineMigrationsCommand.php b/src/Command/DoctrineMigrationsCommand.php index 3c7ba28..0982423 100644 --- a/src/Command/DoctrineMigrationsCommand.php +++ b/src/Command/DoctrineMigrationsCommand.php @@ -4,47 +4,56 @@ namespace MyOnlineStore\DevTools\Command; use MyOnlineStore\DevTools\Configuration; +use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Process\Process; final class DoctrineMigrationsCommand extends DevToolsCommand { /** @var string|null */ protected static $defaultName = 'doctrine-migrations'; - /** @var string|null */ protected static $defaultDescription = 'Doctrine Migrations, always runs in test environment'; /** * @inheritDoc */ - protected function getMultiCommand(): array + protected function getMultiProcess(InputInterface $input): array { return [ // Ensure we're up-to-date - [ - $this->withBinPath('console'), - 'doctrine:migrations:migrate', - '--allow-no-migration', - '--no-interaction', - '--env=test', - ], + new Process( + [ + $this->withBinPath('console'), + 'doctrine:migrations:migrate', + '--allow-no-migration', + '--no-interaction', + '--env=test', + ], + timeout: null, + ), // Test all down patches - [ - $this->withBinPath('console'), - 'doctrine:migrations:migrate', - 'first', - '--allow-no-migration', - '--no-interaction', - '--env=test', - ], + new Process( + [ + $this->withBinPath('console'), + 'doctrine:migrations:migrate', + 'first', + '--allow-no-migration', + '--no-interaction', + '--env=test', + ], + timeout: null, + ), // Test all migrations ánd if down patches did their job - [ - $this->withBinPath('console'), - 'doctrine:migrations:migrate', - '--allow-no-migration', - '--no-interaction', - '--env=test', - ], + new Process( + [ + $this->withBinPath('console'), + 'doctrine:migrations:migrate', + '--allow-no-migration', + '--no-interaction', + '--env=test', + ], + timeout: null, + ), ]; } diff --git a/src/Command/LintSymfonyContainerCommand.php b/src/Command/LintSymfonyContainerCommand.php index 6495e72..03287b7 100644 --- a/src/Command/LintSymfonyContainerCommand.php +++ b/src/Command/LintSymfonyContainerCommand.php @@ -4,6 +4,7 @@ namespace MyOnlineStore\DevTools\Command; use MyOnlineStore\DevTools\Configuration; +use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Process\Process; final class LintSymfonyContainerCommand extends DevToolsCommand @@ -14,15 +15,15 @@ final class LintSymfonyContainerCommand extends DevToolsCommand /** @var string|null */ protected static $defaultDescription = 'Lint Symfony container'; - /** - * @inheritDoc - */ - protected function getCommand(): array + protected function getProcess(InputInterface $input): Process { - return [ - $this->withBinPath('console'), - 'lint:container', - ]; + return new Process( + [ + $this->withBinPath('console'), + 'lint:container', + ], + timeout: null, + ); } public static function isAvailable(Configuration $configuration): bool diff --git a/src/Command/LintYamlCommand.php b/src/Command/LintYamlCommand.php index 522dd6d..c0e6f61 100644 --- a/src/Command/LintYamlCommand.php +++ b/src/Command/LintYamlCommand.php @@ -4,6 +4,7 @@ namespace MyOnlineStore\DevTools\Command; use MyOnlineStore\DevTools\Configuration; +use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Process\Process; final class LintYamlCommand extends DevToolsCommand @@ -14,17 +15,17 @@ final class LintYamlCommand extends DevToolsCommand /** @var string|null */ protected static $defaultDescription = 'Lint YAML'; - /** - * @inheritDoc - */ - protected function getCommand(): array + protected function getProcess(InputInterface $input): Process { - return [ - $this->withBinPath('console'), - 'lint:yaml', - 'config', - '--parse-tags', - ]; + return new Process( + [ + $this->withBinPath('console'), + 'lint:yaml', + 'config', + '--parse-tags', + ], + timeout: null, + ); } public static function isAvailable(Configuration $configuration): bool diff --git a/src/Command/ListPhpVersionsCommand.php b/src/Command/ListPhpVersionsCommand.php index 65b7a55..541a6be 100644 --- a/src/Command/ListPhpVersionsCommand.php +++ b/src/Command/ListPhpVersionsCommand.php @@ -16,12 +16,9 @@ final class ListPhpVersionsCommand extends Command /** @var string|null */ protected static $defaultDescription = 'Lists PHP versions allowed by composer.json (in JSON format).'; - private Configuration $configuration; - - public function __construct(Configuration $configuration) - { - $this->configuration = $configuration; - + public function __construct( + private Configuration $configuration, + ) { parent::__construct(); } diff --git a/src/Command/ListToolsCommand.php b/src/Command/ListToolsCommand.php index 8eb2c76..b88cb5e 100644 --- a/src/Command/ListToolsCommand.php +++ b/src/Command/ListToolsCommand.php @@ -16,12 +16,9 @@ final class ListToolsCommand extends Command /** @var string|null */ protected static $defaultDescription = 'Lists enabled tools (in JSON).'; - private Configuration $configuration; - - public function __construct(Configuration $configuration) - { - $this->configuration = $configuration; - + public function __construct( + private Configuration $configuration, + ) { parent::__construct(); } diff --git a/src/Command/PhpUnitCommand.php b/src/Command/PhpUnitCommand.php index a48f214..c31e824 100644 --- a/src/Command/PhpUnitCommand.php +++ b/src/Command/PhpUnitCommand.php @@ -4,6 +4,8 @@ namespace MyOnlineStore\DevTools\Command; use MyOnlineStore\DevTools\Configuration; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Process\Process; final class PhpUnitCommand extends DevToolsCommand { @@ -13,14 +15,12 @@ final class PhpUnitCommand extends DevToolsCommand /** @var string|null */ protected static $defaultDescription = 'PHP Unit'; - /** - * @inheritDoc - */ - protected function getCommand(): array + protected function getProcess(InputInterface $input): Process { - return [ - $this->withVendorBinPath('phpunit'), - ]; + return new Process( + [$this->withVendorBinPath('phpunit')], + timeout: null, + ); } public static function isAvailable(Configuration $configuration): bool diff --git a/src/Command/PsalmCommand.php b/src/Command/PsalmCommand.php index 37db63d..1a5c6fa 100644 --- a/src/Command/PsalmCommand.php +++ b/src/Command/PsalmCommand.php @@ -4,6 +4,8 @@ namespace MyOnlineStore\DevTools\Command; use MyOnlineStore\DevTools\Configuration; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Process\Process; final class PsalmCommand extends DevToolsCommand { @@ -13,14 +15,15 @@ final class PsalmCommand extends DevToolsCommand /** @var string|null */ protected static $defaultDescription = 'Psalm'; - /** - * @inheritDoc - */ - protected function getCommand(): array + protected function getProcess(InputInterface $input): Process { - return [ - $this->withVendorBinPath('psalm'), - ]; + $command = [$this->withVendorBinPath('psalm')]; + + if ($this->isGitHubFormat($input)) { + $command[] = '--output-format=github'; + } + + return new Process($command, timeout: null); } public static function isAvailable(Configuration $configuration): bool diff --git a/src/Command/RoaveInfectionCommand.php b/src/Command/RoaveInfectionCommand.php index f0f8266..7e4f596 100644 --- a/src/Command/RoaveInfectionCommand.php +++ b/src/Command/RoaveInfectionCommand.php @@ -4,6 +4,8 @@ namespace MyOnlineStore\DevTools\Command; use MyOnlineStore\DevTools\Configuration; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Process\Process; final class RoaveInfectionCommand extends DevToolsCommand { @@ -13,16 +15,17 @@ final class RoaveInfectionCommand extends DevToolsCommand /** @var string|null */ protected static $defaultDescription = 'Roave Infection'; - /** - * @inheritDoc - */ - protected function getCommand(): array + protected function getProcess(InputInterface $input): Process { - return [ - $this->withVendorBinPath('roave-infection-static-analysis-plugin'), - '--only-covered', - '--show-mutations', - ]; + return new Process( + [ + $this->withVendorBinPath('roave-infection-static-analysis-plugin'), + '--only-covered', + '--show-mutations', + ], + env: ['XDEBUG_MODE' => 'coverage'], + timeout: null, + ); } public static function isAvailable(Configuration $configuration): bool diff --git a/src/Configuration.php b/src/Configuration.php index ee97188..47fa920 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -9,16 +9,15 @@ final class Configuration { private const PHP_VERSIONS = [ - '7.4', '8.0', '8.1', ]; /** @var array>|null */ - private $enabledTools; + private ?array $enabledTools = null; /** @var list|null */ - private $phpVersions; + private ?array $phpVersions = null; private string $rootDir; diff --git a/src/DevTools.php b/src/DevTools.php index c7df0b9..7e45184 100644 --- a/src/DevTools.php +++ b/src/DevTools.php @@ -17,11 +17,9 @@ final class DevTools { - private Configuration $configuration; - - public function __construct(Configuration $configuration) - { - $this->configuration = $configuration; + public function __construct( + private Configuration $configuration, + ) { } /**