Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1126 bin console task sf #1138

Merged
merged 11 commits into from
Jun 14, 2024
7 changes: 7 additions & 0 deletions resources/config/tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
64 changes: 64 additions & 0 deletions src/Task/SymfonyConsole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace GrumPHP\Task;

use GrumPHP\Formatter\ProcessFormatterInterface;
use GrumPHP\Runner\TaskResult;
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

/** @extends AbstractExternalTask<ProcessFormatterInterface> */
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();
veewee marked this conversation as resolved.
Show resolved Hide resolved
if (0 === \count($context->getFiles())) {
return TaskResult::createSkipped($this, $context);
}

if (0 === \count($config['command'])) {
return TaskResult::createNonBlockingFailed(
veewee marked this conversation as resolved.
Show resolved Hide resolved
$this,
$context,
'Missing "command" configuration for task "symfony_console".'
);
}

$arguments = $this->processBuilder->createArgumentsForCommand($config['bin']);
bortefi marked this conversation as resolved.
Show resolved Hide resolved
$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);
}
}
194 changes: 194 additions & 0 deletions test/Unit/Task/SymfonyConsoleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<?php

declare(strict_types=1);

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;

final class SymfonyConsoleTest extends AbstractExternalTaskTestCase
{
protected function provideTask(): TaskInterface
{
return new SymfonyConsole(
$this->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".'
];
}
}