Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/Commands/Deploy.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ protected function configure(): void
->setName('deploy')
->setDescription('Deploy the application')
->addOption('force', null, InputOption::VALUE_NONE, 'Force the deployment')
->addOption('osls4', null, InputOption::VALUE_NONE, 'Use osls@4 instead of osls@3');
->addOption('osls4', null, InputOption::VALUE_NONE, 'Use osls@4 instead of osls@3')
->addOption('param', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Pass a parameter to serverless.yml, e.g. --param="key=value" (can be repeated)');
parent::configure();
}

Expand All @@ -54,6 +55,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
'config' => $config,
] = $this->parseStandardOptions($input);

$isServerlessFrameworkDeploy = $config['type'] === 'serverless-framework';
if (! $isServerlessFrameworkDeploy && $input->getOption('param')) {
throw new Exception('The --param option is only supported for serverless.yml applications');
}

$brefCloud = new BrefCloudClient;

IO::writeln([
Expand Down Expand Up @@ -105,8 +111,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int

IO::writeln("<href={$deployment['url']}>" . Styles::gray($deployment['url']) . '</>');

$isServerlessFrameworkDeploy = $config['type'] === 'serverless-framework';

if ($isServerlessFrameworkDeploy) {
if ($credentials === null) {
IO::spinError();
Expand Down
46 changes: 29 additions & 17 deletions src/Components/ServerlessFramework.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,11 @@ class ServerlessFramework
*/
public function deploy(int $deploymentId, string $environment, array $awsCredentials, BrefCloudClient $brefCloud, InputInterface $input): void
{
$options = [];
$commonOptions = $this->commonOptions($input);
$options = $commonOptions;
if ($input->hasOption('force')) {
$options[] = '--force';
}
$configOption = $input->getOption('config');
if ($input->hasOption('config') && is_string($configOption) && $configOption !== '') {
$configFile = $configOption;
$options[] = '--config';
$options[] = $configFile;
} else {
$configFile = null;
}
$oslsPackage = ($input->hasOption('osls4') && $input->getOption('osls4')) ? 'osls@4' : 'osls@3';

$newLogs = '';
Expand Down Expand Up @@ -102,7 +95,7 @@ public function deploy(int $deploymentId, string $environment, array $awsCredent

$hasChanges = ! str_contains($newLogs, 'No changes to deploy. Deployment skipped.');
if ($hasChanges) {
$outputs = $this->retrieveOutputs($oslsPackage, $environment, $awsCredentials, $configFile);
$outputs = $this->retrieveOutputs($oslsPackage, $environment, $awsCredentials, $commonOptions);

$region = $outputs['region'];
$stackName = $outputs['stack'];
Expand All @@ -123,6 +116,30 @@ public function deploy(int $deploymentId, string $environment, array $awsCredent
}
}

/**
* The options that both `serverless deploy` and the `serverless info` that follows it need, to resolve the
* same configuration (e.g. `${param:...}` variables).
*
* @return list<string>
*/
public function commonOptions(InputInterface $input): array
{
$options = [];
$configFile = $input->hasOption('config') ? $input->getOption('config') : null;
if (is_string($configFile) && $configFile !== '') {
$options[] = '--config';
$options[] = $configFile;
}
/** @var list<string> $params */
$params = $input->hasOption('param') ? $input->getOption('param') : [];
foreach ($params as $param) {
$options[] = '--param';
$options[] = $param;
}

return $options;
}

/**
* The stack that the deployment created, if it did.
*
Expand Down Expand Up @@ -150,17 +167,12 @@ public function findCreatedStack(string $output): ?array

/**
* @param array{ accessKeyId: string, secretAccessKey: string, sessionToken: string } $awsCredentials
* @param list<string> $options
* @return array<string, string>
* @throws Exception
*/
private function retrieveOutputs(string $oslsPackage, string $environment, array $awsCredentials, ?string $configFile): array
private function retrieveOutputs(string $oslsPackage, string $environment, array $awsCredentials, array $options): array
{
$options = [];
if ($configFile) {
$options[] = '--config';
$options[] = $configFile;
}

$process = $this->serverlessExec($oslsPackage, 'info', $environment, $awsCredentials, $options);
$process->join();
$infoOutput = buffer($process->getStdout());
Expand Down
30 changes: 30 additions & 0 deletions tests/Commands/DeployTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php declare(strict_types=1);

namespace Bref\Cli\Test\Commands;

use Bref\Cli\Cli\IO;
use Bref\Cli\Commands\Deploy;
use Exception;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;

class DeployTest extends CommandTestCase
{
public function test_params_are_only_supported_for_serverless_yml_applications(): void
{
$configFile = sys_get_temp_dir() . '/bref-cli-test-' . bin2hex(random_bytes(4)) . '.php';
file_put_contents($configFile, '<?php echo json_encode(["name" => "shop", "team" => "acme", "type" => "laravel"]);');
$input = new ArrayInput(['--config' => $configFile, '--param' => ['domain=example.com']]);
$input->setInteractive(false);
$output = new BufferedOutput;
IO::init($input, $output);

try {
$this->expectException(Exception::class);
$this->expectExceptionMessage('The --param option is only supported for serverless.yml applications');
(new Deploy)->run($input, $output);
} finally {
unlink($configFile);
}
}
}
23 changes: 23 additions & 0 deletions tests/Components/ServerlessFrameworkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,35 @@

namespace Bref\Cli\Test\Components;

use Bref\Cli\Commands\Deploy;
use Bref\Cli\Components\ServerlessFramework;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\ArrayInput;

class ServerlessFrameworkTest extends TestCase
{
public function test_forwards_the_config_file_and_the_params_to_serverless(): void
{
$input = new ArrayInput([
'--config' => 'serverless.prod.yml',
'--param' => ['layer=arn:aws:lambda:us-east-1:123:layer:php-85:1', 'domain=example.com'],
], (new Deploy)->getDefinition());

$this->assertSame([
'--config', 'serverless.prod.yml',
'--param', 'layer=arn:aws:lambda:us-east-1:123:layer:php-85:1',
'--param', 'domain=example.com',
], (new ServerlessFramework)->commonOptions($input));
}

public function test_no_options_by_default(): void
{
$input = new ArrayInput([], (new Deploy)->getDefinition());

$this->assertSame([], (new ServerlessFramework)->commonOptions($input));
}

/**
* @param array{string, string}|null $expected
*/
Expand Down
Loading