-
Notifications
You must be signed in to change notification settings - Fork 128
Adds a secondary form to project:create for template, catalog, and initialize options #831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Changes from 11 commits
9381f8e
65a5027
9da78e2
95817f8
c783520
fca2eef
6b3dca3
422d38d
16b8b3c
4002301
9a53654
11f3652
69bab98
d25b5b8
60f0d6b
22e4abb
3b39002
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,8 @@ | |
| use Platformsh\Cli\Console\Bot; | ||
| use Platformsh\ConsoleForm\Field\Field; | ||
| use Platformsh\ConsoleForm\Field\OptionsField; | ||
| use Platformsh\ConsoleForm\Field\BooleanField; | ||
| use Platformsh\ConsoleForm\Field\UrlField; | ||
| use Platformsh\ConsoleForm\Form; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Input\InputOption; | ||
|
|
@@ -31,7 +33,8 @@ protected function configure() | |
| $this->form->configureInputDefinition($this->getDefinition()); | ||
|
|
||
| $this->addOption('check-timeout', null, InputOption::VALUE_REQUIRED, 'The API timeout while checking the project status', 30) | ||
| ->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'The total timeout for all API checks (0 to disable the timeout)', 900); | ||
| ->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'The total timeout for all API checks (0 to disable the timeout)', 900) | ||
| ->addOption('template', null, InputOption::VALUE_OPTIONAL, 'Choose a starting template or provide a url of one.', false); | ||
|
|
||
| $this->setHelp(<<<EOF | ||
| Use this command to create a new project. | ||
|
|
@@ -57,12 +60,24 @@ protected function execute(InputInterface $input, OutputInterface $output) | |
| { | ||
| /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */ | ||
| $questionHelper = $this->getService('question_helper'); | ||
|
|
||
| $options = $this->form->resolveOptions($input, $output, $questionHelper); | ||
| $template = $input->getOption('template'); | ||
|
|
||
| if ($template !== false) { | ||
| if (empty(parse_url($template, PHP_URL_PATH))) { | ||
| $temp_provided = true; | ||
| } | ||
| else { | ||
| $temp_provided = false; | ||
| } | ||
| $this->template_form = Form::fromArray($this->getTemplateFields($temp_provided)); | ||
shawnawsu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
shawnawsu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| $template_options = $this->template_form->resolveOptions($input, $output, $questionHelper); | ||
| } | ||
|
|
||
| $estimate = $this->api() | ||
| ->getClient() | ||
| ->getSubscriptionEstimate($options['plan'], $options['storage'], $options['environments'], 1); | ||
|
|
||
| $costConfirm = sprintf( | ||
| 'The estimated monthly cost of this project is: <comment>%s</comment>', | ||
| $estimate['total'] | ||
|
|
@@ -78,13 +93,22 @@ protected function execute(InputInterface $input, OutputInterface $output) | |
| return 1; | ||
| } | ||
|
|
||
| // Grab the url of the yaml file. | ||
| if (!empty($template_options['template_url_from_catalog'])) { | ||
| $options['catalog'] = $template_options['template_url_from_catalog']; | ||
| } | ||
| else if (!empty($template_options['template_url'])) { | ||
| $options['catalog'] = $template_options['template_url']; | ||
| } | ||
shawnawsu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| $subscription = $this->api()->getClient() | ||
| ->createSubscription( | ||
| $options['region'], | ||
| $options['plan'], | ||
| $options['title'], | ||
| $options['storage'] * 1024, | ||
| $options['environments'] | ||
| $options['environments'], | ||
| $options['catalog'] | ||
| ); | ||
|
|
||
| $this->api()->clearProjectsCache(); | ||
|
|
@@ -129,7 +153,6 @@ protected function execute(InputInterface $input, OutputInterface $output) | |
| $timedOut = $totalTimeout ? time() - $start > $totalTimeout : false; | ||
| } | ||
| $this->stdErr->writeln(''); | ||
|
|
||
| if (!$subscription->isActive()) { | ||
| if ($timedOut) { | ||
| $this->stdErr->writeln('<error>The project failed to activate on time</error>'); | ||
|
|
@@ -146,14 +169,37 @@ protected function execute(InputInterface $input, OutputInterface $output) | |
| return 1; | ||
| } | ||
|
|
||
| $this->stdErr->writeln("The project is now ready!"); | ||
| if ($template_options['initialize']) { | ||
shawnawsu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // Make sure nothing happens if the all important subscription info | ||
| // is not available for some reason. | ||
| $project = $this->api()->getProject($subscription->project_id); | ||
| if (!empty($project)) { | ||
| $environment = $this->api()->getEnvironment('master', $project); | ||
| if (isset($subscription->project_options['initialize']['profile']) && isset( $subscription->project_options['initialize']['repository'])) { | ||
| $environment->initialize($subscription->project_options['initialize']['profile'], $subscription->project_options['initialize']['repository']); | ||
| $this->api()->clearEnvironmentsCache($environment->project); | ||
| $this->stdErr->writeln("The project has been initialized and is ready!"); | ||
| } | ||
| else { | ||
| $this->stdErr->writeln("The project could not be initialized at this time due to missing profile and repository information."); | ||
| } | ||
| } | ||
| } | ||
| else { | ||
| $this->stdErr->writeln("The project is now ready!"); | ||
| } | ||
|
|
||
| $output->writeln($subscription->project_id); | ||
| $this->stdErr->writeln(''); | ||
|
|
||
| if (!empty($subscription->project_options['initialize'])) { | ||
| $this->stdErr->writeln(" Template: <info>{$subscription->project_options[initialize][repository] }</info>"); | ||
| } | ||
| $this->stdErr->writeln(" Region: <info>{$subscription->project_region}</info>"); | ||
| $this->stdErr->writeln(" Project ID: <info>{$subscription->project_id}</info>"); | ||
| $this->stdErr->writeln(" Project title: <info>{$subscription->project_title}</info>"); | ||
| $this->stdErr->writeln(" URL: <info>{$subscription->project_ui}</info>"); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
|
|
@@ -216,6 +262,40 @@ protected function getAvailableRegions($runtime = false) | |
| return $regions; | ||
| } | ||
|
|
||
| /** | ||
| * Return the catalog. | ||
| * | ||
| * The default list is in the config `service.catalog`. This is | ||
| * replaced at runtime by an API call. | ||
| * | ||
| * @param bool $runtime | ||
| * | ||
| * @return array | ||
| */ | ||
| protected function getDefaultCatalog($runtime = false) | ||
| { | ||
| if ($runtime) { | ||
| $catalog = []; | ||
| $catalog_items = $this->api()->getClient()->getCatalog()->getData(); | ||
| if (!empty($catalog_items)) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the |
||
| foreach ($catalog_items as $item) { | ||
| if (isset($item['info']) && isset($item['template'])) { | ||
| $catalog[$item['template']] = $item['info']['name']; | ||
| } | ||
| } | ||
| } | ||
| $catalog['empty'] = 'Empty Project'; | ||
shawnawsu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } else { | ||
| $catalog = (array) $this->config()->get('service.catalog'); | ||
| } | ||
|
|
||
| if (empty($catalog)) { | ||
| // Should we throw an error here? Do we want to kill the process? | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if the I don't have a clue what am I writing about, right here, so please be free to ignore me if I make no sense at all.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I'd personally fail it. What do you think @pjcdawkins?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd return |
||
| } | ||
|
|
||
| return $catalog; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a list of ConsoleForm form fields for this command. | ||
| * | ||
|
|
@@ -224,46 +304,108 @@ protected function getAvailableRegions($runtime = false) | |
| protected function getFields() | ||
| { | ||
| return [ | ||
| 'title' => new Field('Project title', [ | ||
| 'optionName' => 'title', | ||
| 'description' => 'The initial project title', | ||
| 'questionLine' => '', | ||
| 'default' => 'Untitled Project', | ||
| ]), | ||
| 'region' => new OptionsField('Region', [ | ||
| 'optionName' => 'region', | ||
| 'description' => 'The region where the project will be hosted', | ||
| 'options' => $this->getAvailableRegions(), | ||
| 'optionsCallback' => function () { | ||
| return $this->getAvailableRegions(true); | ||
| }, | ||
| ]), | ||
| 'plan' => new OptionsField('Plan', [ | ||
| 'optionName' => 'plan', | ||
| 'description' => 'The subscription plan', | ||
| 'options' => $this->getAvailablePlans(), | ||
| 'title' => new Field('Project title', [ | ||
| 'optionName' => 'title', | ||
| 'description' => 'The initial project title', | ||
| 'questionLine' => '', | ||
| 'default' => 'Untitled Project', | ||
| ]), | ||
| 'region' => new OptionsField('Region', [ | ||
| 'optionName' => 'region', | ||
| 'description' => 'The region where the project will be hosted', | ||
| 'options' => $this->getAvailableRegions(), | ||
| 'optionsCallback' => function () { | ||
| return $this->getAvailableRegions(true); | ||
| }, | ||
| ]), | ||
| 'plan' => new OptionsField('Plan', [ | ||
| 'optionName' => 'plan', | ||
| 'description' => 'The subscription plan', | ||
| 'options' => $this->getAvailablePlans(), | ||
| 'optionsCallback' => function () { | ||
| return $this->getAvailablePlans(true); | ||
| }, | ||
| 'default' => in_array('development', $this->getAvailablePlans()) ? 'development' : null, | ||
| 'allowOther' => true, | ||
| ]), | ||
| 'environments' => new Field('Environments', [ | ||
| 'optionName' => 'environments', | ||
| 'description' => 'The number of environments', | ||
| 'default' => 3, | ||
| 'validator' => function ($value) { | ||
| return is_numeric($value) && $value > 0 && $value < 50; | ||
| }, | ||
| ]), | ||
| 'storage' => new Field('Storage', [ | ||
| 'description' => 'The amount of storage per environment, in GiB', | ||
| 'default' => 5, | ||
| 'validator' => function ($value) { | ||
| return is_numeric($value) && $value > 0 && $value < 1024; | ||
| }, | ||
| ]), | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a list of ConsoleForm form fields for this command. | ||
| * | ||
| * @return Field[] | ||
| */ | ||
| protected function getTemplateFields($url_provided) | ||
| { | ||
| $fields = []; | ||
|
|
||
| if (!$url_provided) { | ||
| $fields['template_option'] = new OptionsField('Template Options', [ | ||
| 'optionName' => 'template_option', | ||
| 'options' => [ | ||
| 'Provide your own template url.', | ||
| 'Choose a template from the catalog.', | ||
| 'No template at this time.', | ||
| ], | ||
| 'description' => 'Choose a template, provide a url or choose not to use one.', | ||
| 'includeAsOption' => false, | ||
| ]); | ||
|
|
||
| $fields['template_url_from_catalog'] = new OptionsField('Template (from a catalog)', [ | ||
| 'optionName' => 'template_url_from_catalog', | ||
| 'conditions' => [ | ||
| 'template_option' => [ | ||
| 'Choose a template from the catalog.' | ||
| ], | ||
| ], | ||
| 'description' => 'The template from which to create your project or your own blank project.', | ||
| 'options' => $this->getDefaultCatalog(), | ||
| 'asChoice' => FALSE, | ||
| 'optionsCallback' => function () { | ||
| return $this->getAvailablePlans(true); | ||
| }, | ||
| 'default' => in_array('development', $this->getAvailablePlans()) ? 'development' : null, | ||
| 'allowOther' => true, | ||
| ]), | ||
| 'environments' => new Field('Environments', [ | ||
| 'optionName' => 'environments', | ||
| 'description' => 'The number of environments', | ||
| 'default' => 3, | ||
| 'validator' => function ($value) { | ||
| return is_numeric($value) && $value > 0 && $value < 50; | ||
| }, | ||
| ]), | ||
| 'storage' => new Field('Storage', [ | ||
| 'description' => 'The amount of storage per environment, in GiB', | ||
| 'default' => 5, | ||
| 'validator' => function ($value) { | ||
| return is_numeric($value) && $value > 0 && $value < 1024; | ||
| }, | ||
| ]), | ||
| ]; | ||
| return $this->getDefaultCatalog(true); | ||
| }, | ||
| ]); | ||
|
|
||
| $fields['template_url'] = new UrlField('Template URL', [ | ||
shawnawsu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 'optionName' => 'template_url', | ||
| 'conditions' => [ | ||
| 'template_option' => [ | ||
| 'Provide your own template url.' | ||
| ], | ||
| ], | ||
| 'description' => 'The template url', | ||
| 'questionLine' => 'What is the URL of the template?', | ||
| ]); | ||
| } | ||
| $fields['initialize'] = new BooleanField('Initialize', [ | ||
| 'optionName' => 'initialized', | ||
| 'conditions' => [ | ||
| 'template_option' => [ | ||
| 'Provide your own template url.', | ||
| 'Choose a template from the catalog.', | ||
| ], | ||
| ], | ||
| 'description' => 'Initialize this project from a template?', | ||
| 'questionLine' => 'Initialize this project from a template?', | ||
| ]); | ||
|
|
||
| return $fields; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.