diff --git a/src/BrefCloudClient.php b/src/BrefCloudClient.php index 6ac0c6e..7fab979 100644 --- a/src/BrefCloudClient.php +++ b/src/BrefCloudClient.php @@ -305,15 +305,17 @@ public function removeEnvironment(int $environmentId): void } /** + * @param bool $ansi Ask for colors: Bref Cloud adds `--ansi` to the command when the application's console supports it. * @throws HttpExceptionInterface * @throws ExceptionInterface */ - public function startCommand(int $environmentId, string $command): int + public function startCommand(int $environmentId, string $command, bool $ansi = false): int { return $this->client->request('POST', '/api/v1/commands/start', [ 'json' => [ 'environmentId' => $environmentId, 'command' => $command, + 'ansi' => $ansi, ], ])->toArray()['id']; } diff --git a/src/Commands/Command.php b/src/Commands/Command.php index 0b0a29e..8affa2c 100644 --- a/src/Commands/Command.php +++ b/src/Commands/Command.php @@ -13,6 +13,12 @@ class Command extends ApplicationCommand { + public function __construct( + private readonly ?BrefCloudClient $brefCloud = null, + ) { + parent::__construct(); + } + protected function configure(): void { $this @@ -35,9 +41,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int IO::spin('starting command'); - $brefCloud = new BrefCloudClient; + $brefCloud = $this->brefCloud ?? new BrefCloudClient; $environment = $brefCloud->findEnvironment($team, $appName, $environmentName); - $id = $brefCloud->startCommand($environment['id'], $command); + // Colors when the output is a terminal that shows them, the command's output is printed as is + $id = $brefCloud->startCommand($environment['id'], $command, $output->isDecorated()); IO::spin('running'); diff --git a/tests/Commands/CommandTest.php b/tests/Commands/CommandTest.php new file mode 100644 index 0000000..18ee731 --- /dev/null +++ b/tests/Commands/CommandTest.php @@ -0,0 +1,66 @@ +configFile = sys_get_temp_dir() . '/bref-cli-test-' . bin2hex(random_bytes(4)) . '.yml'; + file_put_contents($this->configFile, "service: shop\nbref:\n team: acme\n"); + } + + protected function tearDown(): void + { + unlink($this->configFile); + parent::tearDown(); + } + + public function test_asks_for_colors_when_the_output_is_a_terminal(): void + { + [$status, $display] = $this->runCommand(decorated: true); + + $this->assertSame(0, $status, $display); + $this->assertSame(['environmentId' => 12, 'command' => 'about', 'ansi' => true], $this->requestBodies['/api/v1/commands/start']); + // Printed as is: the terminal renders the colors + $this->assertStringContainsString("\e[32mLaravel\e[39m", $display); + } + + public function test_no_colors_when_the_output_is_not_a_terminal(): void + { + [$status, $display] = $this->runCommand(decorated: false); + + $this->assertSame(0, $status, $display); + $this->assertFalse($this->requestBodies['/api/v1/commands/start']['ansi']); + } + + /** + * @return array{int, string} The exit code and the output + */ + private function runCommand(bool $decorated): array + { + $command = new Command($this->brefCloud([ + '/api/v1/environments/find' => $this->environment(), + '/api/v1/commands/start' => ['id' => 5], + '/api/v1/commands/5' => ['status' => 'success', 'output' => "\e[32mLaravel\e[39m 13"], + ])); + $input = new ArrayInput(['args' => 'about', '--config' => $this->configFile]); + $input->setInteractive(false); + $output = new BufferedOutput(decorated: $decorated); + // What the application does before running a command + IO::init($input, $output); + + $status = $command->run($input, $output); + IO::stop(); + + return [$status, $output->fetch()]; + } +} diff --git a/tests/Commands/CommandTestCase.php b/tests/Commands/CommandTestCase.php index 3664714..d4819a0 100644 --- a/tests/Commands/CommandTestCase.php +++ b/tests/Commands/CommandTestCase.php @@ -14,6 +14,8 @@ abstract class CommandTestCase extends TestCase private array $agentVariables = []; /** @var list Paths and query strings of the requests sent to Bref Cloud */ protected array $requests = []; + /** @var array JSON bodies of the requests sent to Bref Cloud, indexed by path */ + protected array $requestBodies = []; protected function setUp(): void { @@ -41,10 +43,13 @@ protected function runByAnAgent(): void */ protected function brefCloud(array $routes): BrefCloudClient { - $client = new MockHttpClient(function (string $method, string $url) use ($routes): MockResponse { + $client = new MockHttpClient(function (string $method, string $url, array $options) use ($routes): MockResponse { $path = (string) parse_url($url, PHP_URL_PATH); $query = (string) parse_url($url, PHP_URL_QUERY); $this->requests[] = urldecode($path . ($query ? "?$query" : '')); + if (is_string($options['body'] ?? null) && $options['body'] !== '') { + $this->requestBodies[$path] = json_decode($options['body'], true); + } if (! array_key_exists($path, $routes)) { $this->fail("Unexpected request: $method $url"); }