diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..6537ca46 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 95% rename from phpunit.xml rename to phpunit.xml.dist index 09b9fb0c..2b34d4a7 100644 --- a/phpunit.xml +++ b/phpunit.xml.dist @@ -8,7 +8,8 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false"> + stopOnFailure="false" +> tests diff --git a/src/BuildProcess/RemoveIgnoredFiles.php b/src/BuildProcess/RemoveIgnoredFiles.php index a88c81b2..bbd9d625 100644 --- a/src/BuildProcess/RemoveIgnoredFiles.php +++ b/src/BuildProcess/RemoveIgnoredFiles.php @@ -123,6 +123,8 @@ protected function removeUserIgnoredFiles() [$directory, $filePattern] = $this->parsePattern($pattern); if ($this->files->exists($directory.'/'.$filePattern) && $this->files->isDirectory($directory.'/'.$filePattern)) { + Helpers::step('Removing Ignored Directory: '.$filePattern.'/'); + $this->files->deleteDirectory($directory.'/'.$filePattern, $preserve = false); } else { $files = (new Finder) diff --git a/src/Commands/Command.php b/src/Commands/Command.php index 1656e9b9..5a27a417 100644 --- a/src/Commands/Command.php +++ b/src/Commands/Command.php @@ -68,9 +68,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->configureOutputStyles($output); - Helpers::app()->call([$this, 'handle']); - - return 0; + return Helpers::app()->call([$this, 'handle']) ?: 0; } /** diff --git a/src/Commands/EnvDescribeCommand.php b/src/Commands/EnvDescribeCommand.php new file mode 100644 index 00000000..5c62888d --- /dev/null +++ b/src/Commands/EnvDescribeCommand.php @@ -0,0 +1,106 @@ +%attribute-key%] %attribute-value%'; + + /** + * Configure the command options. + * + * @return void + */ + protected function configure() + { + $this + ->setName('env:describe') + ->addArgument('environment', InputArgument::REQUIRED, 'The environment name') + ->addArgument('attribute', null, 'The environment attribute you would like to retrieve') + ->addOption('list', 'l', InputOption::VALUE_NONE, 'Indicate that all attributes should be listed') + ->addOption('format', 'f', InputOption::VALUE_REQUIRED, 'The list format string') + ->setDescription('Describe an environment'); + } + + /** + * Execute the command. + * + * @return void + */ + public function handle() + { + Helpers::ensure_api_token_is_available(); + + $environment = $this->vapor->environmentNamed( + Manifest::id(), + $this->argument('environment') + ); + + $domains = $environment['latest_deployment']['root_domains'] ?: []; + + $domain = count($domains) ? $domains[0] : null; + + $description = [ + 'project_id' => $environment['project_id'], + 'uuid' => $environment['uuid'], + 'id' => $environment['id'], + 'name' => $environment['name'], + 'vanity_domain' => $environment['vanity_domain'], + 'latest_deployment_id' => $environment['latest_deployment_id'], + 'latest_deployment_status' => $environment['latest_deployment']['status'], + 'latest_deployment_url' => 'https://vapor.laravel.com/app/projects/'.$environment['project_id'].'/environments/'.$environment['name'].'/deployments/'.$environment['latest_deployment_id'], + 'deployment_status' => $environment['deployment_status'], + 'domains' => $domains, + 'domain' => $domain, + 'management_url' => 'https://vapor.laravel.com/app/projects/'.$environment['project_id'].'/environments/'.$environment['name'], + 'vanity_url' => 'https://'.$environment['vanity_domain'], + 'custom_url' => $domain ? 'https://'.$domain : null, + ]; + + if ($this->option('list')) { + $format = $this->option('format') ?: static::DEFAULT_FORMAT; + + foreach ($description as $settingKey => $settingValue) { + if (is_bool($settingValue)) { + $settingValue = var_export($settingValue, true); + } + + if (is_array($settingValue)) { + $settingValue = implode(',', $settingValue); + } + + Helpers::line(str_replace( + ['%attribute-key%', '%attribute-value%'], + [$settingKey, $settingValue], + $format + )); + } + + return; + } + + $settingKey = $this->argument('attribute'); + + if (! $settingKey || ! is_string($settingKey)) { + return; + } + + if (! array_key_exists($settingKey, $description)) { + throw new RuntimeException($settingKey.' is not defined'); + } + + $settingValue = $description[$settingKey]; + + if (is_bool($settingValue)) { + $settingValue = var_export($settingValue, true); + } + + Helpers::line($settingValue); + } +} diff --git a/src/Commands/LocalCommand.php b/src/Commands/LocalCommand.php index 52f26293..e63e186a 100644 --- a/src/Commands/LocalCommand.php +++ b/src/Commands/LocalCommand.php @@ -47,12 +47,14 @@ protected function configure() /** * Execute the command. * - * @return void + * @return int * @throws Exception */ public function handle() { $options = array_slice($_SERVER['argv'], $this->option('php') ? 3 : 2); + + $status = 0; file_put_contents( $dockerComposePath = Path::current().'/vapor-docker-compose.yml', @@ -75,10 +77,13 @@ public function handle() '-v', Path::current().':/app', 'app', - ], $options)) + ], $options)), + $status ); unlink($dockerComposePath); + + return $status; } /** diff --git a/src/Commands/MetricsCommand.php b/src/Commands/MetricsCommand.php index e60b523d..38034802 100644 --- a/src/Commands/MetricsCommand.php +++ b/src/Commands/MetricsCommand.php @@ -42,11 +42,14 @@ public function handle() ], [ ['API Gateway Requests', number_format($metrics['totalRestApiRequests']), '$'.number_format($metrics['estimatedApiCost'], 2).''], ['Web Function Invocations', number_format($metrics['totalFunctionInvocations']), '-'], - ['CLI / Queue Function Invocations', number_format($metrics['totalCliFunctionInvocations']), '-'], + ['CLI Function Invocations', number_format($metrics['totalCliFunctionInvocations']), '-'], + ['Queue Function Invocations', number_format($metrics['totalQueueFunctionInvocations']), '-'], ['Average Web Function Duration', number_format($metrics['averageFunctionDuration'], 0).'ms', '-'], - ['Average CLI / Queue Function Duration', number_format($metrics['averageCliFunctionDuration'], 0).'ms', '-'], + ['Average CLI Function Duration', number_format($metrics['averageCliFunctionDuration'], 0).'ms', '-'], + ['Average Queue Function Duration', number_format($metrics['averageQueueFunctionDuration'], 0).'ms', '-'], ['Total Web Function Duration', number_format($metrics['totalFunctionDuration'] / 1000, 0).'s', '$'.number_format($metrics['estimatedCost'], 2).''], - ['Total CLI / Queue Function Duration', number_format($metrics['totalCliFunctionDuration'] / 1000, 0).'s', '$'.number_format($metrics['estimatedCliCost'], 2).''], + ['Total CLI Function Duration', number_format($metrics['totalCliFunctionDuration'] / 1000, 0).'s', '$'.number_format($metrics['estimatedCliCost'], 2).''], + ['Total Queue Function Duration', number_format($metrics['totalQueueFunctionDuration'] / 1000, 0).'s', '$'.number_format($metrics['estimatedQueueCost'], 2).''], ]); Helpers::line(); diff --git a/src/Commands/ProjectDescribeCommand.php b/src/Commands/ProjectDescribeCommand.php new file mode 100644 index 00000000..d0e363ee --- /dev/null +++ b/src/Commands/ProjectDescribeCommand.php @@ -0,0 +1,94 @@ +%attribute-key%] %attribute-value%'; + + /** + * Configure the command options. + * + * @return void + */ + protected function configure() + { + $this + ->setName('project:describe') + ->addArgument('attribute', null, 'The project attribute you would like to retrieve') + ->addOption('list', 'l', InputOption::VALUE_NONE, 'Indicate that all attributes should be listed') + ->addOption('format', 'f', InputOption::VALUE_REQUIRED, 'The list format string') + ->setDescription('Describe the project'); + } + + /** + * Execute the command. + * + * @return void + */ + public function handle() + { + Helpers::ensure_api_token_is_available(); + + $settingKey = $this->argument('attribute'); + + if ($settingKey && $settingKey === 'id') { + // If we want the ID, we can just get it. + Helpers::line(Manifest::id()); + + return; + } + + $project = $this->vapor->project(Manifest::id()); + + $description = [ + 'id' => $project['id'], + 'name' => $project['name'], + 'team_id' => $project['team_id'], + 'team_name' => $project['team']['name'], + 'region' => $project['region'], + 'github_repository' => $project['github_repository'], + 'management_url' => 'https://vapor.laravel.com/app/projects/' . $project['id'], + ]; + + if ($this->option('list')) { + $format = $this->option('format') ?: static::DEFAULT_FORMAT; + + foreach ($description as $settingKey => $settingValue) { + if (is_bool($settingValue)) { + $settingValue = var_export($settingValue, true); + } + + Helpers::line(str_replace( + ['%attribute-key%', '%attribute-value%'], + [$settingKey, $settingValue], + $format + )); + } + + return; + } + + if (! $settingKey || ! is_string($settingKey)) { + return; + } + + if (! array_key_exists($settingKey, $description)) { + throw new RuntimeException($settingKey.' is not defined'); + } + + $settingValue = $description[$settingKey]; + + if (is_bool($settingValue)) { + $settingValue = var_export($settingValue, true); + } + + Helpers::line($settingValue); + } +} diff --git a/src/ConsoleVaporClient.php b/src/ConsoleVaporClient.php index a78d5301..dca633ca 100644 --- a/src/ConsoleVaporClient.php +++ b/src/ConsoleVaporClient.php @@ -757,6 +757,19 @@ public function environments($projectId) return $this->request('get', '/api/projects/'.$projectId.'/environments'); } + /** + * Get the environment by a specific name for the given project. + * + * @param string $projectId + * @return array + */ + public function environmentNamed($projectId, $name) + { + return collect($this->environments($projectId))->first(function ($environment) use ($name) { + return $environment['name'] === $name; + }); + } + /** * Delete the given project. * diff --git a/vapor b/vapor index 5ea4cd58..eb8f391f 100755 --- a/vapor +++ b/vapor @@ -52,7 +52,7 @@ require __DIR__.'/services.php'; /** * Start the console application. */ -$app = new Application('Laravel Vapor', '1.4.7'); +$app = new Application('Laravel Vapor', '1.6.2'); // Authentication... $app->add(new Commands\LoginCommand); @@ -133,10 +133,12 @@ $app->add(new Commands\BalancerDeleteCommand); // Projects... $app->add(new Commands\InitCommand); $app->add(new Commands\ProjectDeleteCommand); +$app->add(new Commands\ProjectDescribeCommand); // Environments... $app->add(new Commands\EnvListCommand); $app->add(new Commands\EnvCommand); +$app->add(new Commands\EnvDescribeCommand); $app->add(new Commands\EnvPullCommand); $app->add(new Commands\EnvPushCommand); $app->add(new Commands\EnvCloneCommand);