From 179c793a77f03f7f5611708e7ba379eeb8ecd44d Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Fri, 31 May 2024 13:49:11 +0200 Subject: [PATCH 01/11] #1126 update contributing docs --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06d1b76a8..71ceae7d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,8 +5,8 @@ feel free to do this, but remember to follow this few simple rules: ## Branching strategy -- __Always__ base your changes on the `master` branch (all new development happens here), -- When you create Pull Request, always select `master` branch as target, otherwise it +- __Always__ base your changes on the latest version `v.x` branch (all new development happens here), +- When you create Pull Request, always select `v.x` branch as target, otherwise it will be closed (this is selected by default). ## Coverage From 0f5673fb1b6c881f63a08a3219fd14ade80736eb Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Fri, 31 May 2024 14:50:31 +0200 Subject: [PATCH 02/11] #1126 symfony console: update docs --- doc/tasks.md | 2 ++ doc/tasks/symfony_console.md | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 doc/tasks/symfony_console.md diff --git a/doc/tasks.md b/doc/tasks.md index e2ebba688..64f3a4e6a 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -61,6 +61,7 @@ grumphp: securitychecker_symfony: ~ shell: ~ stylelint: ~ + symfony_console: ~ tester: ~ twigcs: ~ twigcsfixer: ~ @@ -128,6 +129,7 @@ Every task has its own default configuration. It is possible to overwrite the pa - [Symfony](tasks/securitychecker/symfony.md) - [Shell](tasks/shell.md) - [Stylelint](tasks/stylelint.md) +- [Symfony Console](tasks/symfony_console.md) - [Tester](tasks/tester.md) - [TwigCs](tasks/twigcs.md) - [Twig-CS-Fixer](tasks/twigcsfixer.md) diff --git a/doc/tasks/symfony_console.md b/doc/tasks/symfony_console.md new file mode 100644 index 000000000..864f73968 --- /dev/null +++ b/doc/tasks/symfony_console.md @@ -0,0 +1,47 @@ +# Symfony Console + +Run a symfony console command. + +## Composer + +Requires the Symfony Console component: [Console Component](https://symfony.com/components/Console) + +```bash +composer require symfony/console +``` + +## Config + +The task lives under the `symfony_console` namespace and has following configurable parameters: + +```yaml +# grumphp.yml +grumphp: + tasks: + symfony_console: + command: [ "lint:container", "-vvv" ] +``` + +**command** + +Specify the symfony command with defined options and arguments. +Verify the installed console component version for available commands `./bin/console list` + +## Note: Multiple Console command tasks + +[Run the same task twice with different configuration](../tasks.md#run-the-same-task-twice-with-different-configuration) + +Specific running multiple symfony console commands: + +```yaml +# grumphp.yml +grumphp: + lint-container: + command: [ "lint:container", "-vvv"] + metadata: + task: symfony_console + lint-yaml: + command: [ "lint:yaml", "path/to/yaml"] + metadata: + task: symfony_console +``` From f6c738599be30eda1fdf2c2d9ff2269ff3635ec6 Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Fri, 31 May 2024 16:45:17 +0200 Subject: [PATCH 03/11] #1126 Add SymfonyConsole Task, Test, service config --- resources/config/tasks.yml | 7 + src/Task/SymfonyConsole.php | 64 +++++++++ test/Unit/Task/SymfonyConsoleTest.php | 194 ++++++++++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 src/Task/SymfonyConsole.php create mode 100644 test/Unit/Task/SymfonyConsoleTest.php diff --git a/resources/config/tasks.yml b/resources/config/tasks.yml index 318dbe8d5..d494e23c4 100644 --- a/resources/config/tasks.yml +++ b/resources/config/tasks.yml @@ -386,6 +386,13 @@ services: tags: - {name: grumphp.task, task: stylelint} + GrumPHP\Task\SymfonyConsole: + arguments: + - '@process_builder' + - '@formatter.raw_process' + tags: + - {name: grumphp.task, task: symfony_console} + GrumPHP\Task\Tester: class: arguments: diff --git a/src/Task/SymfonyConsole.php b/src/Task/SymfonyConsole.php new file mode 100644 index 000000000..78e219ad1 --- /dev/null +++ b/src/Task/SymfonyConsole.php @@ -0,0 +1,64 @@ + */ +class SymfonyConsole extends AbstractExternalTask +{ + public static function getConfigurableOptions(): ConfigOptionsResolver + { + return ConfigOptionsResolver::fromOptionsResolver( + (new OptionsResolver()) + ->setDefaults([ + 'bin' => './bin/console', + 'command' => [], + ]) + ->addAllowedTypes('command', ['string[]']) + ->setRequired('command') + ); + } + + public function canRunInContext(ContextInterface $context): bool + { + return ($context instanceof GitPreCommitContext || $context instanceof RunContext); + } + + public function run(ContextInterface $context): TaskResultInterface + { + $config = $this->getConfig()->getOptions(); + if (0 === \count($context->getFiles())) { + return TaskResult::createSkipped($this, $context); + } + + if (0 === \count($config['command'])) { + return TaskResult::createNonBlockingFailed( + $this, + $context, + 'Missing "command" configuration for task "symfony_console".' + ); + } + + $arguments = $this->processBuilder->createArgumentsForCommand($config['bin']); + $arguments->addArgumentArray('%s', $config['command']); + + $process = $this->processBuilder->buildProcess($arguments); + $process->run(); + + if (!$process->isSuccessful()) { + return TaskResult::createFailed($this, $context, $this->formatter->format($process)); + } + + return TaskResult::createPassed($this, $context); + } +} diff --git a/test/Unit/Task/SymfonyConsoleTest.php b/test/Unit/Task/SymfonyConsoleTest.php new file mode 100644 index 000000000..ac59cb2a4 --- /dev/null +++ b/test/Unit/Task/SymfonyConsoleTest.php @@ -0,0 +1,194 @@ +processBuilder->reveal(), + $this->formatter->reveal() + ); + } + + public function provideConfigurableOptions(): iterable + { + yield 'default' => [ + [], + [ + 'bin' => './bin/console', + 'command' => [], + ] + ]; + + yield 'single-command' => [ + [ + 'command' => ['task:run'], + ], + [ + 'bin' => './bin/console', + 'command' => [ + 'task:run' + ], + ] + ]; + + yield 'array-command' => [ + [ + 'command' => ['task:run', '--env', 'dev', '-vvv'], + ], + [ + 'bin' => './bin/console', + 'command' => [ + 'task:run', + '--env', + 'dev', + '-vvv' + ], + ] + ]; + } + + public function provideRunContexts(): iterable + { + yield 'run-context' => [ + true, + $this->mockContext(RunContext::class) + ]; + + yield 'pre-commit-context' => [ + true, + $this->mockContext(GitPreCommitContext::class) + ]; + + yield 'other' => [ + false, + $this->mockContext() + ]; + } + + public function provideFailsOnStuff(): iterable + { + yield 'exitCode1' => [ + [ + 'command' => ['--version'] + ], + $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), + function() { + $process = $this->mockProcess(1); + $this->mockProcessBuilder('./bin/console', $process); + $this->formatter->format($process)->willReturn('nope'); + }, + 'nope' + ]; + } + + public function providePassesOnStuff(): iterable + { + yield 'exitCode0' => [ + [ + 'command' => ['--version'] + ], + $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), + function() { + $this->mockProcessBuilder('./bin/console', $this->mockProcess()); + } + ]; + } + + public function provideSkipsOnStuff(): iterable + { + yield 'no-files' => [ + [], + $this->mockContext(RunContext::class), + function() { + } + ]; + } + + public function provideExternalTaskRuns(): iterable + { + yield 'single-command' => [ + [ + 'command' => ['lint:container'] + ], + $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), + './bin/console', + [ + 'lint:container', + ] + ]; + + yield 'array-command' => [ + [ + 'command' => [ + 'task:run', + '--env', + 'dev', + '-vvv' + ] + ], + $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), + './bin/console', + [ + 'task:run', + '--env', + 'dev', + '-vvv' + ] + ]; + } + + /** + * @test + * @dataProvider provideFailsNonBlockingOnStuff + */ + public function it_fails_non_blocking_on_stuff( + array $config, + ContextInterface $context, + callable $configurator, + string $expectedErrorMessage, + ): void { + $task = $this->configureTask($config); + \Closure::bind($configurator, $this)($task->getConfig()->getOptions(), $context); + $result = $task->run($context); + + self::assertInstanceOf(TaskResultInterface::class, $result); + self::assertSame(TaskResultInterface::NONBLOCKING_FAILED, $result->getResultCode()); + self::assertSame($task, $result->getTask()); + self::assertSame($context, $result->getContext()); + self::assertSame($expectedErrorMessage, $result->getMessage()); + } + + public function provideFailsNonBlockingOnStuff(): iterable + { + yield 'no-command' => [ + [ + // missing command + ], + $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), + function() {}, + 'Missing "command" configuration for task "symfony_console".' + ]; + + yield 'missing-command-data' => [ + [ + 'command' => [], // missing command config + ], + $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), + function() {}, + 'Missing "command" configuration for task "symfony_console".' + ]; + } +} From d7a2a2817f978b6846bb85dce14c6615ec6ea2ca Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Fri, 31 May 2024 16:46:31 +0200 Subject: [PATCH 04/11] #1126 update non-static method call --- src/Test/Task/AbstractTaskTestCase.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Test/Task/AbstractTaskTestCase.php b/src/Test/Task/AbstractTaskTestCase.php index 75d682f3d..83124c1c7 100644 --- a/src/Test/Task/AbstractTaskTestCase.php +++ b/src/Test/Task/AbstractTaskTestCase.php @@ -6,7 +6,6 @@ use GrumPHP\Collection\FilesCollection; use GrumPHP\Runner\TaskResult; -use GrumPHP\Runner\TaskResultInterface; use GrumPHP\Task\Config\EmptyTaskConfig; use GrumPHP\Task\Config\Metadata; use GrumPHP\Task\Config\TaskConfig; @@ -47,7 +46,7 @@ protected function setUp(): void public function it_contains_configurable_options(array $input, ?array $output): void { if (!$output) { - self::expectException(ExceptionInterface::class); + $this->expectException(ExceptionInterface::class); } $resolver = $this->task::getConfigurableOptions(); From ba7cbf1ff81c6c42577c2d9fd0a3c774ce170f32 Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Fri, 31 May 2024 17:30:02 +0200 Subject: [PATCH 05/11] #1126 prevent symfony console: empty 'command' array config --- src/Task/SymfonyConsole.php | 2 +- test/Unit/Task/SymfonyConsoleTest.php | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Task/SymfonyConsole.php b/src/Task/SymfonyConsole.php index 78e219ad1..b38348fcc 100644 --- a/src/Task/SymfonyConsole.php +++ b/src/Task/SymfonyConsole.php @@ -41,7 +41,7 @@ public function run(ContextInterface $context): TaskResultInterface return TaskResult::createSkipped($this, $context); } - if (0 === \count($config['command'])) { + if ('' === \implode('', $config['command'])) { return TaskResult::createNonBlockingFailed( $this, $context, diff --git a/test/Unit/Task/SymfonyConsoleTest.php b/test/Unit/Task/SymfonyConsoleTest.php index ac59cb2a4..e0ad84f34 100644 --- a/test/Unit/Task/SymfonyConsoleTest.php +++ b/test/Unit/Task/SymfonyConsoleTest.php @@ -173,7 +173,7 @@ public function it_fails_non_blocking_on_stuff( public function provideFailsNonBlockingOnStuff(): iterable { - yield 'no-command' => [ + yield 'missing-command' => [ [ // missing command ], @@ -182,7 +182,7 @@ function() {}, 'Missing "command" configuration for task "symfony_console".' ]; - yield 'missing-command-data' => [ + yield 'empty-command-array' => [ [ 'command' => [], // missing command config ], @@ -190,5 +190,14 @@ function() {}, function() {}, 'Missing "command" configuration for task "symfony_console".' ]; + + yield 'empty-command-data' => [ + [ + 'command' => [""], // empty command config + ], + $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), + function() {}, + 'Missing "command" configuration for task "symfony_console".' + ]; } } From 6e54735e884bd67942209af9970afe3df84cf6f6 Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Fri, 31 May 2024 17:35:40 +0200 Subject: [PATCH 06/11] #1126 Add composer suggest 'symfony/console' --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 00d9b0e17..748ab5429 100644 --- a/composer.json +++ b/composer.json @@ -78,6 +78,7 @@ "sebastian/phpcpd": "Lets GrumPHP find duplicated code.", "squizlabs/php_codesniffer": "Lets GrumPHP sniff on your code.", "sstalle/php7cc": "Lets GrumPHP check PHP 5.3 - 5.6 code compatibility with PHP 7.", + "symfony/console": "Lets GrumPHP run Symfony Console commands.", "symfony/phpunit-bridge": "Lets GrumPHP run your unit tests with the phpunit-bridge of Symfony.", "symplify/easy-coding-standard": "Lets GrumPHP check coding standard.", "vimeo/psalm": "Lets GrumPHP discover errors in your code without running it.", From 42f89ca42d233b7938871bc036e8861830cb3421 Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Mon, 3 Jun 2024 07:35:53 +0200 Subject: [PATCH 07/11] #1126 update docs: include default path symfony console --- doc/tasks/symfony_console.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/tasks/symfony_console.md b/doc/tasks/symfony_console.md index 864f73968..f0e548a8e 100644 --- a/doc/tasks/symfony_console.md +++ b/doc/tasks/symfony_console.md @@ -22,12 +22,16 @@ grumphp: command: [ "lint:container", "-vvv" ] ``` +**Note:** GrumPHP will use the default Symfony console path `./bin/console` from the project root. + +### Parameters + **command** Specify the symfony command with defined options and arguments. Verify the installed console component version for available commands `./bin/console list` -## Note: Multiple Console command tasks +## Multiple Console command tasks [Run the same task twice with different configuration](../tasks.md#run-the-same-task-twice-with-different-configuration) From 4d34896ccd3a616e517a31945e145f34d4b06ee1 Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Mon, 3 Jun 2024 15:29:10 +0200 Subject: [PATCH 08/11] #1226 Add options: ignore_patterns, whitelist_patterns, triggered_by, run_always; add php excutable finder --- src/Task/SymfonyConsole.php | 38 +++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Task/SymfonyConsole.php b/src/Task/SymfonyConsole.php index b38348fcc..47c290130 100644 --- a/src/Task/SymfonyConsole.php +++ b/src/Task/SymfonyConsole.php @@ -12,6 +12,7 @@ use GrumPHP\Task\Context\GitPreCommitContext; use GrumPHP\Task\Context\RunContext; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Process\PhpExecutableFinder; /** @extends AbstractExternalTask */ class SymfonyConsole extends AbstractExternalTask @@ -23,8 +24,26 @@ public static function getConfigurableOptions(): ConfigOptionsResolver ->setDefaults([ 'bin' => './bin/console', 'command' => [], + 'ignore_patterns' => [], + 'whitelist_patterns' => [], + 'triggered_by' => ['php', 'yml', 'xml'], + 'run_always' => false, ]) + ->addAllowedTypes('bin', ['string']) ->addAllowedTypes('command', ['string[]']) + ->addAllowedTypes('ignore_patterns', ['array']) + ->addAllowedTypes('whitelist_patterns', ['array']) + ->addAllowedTypes('triggered_by', ['array']) + ->addAllowedTypes('run_always', ['bool']) + ->setAllowedValues( + 'bin', + static fn(string $bin): bool => '' !== $bin + ) + ->setAllowedValues( + 'command', + static fn(array $command): bool => '' !== \implode('', $command) + ) + ->setAllowedValues('bin', static fn(string $bin): bool => '' !== $bin) ->setRequired('command') ); } @@ -37,19 +56,22 @@ public function canRunInContext(ContextInterface $context): bool public function run(ContextInterface $context): TaskResultInterface { $config = $this->getConfig()->getOptions(); - if (0 === \count($context->getFiles())) { + + $files = $context->getFiles() + ->extensions($config['triggered_by']) + ->paths($config['whitelist_patterns'] ?? []) + ->notPaths($config['ignore_patterns'] ?? []); + if (!$config['run_always'] && 0 === \count($files)) { return TaskResult::createSkipped($this, $context); } - if ('' === \implode('', $config['command'])) { - return TaskResult::createNonBlockingFailed( - $this, - $context, - 'Missing "command" configuration for task "symfony_console".' - ); + $php = (new PhpExecutableFinder())->find(); + if (false === $php) { + return TaskResult::createFailed($this, $context, 'Unable to locate the PHP executable.'); } - $arguments = $this->processBuilder->createArgumentsForCommand($config['bin']); + $arguments = $this->processBuilder->createArgumentsForCommand($php); + $arguments->add($config['bin']); $arguments->addArgumentArray('%s', $config['command']); $process = $this->processBuilder->buildProcess($arguments); From 5a700bd3542ee8a6103ecbd6420d626baa770d75 Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Mon, 3 Jun 2024 15:29:41 +0200 Subject: [PATCH 09/11] #1226 update test cases --- test/Unit/Task/SymfonyConsoleTest.php | 137 +++++++++++++------------- 1 file changed, 67 insertions(+), 70 deletions(-) diff --git a/test/Unit/Task/SymfonyConsoleTest.php b/test/Unit/Task/SymfonyConsoleTest.php index e0ad84f34..82b361d00 100644 --- a/test/Unit/Task/SymfonyConsoleTest.php +++ b/test/Unit/Task/SymfonyConsoleTest.php @@ -4,16 +4,22 @@ namespace GrumPHPTest\Unit\Task; -use GrumPHP\Runner\TaskResultInterface; -use GrumPHP\Task\Context\ContextInterface; use GrumPHP\Task\Context\GitPreCommitContext; use GrumPHP\Task\Context\RunContext; use GrumPHP\Task\SymfonyConsole; use GrumPHP\Task\TaskInterface; use GrumPHP\Test\Task\AbstractExternalTaskTestCase; +use Symfony\Component\Process\PhpExecutableFinder; final class SymfonyConsoleTest extends AbstractExternalTaskTestCase { + private static string|false $php; + + private static function php(): string|false + { + return self::$php ??= (new PhpExecutableFinder())->find(); + } + protected function provideTask(): TaskInterface { return new SymfonyConsole( @@ -25,26 +31,20 @@ protected function provideTask(): TaskInterface public function provideConfigurableOptions(): iterable { yield 'default' => [ - [], - [ - 'bin' => './bin/console', - 'command' => [], - ] - ]; - - yield 'single-command' => [ [ 'command' => ['task:run'], ], [ 'bin' => './bin/console', - 'command' => [ - 'task:run' - ], + 'command' => ['task:run'], + 'ignore_patterns' => [], + 'whitelist_patterns' => [], + 'triggered_by' => ['php', 'yml', 'xml'], + 'run_always' => false, ] ]; - yield 'array-command' => [ + yield 'with-array-command' => [ [ 'command' => ['task:run', '--env', 'dev', '-vvv'], ], @@ -56,6 +56,10 @@ public function provideConfigurableOptions(): iterable 'dev', '-vvv' ], + 'ignore_patterns' => [], + 'whitelist_patterns' => [], + 'triggered_by' => ['php', 'yml', 'xml'], + 'run_always' => false, ] ]; } @@ -87,7 +91,7 @@ public function provideFailsOnStuff(): iterable $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), function() { $process = $this->mockProcess(1); - $this->mockProcessBuilder('./bin/console', $process); + $this->mockProcessBuilder(self::php(), $process); $this->formatter->format($process)->willReturn('nope'); }, 'nope' @@ -102,7 +106,18 @@ public function providePassesOnStuff(): iterable ], $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), function() { - $this->mockProcessBuilder('./bin/console', $this->mockProcess()); + $this->mockProcessBuilder(self::php(), $this->mockProcess()); + } + ]; + + yield 'exitCode0WhenRunAlways' => [ + [ + 'command' => ['--version'], + 'run_always' => true, + ], + $this->mockContext(RunContext::class, ['non-related.log']), + function() { + $this->mockProcessBuilder(self::php(), $this->mockProcess()); } ]; } @@ -110,11 +125,42 @@ function() { public function provideSkipsOnStuff(): iterable { yield 'no-files' => [ - [], + [ + 'command' => ['task:run'] + ], $this->mockContext(RunContext::class), function() { } ]; + + yield 'no-files-after-ignore-patterns' => [ + [ + 'command' => ['task:run'], + 'ignore_patterns' => ['test/'], + ], + $this->mockContext(RunContext::class, ['test/file.php']), + function() { + } + ]; + + yield 'no-files-after-whitelist-patterns' => [ + [ + 'command' => ['task:run'], + 'whitelist_patterns' => ['src/'], + ], + $this->mockContext(RunContext::class, ['config/file.php']), + function() { + } + ]; + + yield 'no-files-after-triggered-by' => [ + [ + 'command' => ['task:run'], + ], + $this->mockContext(RunContext::class, ['non-trigger-extension.log']), + function() { + } + ]; } public function provideExternalTaskRuns(): iterable @@ -124,8 +170,9 @@ public function provideExternalTaskRuns(): iterable 'command' => ['lint:container'] ], $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), - './bin/console', + self::php(), [ + './bin/console', 'lint:container', ] ]; @@ -140,8 +187,9 @@ public function provideExternalTaskRuns(): iterable ] ], $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), - './bin/console', + self::php(), [ + './bin/console', 'task:run', '--env', 'dev', @@ -149,55 +197,4 @@ public function provideExternalTaskRuns(): iterable ] ]; } - - /** - * @test - * @dataProvider provideFailsNonBlockingOnStuff - */ - public function it_fails_non_blocking_on_stuff( - array $config, - ContextInterface $context, - callable $configurator, - string $expectedErrorMessage, - ): void { - $task = $this->configureTask($config); - \Closure::bind($configurator, $this)($task->getConfig()->getOptions(), $context); - $result = $task->run($context); - - self::assertInstanceOf(TaskResultInterface::class, $result); - self::assertSame(TaskResultInterface::NONBLOCKING_FAILED, $result->getResultCode()); - self::assertSame($task, $result->getTask()); - self::assertSame($context, $result->getContext()); - self::assertSame($expectedErrorMessage, $result->getMessage()); - } - - public function provideFailsNonBlockingOnStuff(): iterable - { - yield 'missing-command' => [ - [ - // missing command - ], - $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), - function() {}, - 'Missing "command" configuration for task "symfony_console".' - ]; - - yield 'empty-command-array' => [ - [ - 'command' => [], // missing command config - ], - $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), - function() {}, - 'Missing "command" configuration for task "symfony_console".' - ]; - - yield 'empty-command-data' => [ - [ - 'command' => [""], // empty command config - ], - $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), - function() {}, - 'Missing "command" configuration for task "symfony_console".' - ]; - } } From 250ca759e2998f7aebfa93d9b2ef2a413f492fea Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Mon, 3 Jun 2024 15:30:01 +0200 Subject: [PATCH 10/11] #1226 update symfony_console docs --- doc/tasks/symfony_console.md | 49 ++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/doc/tasks/symfony_console.md b/doc/tasks/symfony_console.md index f0e548a8e..3d3210df5 100644 --- a/doc/tasks/symfony_console.md +++ b/doc/tasks/symfony_console.md @@ -19,18 +19,63 @@ The task lives under the `symfony_console` namespace and has following configura grumphp: tasks: symfony_console: + bin: "./bin/console" command: [ "lint:container", "-vvv" ] + ignore_patterns: [], + whitelist_patterns: [], + triggered_by: ['php', 'yml', 'xml'], + run_always: false ``` -**Note:** GrumPHP will use the default Symfony console path `./bin/console` from the project root. - ### Parameters +**bin** + +*Default: `./bin/console`* + +Specify the path to the Symfony Console script. + **command** +*Default: `[]`* + Specify the symfony command with defined options and arguments. Verify the installed console component version for available commands `./bin/console list` +**ignore_patterns** + +*Default: []* + +This is a list of file patterns that will be ignored by the Symfony console task. +Leave this option blank to run the task for all files defined in the whitelist_patterns and or triggered_by extensions. + +**whitelist_patterns** + +*Default: []* + +This is a list of regex patterns that will filter files to validate. With this option you can skip files like tests. +This option is used in relation with the parameter `triggered_by`. +For example: whitelist files in `src/FolderA/` and `src/FolderB/` you can use +```yaml +whitelist_patterns: + - /^src\/FolderA\/(.*)/ + - /^src\/FolderB\/(.*)/ +``` + +**triggered_by** + +*Default: [php, yml, xml]* + +This option will specify which file extensions will trigger the Symfony console task. +By default, altering a `php`, `yml`, `xml` file will trigger the task. +You can overwrite this option to whatever filetype you want to validate! + +**run_always** + +*Default: false* + +If this is set to `true` the Symfony console task will be executed on every commit, regardless of any modified files. + ## Multiple Console command tasks [Run the same task twice with different configuration](../tasks.md#run-the-same-task-twice-with-different-configuration) From 3900ffb1ddaf619dd885bc5006dce919f58ec74f Mon Sep 17 00:00:00 2001 From: Filippe PHPro Date: Fri, 14 Jun 2024 14:18:45 +0200 Subject: [PATCH 11/11] Update composer, docs, remove php excutable finder --- composer.json | 1 - doc/tasks/symfony_console.md | 8 ++------ src/Task/SymfonyConsole.php | 8 +------- test/Unit/Task/SymfonyConsoleTest.php | 18 +++++------------- 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/composer.json b/composer.json index 748ab5429..00d9b0e17 100644 --- a/composer.json +++ b/composer.json @@ -78,7 +78,6 @@ "sebastian/phpcpd": "Lets GrumPHP find duplicated code.", "squizlabs/php_codesniffer": "Lets GrumPHP sniff on your code.", "sstalle/php7cc": "Lets GrumPHP check PHP 5.3 - 5.6 code compatibility with PHP 7.", - "symfony/console": "Lets GrumPHP run Symfony Console commands.", "symfony/phpunit-bridge": "Lets GrumPHP run your unit tests with the phpunit-bridge of Symfony.", "symplify/easy-coding-standard": "Lets GrumPHP check coding standard.", "vimeo/psalm": "Lets GrumPHP discover errors in your code without running it.", diff --git a/doc/tasks/symfony_console.md b/doc/tasks/symfony_console.md index 3d3210df5..525fdc3f3 100644 --- a/doc/tasks/symfony_console.md +++ b/doc/tasks/symfony_console.md @@ -2,13 +2,9 @@ Run a symfony console command. -## Composer +## Requirements -Requires the Symfony Console component: [Console Component](https://symfony.com/components/Console) - -```bash -composer require symfony/console -``` +This task requires a Symfony application with console component. ## Config diff --git a/src/Task/SymfonyConsole.php b/src/Task/SymfonyConsole.php index 47c290130..34726945d 100644 --- a/src/Task/SymfonyConsole.php +++ b/src/Task/SymfonyConsole.php @@ -12,7 +12,6 @@ use GrumPHP\Task\Context\GitPreCommitContext; use GrumPHP\Task\Context\RunContext; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Process\PhpExecutableFinder; /** @extends AbstractExternalTask */ class SymfonyConsole extends AbstractExternalTask @@ -65,12 +64,7 @@ public function run(ContextInterface $context): TaskResultInterface return TaskResult::createSkipped($this, $context); } - $php = (new PhpExecutableFinder())->find(); - if (false === $php) { - return TaskResult::createFailed($this, $context, 'Unable to locate the PHP executable.'); - } - - $arguments = $this->processBuilder->createArgumentsForCommand($php); + $arguments = $this->processBuilder->createArgumentsForCommand('php'); $arguments->add($config['bin']); $arguments->addArgumentArray('%s', $config['command']); diff --git a/test/Unit/Task/SymfonyConsoleTest.php b/test/Unit/Task/SymfonyConsoleTest.php index 82b361d00..2306db5ba 100644 --- a/test/Unit/Task/SymfonyConsoleTest.php +++ b/test/Unit/Task/SymfonyConsoleTest.php @@ -9,17 +9,9 @@ use GrumPHP\Task\SymfonyConsole; use GrumPHP\Task\TaskInterface; use GrumPHP\Test\Task\AbstractExternalTaskTestCase; -use Symfony\Component\Process\PhpExecutableFinder; final class SymfonyConsoleTest extends AbstractExternalTaskTestCase { - private static string|false $php; - - private static function php(): string|false - { - return self::$php ??= (new PhpExecutableFinder())->find(); - } - protected function provideTask(): TaskInterface { return new SymfonyConsole( @@ -91,7 +83,7 @@ public function provideFailsOnStuff(): iterable $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), function() { $process = $this->mockProcess(1); - $this->mockProcessBuilder(self::php(), $process); + $this->mockProcessBuilder('php', $process); $this->formatter->format($process)->willReturn('nope'); }, 'nope' @@ -106,7 +98,7 @@ public function providePassesOnStuff(): iterable ], $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), function() { - $this->mockProcessBuilder(self::php(), $this->mockProcess()); + $this->mockProcessBuilder('php', $this->mockProcess()); } ]; @@ -117,7 +109,7 @@ function() { ], $this->mockContext(RunContext::class, ['non-related.log']), function() { - $this->mockProcessBuilder(self::php(), $this->mockProcess()); + $this->mockProcessBuilder('php', $this->mockProcess()); } ]; } @@ -170,7 +162,7 @@ public function provideExternalTaskRuns(): iterable 'command' => ['lint:container'] ], $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), - self::php(), + 'php', [ './bin/console', 'lint:container', @@ -187,7 +179,7 @@ public function provideExternalTaskRuns(): iterable ] ], $this->mockContext(RunContext::class, ['hello.php', 'hello2.php']), - self::php(), + 'php', [ './bin/console', 'task:run',