Skip to content

Commit 20dc5a3

Browse files
committed
Use the new API to support running longer commands
1 parent bb2b150 commit 20dc5a3

File tree

2 files changed

+93
-49
lines changed

2 files changed

+93
-49
lines changed

src/BrefCloudClient.php

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,20 +197,31 @@ public function removeEnvironment(int $environmentId): void
197197
}
198198

199199
/**
200-
* @return array{success: bool, output: string}
201-
*
202200
* @throws HttpExceptionInterface
203201
* @throws ExceptionInterface
204202
*/
205-
public function startCommand(string $appName, string $environment, string $command): array
203+
public function startCommand(int $environmentId, string $command): int
206204
{
207-
return $this->client->request('POST', '/api/v1/commands', [
205+
return $this->client->request('POST', '/api/v1/commands/start', [
208206
'json' => [
209-
'appName' => $appName,
210-
'environmentName' => $environment,
211-
'consoleCommand' => $command,
207+
'environmentId' => $environmentId,
208+
'command' => $command,
212209
],
213-
])->toArray();
210+
])->toArray()['id'];
211+
}
212+
213+
/**
214+
* @return array{
215+
* status: 'not_started'|'started'|'success'|'failed',
216+
* output: string,
217+
* }
218+
*
219+
* @throws HttpExceptionInterface
220+
* @throws ExceptionInterface
221+
*/
222+
public function getCommand(int $id): array
223+
{
224+
return $this->client->request('GET', "/api/v1/commands/$id")->toArray();
214225
}
215226

216227
/**

src/Commands/Command.php

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,68 +5,101 @@
55
use Bref\Cli\BrefCloudClient;
66
use Bref\Cli\Cli\IO;
77
use Bref\Cli\Cli\Styles;
8-
use Bref\Cli\Config;
98
use JsonException;
109
use Symfony\Component\Console\Input\InputArgument;
1110
use Symfony\Component\Console\Input\InputInterface;
12-
use Symfony\Component\Console\Input\InputOption;
1311
use Symfony\Component\Console\Output\OutputInterface;
12+
use function Amp\delay;
1413

15-
class Command extends \Symfony\Component\Console\Command\Command
14+
class Command extends ApplicationCommand
1615
{
1716
protected function configure(): void
1817
{
1918
$this
2019
->setName('command')
2120
->setDescription('Run a CLI command in the deployed application')
22-
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'The location of the configuration file to use')
23-
->addArgument('args', InputArgument::OPTIONAL, 'The command to run', '')
24-
->addOption('app', null, InputOption::VALUE_REQUIRED, 'The app name (if outside of a project directory)')
25-
->addOption('env', 'e', InputOption::VALUE_REQUIRED, 'The environment to deploy to', 'dev');
21+
->addArgument('args', InputArgument::OPTIONAL, 'The command to run', '');
22+
parent::configure();
2623
}
2724

2825
protected function execute(InputInterface $input, OutputInterface $output): int
2926
{
30-
/** @var string|null $configFileName */
31-
$configFileName = $input->getOption('config');
27+
[
28+
'appName' => $appName,
29+
'environmentName' => $environmentName,
30+
'team' => $team,
31+
] = $this->parseStandardOptions($input);
32+
3233
/** @var string $command */
3334
$command = $input->getArgument('args');
34-
/** @var string $environment */
35-
$environment = $input->getOption('env');
36-
/** @var string|null $appName */
37-
$appName = $input->getOption('app');
38-
if (! $appName) {
39-
$appName = Config::loadConfig($configFileName, $environment, null)['name'];
40-
}
35+
36+
IO::spin('starting command');
4137

4238
$brefCloud = new BrefCloudClient;
43-
$result = $brefCloud->startCommand($appName, $environment, $command);
44-
45-
if ($result['success']) {
46-
IO::writeln($result['output']);
47-
} else {
48-
try {
49-
$errorDetails = json_decode($result['output'], true, 512, JSON_THROW_ON_ERROR);
50-
if (is_array($errorDetails) && isset($errorDetails['errorType'], $errorDetails['errorMessage'])) {
51-
$message = nl2br($errorDetails['errorMessage']);
52-
IO::writeln([
53-
'',
54-
Styles::red('ERROR'),
55-
Styles::gray($errorDetails['errorType']),
56-
'',
57-
$message,
58-
]);
59-
if (isset($errorDetails['stackTrace']) && is_array($errorDetails['stackTrace'])) {
60-
IO::verbose($errorDetails['stackTrace']);
61-
}
62-
} else {
63-
IO::writeln(Styles::red($result['output']));
64-
}
65-
} catch (JsonException) {
66-
IO::writeln(Styles::red($result['output']));
39+
$environment = $brefCloud->findEnvironment($team, $appName, $environmentName);
40+
$id = $brefCloud->startCommand($environment['id'], $command);
41+
42+
IO::spin('running');
43+
44+
// Timeout after 2 minutes and 10 seconds
45+
$timeout = 130;
46+
$startTime = time();
47+
48+
while (true) {
49+
$invocation = $brefCloud->getCommand($id);
50+
51+
if ($invocation['status'] === 'success') {
52+
IO::spinClear();
53+
IO::writeln($invocation['output']);
54+
return 0;
55+
}
56+
57+
if ($invocation['status'] === 'failed') {
58+
IO::spinClear();
59+
$this->writeErrorDetails($invocation['output']);
60+
return 1;
61+
}
62+
63+
if ((time() - $startTime) > $timeout) {
64+
IO::spinClear();
65+
IO::writeln(Styles::red('Timed out'));
66+
IO::writeln(Styles::gray('The execution timed out after 2 minutes, the command might still be running'));
67+
return 1;
6768
}
69+
70+
delay(1);
6871
}
72+
}
73+
74+
private function writeErrorDetails(string $output): void
75+
{
76+
try {
77+
$errorDetails = json_decode($output, true, 512, JSON_THROW_ON_ERROR);
78+
if (! is_array($errorDetails)
79+
|| ! isset($errorDetails['errorType'], $errorDetails['errorMessage'])
80+
|| ! is_string($errorDetails['errorType'])
81+
|| ! is_string($errorDetails['errorMessage'])) {
82+
IO::writeln(Styles::red($output));
83+
return;
84+
}
85+
86+
$errorType = $errorDetails['errorType'];
87+
if ($errorType === 'Bref\ConsoleRuntime\CommandFailed') {
88+
// No need to show this class, it's noise
89+
$errorType = '';
90+
}
6991

70-
return $result['success'] ? 0 : 1;
92+
IO::writeln([
93+
'',
94+
Styles::bold(Styles::red('ERROR')) . ' ' . Styles::gray($errorType),
95+
'',
96+
$errorDetails['errorMessage'],
97+
]);
98+
if (isset($errorDetails['stackTrace']) && is_array($errorDetails['stackTrace'])) {
99+
IO::verbose($errorDetails['stackTrace']);
100+
}
101+
} catch (JsonException) {
102+
IO::writeln(Styles::red($output));
103+
}
71104
}
72105
}

0 commit comments

Comments
 (0)