From 10957d4260b547dd0dfa703f0ef1cd4328aa4578 Mon Sep 17 00:00:00 2001 From: Alexandre Dias Date: Fri, 28 Jun 2024 16:46:46 +0100 Subject: [PATCH 1/4] Add gherkin_lint task --- composer.json | 3 +- doc/tasks.md | 1 + doc/tasks/gherkin_lint.md | 26 ++++++++ resources/config/tasks.yml | 7 ++ src/Task/GherkinLint.php | 69 +++++++++++++++++++ test/Unit/Task/GherkinLintTest.php | 102 +++++++++++++++++++++++++++++ 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 doc/tasks/gherkin_lint.md create mode 100644 src/Task/GherkinLint.php create mode 100644 test/Unit/Task/GherkinLintTest.php diff --git a/composer.json b/composer.json index 00d9b0e1..ad632c0f 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,8 @@ "friendsoftwig/twigcs": "Lets GrumPHP check Twig coding standard.", "infection/infection": "Lets GrumPHP evaluate the quality your unit tests", "maglnet/composer-require-checker": "Lets GrumPHP analyze composer dependencies.", - "malukenho/kawaii-gherkin": "Lets GrumPHP lint your Gherkin files.", + "malukenho/kawaii-gherkin": "Lets GrumPHP lint/fix your Gherkin files.", + "dantleech/ngherkin-lint-php": "Lets GrumPHP lint your Gherkin files.", "nette/tester": "Lets GrumPHP run your unit tests with nette tester.", "nikic/php-parser": "Lets GrumPHP run static analyses through your PHP files.", "pestphp/pest": "Lets GrumPHP run your unit test with Pest PHP", diff --git a/doc/tasks.md b/doc/tasks.md index 64f3a4e6..8cf7db78 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -23,6 +23,7 @@ grumphp: eslint: ~ file_size: ~ gherkin: ~ + gherkin_lint: ~ git_blacklist: ~ git_branch_name: ~ git_commit_message: ~ diff --git a/doc/tasks/gherkin_lint.md b/doc/tasks/gherkin_lint.md new file mode 100644 index 00000000..c4e9949b --- /dev/null +++ b/doc/tasks/gherkin_lint.md @@ -0,0 +1,26 @@ +# Gherkin Lint + +The Gherkin Lint task will lint your Gherkin feature files. +It lives under the `gherkin_lint` namespace and has following configurable parameters: + +```yaml +# grumphp.yml +grumphp: + tasks: + gherkin_lint: + directory: 'features' + config: ~ +``` + +**directory** + +*Default: 'features'* + +This option will specify the location of your Gherkin feature files. +By default, the Behat preferred `features` folder is chosen. + +**config** + +*Default: null* + +By default, all rules are enabled. To customize or disable them, create a configuration file named `gherkinlint.json` in the current directory. You need to set the path value in the configuration parameters. diff --git a/resources/config/tasks.yml b/resources/config/tasks.yml index d494e23c..b1e42a69 100644 --- a/resources/config/tasks.yml +++ b/resources/config/tasks.yml @@ -97,6 +97,13 @@ services: tags: - {name: grumphp.task, task: gherkin} + GrumPHP\Task\GherkinLint: + arguments: + - '@process_builder' + - '@formatter.raw_process' + tags: + - { name: grumphp.task, task: gherkin_lint } + GrumPHP\Task\Git\Blacklist: arguments: - '@process_builder' diff --git a/src/Task/GherkinLint.php b/src/Task/GherkinLint.php new file mode 100644 index 00000000..c2934f33 --- /dev/null +++ b/src/Task/GherkinLint.php @@ -0,0 +1,69 @@ + + */ +class GherkinLint extends AbstractExternalTask +{ + public static function getConfigurableOptions(): ConfigOptionsResolver + { + $resolver = new OptionsResolver(); + $resolver->setDefaults([ + 'directory' => 'features', + 'config' => null, + ]); + + $resolver->addAllowedTypes('directory', ['string']); + $resolver->addAllowedTypes('config', ['null', 'string']); + $resolver->addAllowedValues('config', [null, 'text']); + + return ConfigOptionsResolver::fromOptionsResolver($resolver); + } + + /** + * {@inheritdoc} + */ + public function canRunInContext(ContextInterface $context): bool + { + return $context instanceof GitPreCommitContext || $context instanceof RunContext; + } + + /** + * {@inheritdoc} + */ + public function run(ContextInterface $context): TaskResultInterface + { + $config = $this->getConfig()->getOptions(); + $files = $context->getFiles()->extensions(['feature']); + if (0 === \count($files)) { + return TaskResult::createSkipped($this, $context); + } + + $arguments = $this->processBuilder->createArgumentsForCommand('gherkinlint'); + $arguments->add('lint'); + $arguments->addOptionalArgument('--config=%s', $config['align']); + $arguments->add($config['directory']); + + $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/GherkinLintTest.php b/test/Unit/Task/GherkinLintTest.php new file mode 100644 index 00000000..d953230d --- /dev/null +++ b/test/Unit/Task/GherkinLintTest.php @@ -0,0 +1,102 @@ +processBuilder->reveal(), + $this->formatter->reveal() + ); + } + + public function provideConfigurableOptions(): iterable + { + yield 'defaults' => [ + [], + [ + 'directory' => 'features', + 'config' => null, + ] + ]; + } + + 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' => [ + [], + $this->mockContext(RunContext::class, ['hello.feature']), + function () { + $this->mockProcessBuilder('gherkinlint', $process = $this->mockProcess(1)); + $this->formatter->format($process)->willReturn('nope'); + }, + 'nope' + ]; + } + + public function providePassesOnStuff(): iterable + { + yield 'exitCode0' => [ + [], + $this->mockContext(RunContext::class, ['hello.feature']), + function () { + $this->mockProcessBuilder('gherkinlint', $this->mockProcess(0)); + } + ]; + } + + public function provideSkipsOnStuff(): iterable + { + yield 'no-files' => [ + [], + $this->mockContext(RunContext::class), + function () {} + ]; + yield 'no-files-after-triggered-by' => [ + [], + $this->mockContext(RunContext::class, ['notafeaturefile.txt']), + function () {} + ]; + } + + public function provideExternalTaskRuns(): iterable + { + yield 'defaults' => [ + [], + $this->mockContext(RunContext::class, ['hello.feature', 'hello2.feature']), + 'gherkinlint', + [ + 'lint', + 'features', + ] + ]; + } +} From ad8695cae690cee693c2e41aeb04cd02326d46b6 Mon Sep 17 00:00:00 2001 From: Alexandre Dias Date: Fri, 28 Jun 2024 16:55:23 +0100 Subject: [PATCH 2/4] Missing GherkinLint. --- src/Task/GherkinLint.php | 2 +- test/Unit/Task/GherkinLintTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Task/GherkinLint.php b/src/Task/GherkinLint.php index c2934f33..df9ad74a 100644 --- a/src/Task/GherkinLint.php +++ b/src/Task/GherkinLint.php @@ -54,7 +54,7 @@ public function run(ContextInterface $context): TaskResultInterface $arguments = $this->processBuilder->createArgumentsForCommand('gherkinlint'); $arguments->add('lint'); - $arguments->addOptionalArgument('--config=%s', $config['align']); + $arguments->addOptionalArgument('--config=%s', $config['config']); $arguments->add($config['directory']); $process = $this->processBuilder->buildProcess($arguments); diff --git a/test/Unit/Task/GherkinLintTest.php b/test/Unit/Task/GherkinLintTest.php index d953230d..d26127b4 100644 --- a/test/Unit/Task/GherkinLintTest.php +++ b/test/Unit/Task/GherkinLintTest.php @@ -6,7 +6,7 @@ use GrumPHP\Task\Context\GitPreCommitContext; use GrumPHP\Task\Context\RunContext; -use GrumPHP\Task\Gherkin; +use GrumPHP\Task\GherkinLint; use GrumPHP\Task\TaskInterface; use GrumPHP\Test\Task\AbstractExternalTaskTestCase; @@ -14,7 +14,7 @@ class GherkinLintTest extends AbstractExternalTaskTestCase { protected function provideTask(): TaskInterface { - return new Gherkin( + return new GherkinLint( $this->processBuilder->reveal(), $this->formatter->reveal() ); From d9066f949ea3747b75f3f8f5281c662da4460263 Mon Sep 17 00:00:00 2001 From: Alexandre Dias Date: Fri, 28 Jun 2024 17:04:03 +0100 Subject: [PATCH 3/4] Normalize composer. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ad632c0f..edbbe9ae 100644 --- a/composer.json +++ b/composer.json @@ -52,6 +52,7 @@ "brianium/paratest": "Lets GrumPHP run PHPUnit in parallel.", "codeception/codeception": "Lets GrumPHP run your project's full stack tests", "consolidation/robo": "Lets GrumPHP run your automated PHP tasks.", + "dantleech/ngherkin-lint-php": "Lets GrumPHP lint your Gherkin files.", "designsecurity/progpilot": "Lets GrumPHP be sure that there are no vulnerabilities in your code.", "doctrine/orm": "Lets GrumPHP validate your Doctrine mapping files.", "enlightn/security-checker": "Lets GrumPHP be sure that there are no known security issues.", @@ -61,7 +62,6 @@ "infection/infection": "Lets GrumPHP evaluate the quality your unit tests", "maglnet/composer-require-checker": "Lets GrumPHP analyze composer dependencies.", "malukenho/kawaii-gherkin": "Lets GrumPHP lint/fix your Gherkin files.", - "dantleech/ngherkin-lint-php": "Lets GrumPHP lint your Gherkin files.", "nette/tester": "Lets GrumPHP run your unit tests with nette tester.", "nikic/php-parser": "Lets GrumPHP run static analyses through your PHP files.", "pestphp/pest": "Lets GrumPHP run your unit test with Pest PHP", From 9730013989f495dde26cd108cad1c71f7d56f2e2 Mon Sep 17 00:00:00 2001 From: Alexandre Dias Date: Tue, 2 Jul 2024 13:44:01 +0100 Subject: [PATCH 4/4] Typo in dantleech/gherkin-lint. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index edbbe9ae..39c15be6 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "brianium/paratest": "Lets GrumPHP run PHPUnit in parallel.", "codeception/codeception": "Lets GrumPHP run your project's full stack tests", "consolidation/robo": "Lets GrumPHP run your automated PHP tasks.", - "dantleech/ngherkin-lint-php": "Lets GrumPHP lint your Gherkin files.", + "dantleech/gherkin-lint": "Lets GrumPHP lint your Gherkin files.", "designsecurity/progpilot": "Lets GrumPHP be sure that there are no vulnerabilities in your code.", "doctrine/orm": "Lets GrumPHP validate your Doctrine mapping files.", "enlightn/security-checker": "Lets GrumPHP be sure that there are no known security issues.",