Skip to content

Commit e970657

Browse files
committed
refactor: move command parsing to trait
1 parent 9f697bc commit e970657

3 files changed

Lines changed: 88 additions & 6 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <support@ymirapp.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli\Command;
15+
16+
trait ParsesConsoleCommandTrait
17+
{
18+
/**
19+
* Parses a command string into command parts.
20+
*/
21+
protected function parseCommand(string $command): array
22+
{
23+
return collect(preg_split('/\s+/', trim($command)) ?: [])
24+
->filter(function (string $commandPart): bool {
25+
return '' !== $commandPart;
26+
})
27+
->values()
28+
->all();
29+
}
30+
31+
/**
32+
* Removes the first matching command prefix from a command string.
33+
*/
34+
protected function stripCommandPrefix(string $command, $prefixes): string
35+
{
36+
$prefix = collect((array) $prefixes)->first(function (string $prefix) use ($command): bool {
37+
return str_starts_with($command, sprintf('%s ', $prefix));
38+
});
39+
40+
return is_string($prefix) ? substr($command, strlen(sprintf('%s ', $prefix))) : $command;
41+
}
42+
}

src/Command/WordPress/WpCliCommand.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Console\Input\InputOption;
1919
use Ymir\Cli\Command\AbstractCommand;
2020
use Ymir\Cli\Command\LocalProjectCommandInterface;
21+
use Ymir\Cli\Command\ParsesConsoleCommandTrait;
2122
use Ymir\Cli\Exception\InvalidInputException;
2223
use Ymir\Cli\Exception\Project\UnsupportedProjectException;
2324
use Ymir\Cli\Project\Type\AbstractWordPressProjectType;
@@ -26,6 +27,7 @@
2627
class WpCliCommand extends AbstractCommand implements LocalProjectCommandInterface
2728
{
2829
use HandlesWpCliInvocationTrait;
30+
use ParsesConsoleCommandTrait;
2931

3032
/**
3133
* The name of the command.
@@ -67,14 +69,16 @@ protected function perform()
6769
$command = $this->output->ask('What WP-CLI command would you like to run?');
6870
}
6971

70-
if (str_starts_with($command, 'wp ')) {
71-
$command = substr($command, 3);
72-
}
72+
$command = $this->stripCommandPrefix($command, 'wp');
73+
74+
$commandParts = $this->parseCommand($command);
75+
$commandName = $commandParts[0] ?? '';
76+
$subCommandName = $commandParts[1] ?? '';
7377

74-
if (in_array($command, ['shell'])) {
78+
if ('shell' === $commandName) {
7579
throw new InvalidInputException(sprintf('The "wp %s" command isn\'t available remotely', $command));
76-
} elseif (in_array($command, ['db import', 'db export'])) {
77-
throw new InvalidInputException(sprintf('Please use the "ymir database:%s" command instead of the "wp %s" command', substr($command, 3), $command));
80+
} elseif ('db' === $commandName && in_array($subCommandName, ['import', 'export'], true)) {
81+
throw new InvalidInputException(sprintf('Please use the "ymir database:%s" command instead of the "wp %s" command', $subCommandName, $command));
7882
}
7983

8084
$this->output->info(sprintf('Running "<comment>wp %s</comment>" %s "<comment>%s</comment>" environment', $command, $async ? 'asynchronously on' : 'on', $environment->getName()));

tests/Integration/Command/WordPress/WpCliCommandTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,24 @@ public function testPerformThrowsExceptionIfCommandIsDbImport(): void
139139
$this->executeCommand(WpCliCommand::NAME, ['wp-command' => ['db', 'import'], '--environment' => 'production']);
140140
}
141141

142+
public function testPerformThrowsExceptionIfCommandIsDbImportWithArguments(): void
143+
{
144+
$this->expectException(InvalidInputException::class);
145+
$this->expectExceptionMessage('Please use the "ymir database:import" command instead of the "wp db import ./dump.sql" command');
146+
147+
$this->setupActiveTeam();
148+
$project = $this->setupValidProject(1, 'project', [], 'wordpress', WordPressProjectType::class);
149+
$environment = EnvironmentFactory::create(['name' => 'production']);
150+
151+
$this->apiClient->shouldReceive('getEnvironments')->with(\Mockery::type(Project::class))->andReturn(new ResourceCollection([$environment]));
152+
153+
$this->bootApplication([new WpCliCommand($this->apiClient, $this->createExecutionContextFactory([
154+
Environment::class => function () { return new EnvironmentDefinition(); },
155+
]))]);
156+
157+
$this->executeCommand(WpCliCommand::NAME, ['wp-command' => ['db', 'import', './dump.sql'], '--environment' => 'production']);
158+
}
159+
142160
public function testPerformThrowsExceptionIfCommandIsShell(): void
143161
{
144162
$this->expectException(InvalidInputException::class);
@@ -157,6 +175,24 @@ public function testPerformThrowsExceptionIfCommandIsShell(): void
157175
$this->executeCommand(WpCliCommand::NAME, ['wp-command' => ['shell'], '--environment' => 'production']);
158176
}
159177

178+
public function testPerformThrowsExceptionIfCommandIsShellWithArguments(): void
179+
{
180+
$this->expectException(InvalidInputException::class);
181+
$this->expectExceptionMessage('The "wp shell --prompt=ymir" command isn\'t available remotely');
182+
183+
$this->setupActiveTeam();
184+
$project = $this->setupValidProject(1, 'project', [], 'wordpress', WordPressProjectType::class);
185+
$environment = EnvironmentFactory::create(['name' => 'production']);
186+
187+
$this->apiClient->shouldReceive('getEnvironments')->with(\Mockery::type(Project::class))->andReturn(new ResourceCollection([$environment]));
188+
189+
$this->bootApplication([new WpCliCommand($this->apiClient, $this->createExecutionContextFactory([
190+
Environment::class => function () { return new EnvironmentDefinition(); },
191+
]))]);
192+
193+
$this->executeCommand(WpCliCommand::NAME, ['wp-command' => ['shell', '--prompt=ymir'], '--environment' => 'production']);
194+
}
195+
160196
public function testPerformThrowsExceptionIfProjectIsNotWordPress(): void
161197
{
162198
$this->expectException(UnsupportedProjectException::class);

0 commit comments

Comments
 (0)