From a951e4225ca0a85c60abfd39f182fed12b83527a Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Mon, 24 Jan 2022 14:58:15 -0600 Subject: [PATCH 01/37] Added shortcut method to determine if forced = true --- app/Commands/Concerns/InteractsWithIO.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Commands/Concerns/InteractsWithIO.php b/app/Commands/Concerns/InteractsWithIO.php index 001322d..4388b04 100644 --- a/app/Commands/Concerns/InteractsWithIO.php +++ b/app/Commands/Concerns/InteractsWithIO.php @@ -258,4 +258,9 @@ public function queueResources(Collection $resources, string $endpoint, string $ ucfirst($resourceName), ], $events); } + + protected function forced(): bool + { + return (bool) $this->option('force'); + } } From a00d22f31a42f327806addc9a63466e36a59eb73 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 25 Jan 2022 09:57:51 -0600 Subject: [PATCH 02/37] Created a system to configure command options IO --- app/Commands/Concerns/InteractsWithIO.php | 19 +++++++++++++++ app/Options/HasChoices.php | 16 +++++++++++++ app/Options/Option.php | 28 +++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 app/Options/HasChoices.php create mode 100644 app/Options/Option.php diff --git a/app/Commands/Concerns/InteractsWithIO.php b/app/Commands/Concerns/InteractsWithIO.php index 4388b04..317c3b7 100644 --- a/app/Commands/Concerns/InteractsWithIO.php +++ b/app/Commands/Concerns/InteractsWithIO.php @@ -160,6 +160,25 @@ public function isAssoc(array $array): bool return (int) $this->output->askQuestion($question); } + /** + * Initializes an options object, outputs prompt for and return user input. + * + * @param bool|string|array $defaultOverride + */ + protected function resolveOptionPrompt(string $optionClass, $defaultOverride = null): ?string + { + $optionClass = resolve($optionClass); + + if (!is_null($defaultOverride)) { + $optionClass->default = $defaultOverride; + } + + if (in_array('App\Options\HasChoices', class_uses($optionClass))) { + return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->choices, $optionClass->default); + } + return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->default); + } + protected function largeOutput(array $resource): void { $table = new Table($this->output); diff --git a/app/Options/HasChoices.php b/app/Options/HasChoices.php new file mode 100644 index 0000000..6d4c896 --- /dev/null +++ b/app/Options/HasChoices.php @@ -0,0 +1,16 @@ +choices ?? []; + } + + public function getPromptType(): string + { + return 'askToSelect'; + } +} diff --git a/app/Options/Option.php b/app/Options/Option.php new file mode 100644 index 0000000..0cd9ec8 --- /dev/null +++ b/app/Options/Option.php @@ -0,0 +1,28 @@ +$method(); + } + return $this->{$name}; + } + + public function __set(string $name, $value): void + { + $this->{$name} = $value; + } +} From 7451caef784db576eea01a32e711c832d07ae598 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 25 Jan 2022 09:59:23 -0600 Subject: [PATCH 03/37] Added options for the sites:create command --- app/Options/Sites/DbName.php | 15 +++++++++++++++ app/Options/Sites/DbPass.php | 16 ++++++++++++++++ app/Options/Sites/DbUser.php | 15 +++++++++++++++ app/Options/Sites/Domain.php | 10 ++++++++++ app/Options/Sites/HttpsEnabled.php | 14 ++++++++++++++ app/Options/Sites/PageCacheEnabled.php | 14 ++++++++++++++ app/Options/Sites/PhpVersion.php | 20 ++++++++++++++++++++ app/Options/Sites/SiteUser.php | 15 +++++++++++++++ app/Options/Sites/WpAdminEmail.php | 10 ++++++++++ app/Options/Sites/WpAdminPass.php | 16 ++++++++++++++++ app/Options/Sites/WpAdminUser.php | 10 ++++++++++ app/Options/Sites/WpTitle.php | 10 ++++++++++ 12 files changed, 165 insertions(+) create mode 100644 app/Options/Sites/DbName.php create mode 100644 app/Options/Sites/DbPass.php create mode 100644 app/Options/Sites/DbUser.php create mode 100644 app/Options/Sites/Domain.php create mode 100644 app/Options/Sites/HttpsEnabled.php create mode 100644 app/Options/Sites/PageCacheEnabled.php create mode 100644 app/Options/Sites/PhpVersion.php create mode 100644 app/Options/Sites/SiteUser.php create mode 100644 app/Options/Sites/WpAdminEmail.php create mode 100644 app/Options/Sites/WpAdminPass.php create mode 100644 app/Options/Sites/WpAdminUser.php create mode 100644 app/Options/Sites/WpTitle.php diff --git a/app/Options/Sites/DbName.php b/app/Options/Sites/DbName.php new file mode 100644 index 0000000..037da0c --- /dev/null +++ b/app/Options/Sites/DbName.php @@ -0,0 +1,15 @@ +default); + } +} diff --git a/app/Options/Sites/DbPass.php b/app/Options/Sites/DbPass.php new file mode 100644 index 0000000..16cb634 --- /dev/null +++ b/app/Options/Sites/DbPass.php @@ -0,0 +1,16 @@ +default); + } +} diff --git a/app/Options/Sites/Domain.php b/app/Options/Sites/Domain.php new file mode 100644 index 0000000..90a6c4f --- /dev/null +++ b/app/Options/Sites/Domain.php @@ -0,0 +1,10 @@ + '8.0', + '74' => '7.4', + ]; + + protected $default = '8'; + + protected string $promptValue = 'PHP Version'; +} diff --git a/app/Options/Sites/SiteUser.php b/app/Options/Sites/SiteUser.php new file mode 100644 index 0000000..f584801 --- /dev/null +++ b/app/Options/Sites/SiteUser.php @@ -0,0 +1,15 @@ +default); + } +} diff --git a/app/Options/Sites/WpAdminEmail.php b/app/Options/Sites/WpAdminEmail.php new file mode 100644 index 0000000..e8e3562 --- /dev/null +++ b/app/Options/Sites/WpAdminEmail.php @@ -0,0 +1,10 @@ + Date: Wed, 26 Jan 2022 09:25:41 -0600 Subject: [PATCH 04/37] Renamed "Options" to "OptionsIO" --- app/{Options => OptionsIO}/HasChoices.php | 2 +- app/{Options => OptionsIO}/Option.php | 2 +- app/{Options => OptionsIO}/Sites/DbName.php | 4 ++-- app/{Options => OptionsIO}/Sites/DbPass.php | 4 ++-- app/{Options => OptionsIO}/Sites/DbUser.php | 4 ++-- app/{Options => OptionsIO}/Sites/Domain.php | 4 ++-- app/{Options => OptionsIO}/Sites/HttpsEnabled.php | 4 ++-- app/{Options => OptionsIO}/Sites/PageCacheEnabled.php | 4 ++-- app/{Options => OptionsIO}/Sites/PhpVersion.php | 6 +++--- app/{Options => OptionsIO}/Sites/SiteUser.php | 4 ++-- app/{Options => OptionsIO}/Sites/WpAdminEmail.php | 4 ++-- app/{Options => OptionsIO}/Sites/WpAdminPass.php | 4 ++-- app/{Options => OptionsIO}/Sites/WpAdminUser.php | 4 ++-- app/{Options => OptionsIO}/Sites/WpTitle.php | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) rename app/{Options => OptionsIO}/HasChoices.php (89%) rename app/{Options => OptionsIO}/Option.php (95%) rename app/{Options => OptionsIO}/Sites/DbName.php (77%) rename app/{Options => OptionsIO}/Sites/DbPass.php (78%) rename app/{Options => OptionsIO}/Sites/DbUser.php (77%) rename app/{Options => OptionsIO}/Sites/Domain.php (61%) rename app/{Options => OptionsIO}/Sites/HttpsEnabled.php (75%) rename app/{Options => OptionsIO}/Sites/PageCacheEnabled.php (76%) rename app/{Options => OptionsIO}/Sites/PhpVersion.php (72%) rename app/{Options => OptionsIO}/Sites/SiteUser.php (77%) rename app/{Options => OptionsIO}/Sites/WpAdminEmail.php (67%) rename app/{Options => OptionsIO}/Sites/WpAdminPass.php (79%) rename app/{Options => OptionsIO}/Sites/WpAdminUser.php (65%) rename app/{Options => OptionsIO}/Sites/WpTitle.php (62%) diff --git a/app/Options/HasChoices.php b/app/OptionsIO/HasChoices.php similarity index 89% rename from app/Options/HasChoices.php rename to app/OptionsIO/HasChoices.php index 6d4c896..f6208f7 100644 --- a/app/Options/HasChoices.php +++ b/app/OptionsIO/HasChoices.php @@ -1,6 +1,6 @@ Date: Wed, 26 Jan 2022 09:29:02 -0600 Subject: [PATCH 05/37] Added a trait for commands which utilize OptionsIO --- app/Commands/Concerns/HasOptionsIO.php | 32 +++++++++++++++++++++++ app/Commands/Concerns/InteractsWithIO.php | 19 -------------- 2 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 app/Commands/Concerns/HasOptionsIO.php diff --git a/app/Commands/Concerns/HasOptionsIO.php b/app/Commands/Concerns/HasOptionsIO.php new file mode 100644 index 0000000..eb375f0 --- /dev/null +++ b/app/Commands/Concerns/HasOptionsIO.php @@ -0,0 +1,32 @@ +default = $defaultOverride; + } + + if (in_array('App\Options\HasChoices', class_uses($optionClass))) { + return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->choices, $optionClass->default); + } + return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->default); + } + + public function getAvailableOptionsIO(): array + { + return $this->availableOptionIO; + } +} diff --git a/app/Commands/Concerns/InteractsWithIO.php b/app/Commands/Concerns/InteractsWithIO.php index 317c3b7..4388b04 100644 --- a/app/Commands/Concerns/InteractsWithIO.php +++ b/app/Commands/Concerns/InteractsWithIO.php @@ -160,25 +160,6 @@ public function isAssoc(array $array): bool return (int) $this->output->askQuestion($question); } - /** - * Initializes an options object, outputs prompt for and return user input. - * - * @param bool|string|array $defaultOverride - */ - protected function resolveOptionPrompt(string $optionClass, $defaultOverride = null): ?string - { - $optionClass = resolve($optionClass); - - if (!is_null($defaultOverride)) { - $optionClass->default = $defaultOverride; - } - - if (in_array('App\Options\HasChoices', class_uses($optionClass))) { - return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->choices, $optionClass->default); - } - return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->default); - } - protected function largeOutput(array $resource): void { $table = new Table($this->output); From 433398ba2a43103dbeda10724b554fc9308e1981 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Wed, 26 Jan 2022 16:36:04 -0600 Subject: [PATCH 06/37] Added sites:create command --- app/Commands/Concerns/HasOptionsIO.php | 23 +++-- app/Commands/Sites/CreateCommand.php | 118 ++++++++++++++++++++++++ app/Helpers/OptionsHelper.php | 14 +++ app/OptionsIO/Sites/PhpVersion.php | 13 +-- app/Repositories/SpinupWpRepository.php | 32 +++++++ 5 files changed, 186 insertions(+), 14 deletions(-) create mode 100644 app/Commands/Sites/CreateCommand.php create mode 100644 app/Helpers/OptionsHelper.php diff --git a/app/Commands/Concerns/HasOptionsIO.php b/app/Commands/Concerns/HasOptionsIO.php index eb375f0..78de41c 100644 --- a/app/Commands/Concerns/HasOptionsIO.php +++ b/app/Commands/Concerns/HasOptionsIO.php @@ -2,16 +2,16 @@ namespace App\Commands\Concerns; +use App\OptionsIO\Option; + trait HasOptionsIO { - protected array $availableOptionIO = []; - /** * Initializes an options object, outputs prompt for and return user input. * * @param bool|string|array $defaultOverride */ - protected function resolveOptionIO(string $optionClass, $defaultOverride = null): ?string + protected function resolveOptionIO(string $optionClass, $defaultOverride = null, $returnDefault = false): ?string { $optionClass = resolve($optionClass); @@ -19,14 +19,21 @@ protected function resolveOptionIO(string $optionClass, $defaultOverride = null) $optionClass->default = $defaultOverride; } - if (in_array('App\Options\HasChoices', class_uses($optionClass))) { - return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->choices, $optionClass->default); + if ($returnDefault) { + return $optionClass->default; } - return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->default); + + return $this->promptForOption($optionClass); } - public function getAvailableOptionsIO(): array + /** + * @return mixed + */ + protected function promptForOption(Option $optionClass) { - return $this->availableOptionIO; + if (in_array('App\OptionsIO\HasChoices', class_uses($optionClass))) { + return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->choices, $optionClass->default); + } + return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->default); } } diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php new file mode 100644 index 0000000..079d2ef --- /dev/null +++ b/app/Commands/Sites/CreateCommand.php @@ -0,0 +1,118 @@ + Domain::class, + 'https_enabled' => HttpsEnabled::class, + 'site_user' => SiteUser::class, + 'db_name' => DbName::class, + 'db_user' => DbUser::class, + 'db_pass' => DbPass::class, + 'wp_title' => WpTitle::class, + 'wp_admin_user' => WpAdminUser::class, + 'wp_admin_email' => WpAdminEmail::class, + 'wp_admin_pass' => WpAdminPass::class, + 'php_version' => PhpVersion::class, + 'page_cache_enabled' => PageCacheEnabled::class, + ]; + + protected function action(): int + { + if (!in_array($this->argument('installation_method'), OptionsHelper::INSTALLATION_METHODS, true)) { + $this->error('Invalid site type.'); + $this->newLine(1); + return self::INVALID; + } + + $userInput = []; + $server = $this->selectServer('deploy to')->first(); + $optionIO = $this->getAvailableOptionIO($this->argument('installation_method')); + + foreach ($optionIO as $optionKey => $optionClass) { + if (empty($this->option($optionKey))) { + $default = null; + if ($optionKey === 'site_user' || $optionKey === 'db_name' || $optionKey === 'db_user' || $optionKey === 'wp_title') { + $default = $this->domain; + } + + $userInput[$optionKey] = $this->resolveOptionIO($optionClass, $default, $this->forced()); + } + + if ($optionKey === 'domain') { + $this->domain = $userInput[$optionKey] ?? $this->option('domain'); + } + } + + $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), $userInput)); + + $this->successfulStep("{$site->domain} is {$site->status} (event_id = {$site->eventId()})"); + + return self::SUCCESS; + } + + /** + * Use different options depending on site install type. + */ + protected function getAvailableOptionIO(string $type): array + { + switch ($type) { + case 'blank': + return Arr::except($this->availableOptionIO, [ + 'db_name', 'db_user', 'db_pass', + 'wp_title', 'wp_admin_user', 'wp_admin_email', 'wp_admin_pass', + ]); + case 'git': + return Arr::except($this->availableOptionIO, [ + 'wp_title', 'wp_admin_user', 'wp_admin_email', 'wp_admin_pass', + ]); + default: + return $this->availableOptionIO; + } + } +} diff --git a/app/Helpers/OptionsHelper.php b/app/Helpers/OptionsHelper.php new file mode 100644 index 0000000..851abd7 --- /dev/null +++ b/app/Helpers/OptionsHelper.php @@ -0,0 +1,14 @@ + '8.0', + '74' => '7.4', + ]; +} diff --git a/app/OptionsIO/Sites/PhpVersion.php b/app/OptionsIO/Sites/PhpVersion.php index c59513b..4618155 100644 --- a/app/OptionsIO/Sites/PhpVersion.php +++ b/app/OptionsIO/Sites/PhpVersion.php @@ -2,6 +2,7 @@ namespace App\OptionsIO\Sites; +use App\Helpers\OptionsHelper; use App\OptionsIO\HasChoices; use App\OptionsIO\Option; @@ -9,12 +10,12 @@ class PhpVersion extends Option { use HasChoices; - protected array $choices = [ - '8' => '8.0', - '74' => '7.4', - ]; - - protected $default = '8'; + protected $default = '80'; protected string $promptValue = 'PHP Version'; + + public function getChoices(): array + { + return OptionsHelper::PHP_VERSIONS; + } } diff --git a/app/Repositories/SpinupWpRepository.php b/app/Repositories/SpinupWpRepository.php index 7f07744..b6c3601 100644 --- a/app/Repositories/SpinupWpRepository.php +++ b/app/Repositories/SpinupWpRepository.php @@ -2,6 +2,8 @@ namespace App\Repositories; +use App\Helpers\OptionsHelper; +use App\OptionsIO\Sites\PhpVersion; use DeliciousBrains\SpinupWp\Endpoints\Event; use DeliciousBrains\SpinupWp\Endpoints\Server; use DeliciousBrains\SpinupWp\Endpoints\Site; @@ -9,6 +11,7 @@ use DeliciousBrains\SpinupWp\Resources\Site as SiteResource; use DeliciousBrains\SpinupWp\SpinupWp; use GuzzleHttp\Client; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; /** @@ -76,4 +79,33 @@ public function listSites(int $serverId = null): Collection return collect($this->spinupwp->sites->listForServer($serverId, 1, $params)); } + + public function createSite(int $serverId, array $inputParams): SiteResource + { + $inputParams = [ + 'installation_method' => $inputParams['installation_method'], + 'domain' => $inputParams['domain'], + 'php_version' => OptionsHelper::PHP_VERSIONS[$inputParams['php_version']], + 'site_user' => $inputParams['site_user'], + 'page_cache' => [ + 'enabled' => $inputParams['page_cache_enabled'], + ], + 'https' => [ + 'enabled' => $inputParams['https_enabled'], + ], + 'database' => [ + 'name' => $inputParams['db_name'], + 'username' => $inputParams['db_user'], + 'password' => $inputParams['db_pass'], + ], + 'wordpress' => [ + 'title' => $inputParams['wp_title'], + 'admin_user' => $inputParams['wp_admin_user'], + 'admin_email' => $inputParams['wp_admin_email'], + 'admin_password' => $inputParams['wp_admin_pass'], + ], + ]; + + return $this->spinupwp->sites->create($serverId, $inputParams); + } } From 4880f5f132a031f59f3229ee12c303cc2b92ed1f Mon Sep 17 00:00:00 2001 From: ohryan Date: Wed, 26 Jan 2022 22:36:29 +0000 Subject: [PATCH 07/37] Apply php-cs-fixer changes --- app/Helpers/OptionsHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Helpers/OptionsHelper.php b/app/Helpers/OptionsHelper.php index 851abd7..d3a6e47 100644 --- a/app/Helpers/OptionsHelper.php +++ b/app/Helpers/OptionsHelper.php @@ -5,9 +5,9 @@ class OptionsHelper { // SpinupWP CLI only supports a subset of installation methods available via the REST API - const INSTALLATION_METHODS = ['wp', 'blank']; + public const INSTALLATION_METHODS = ['wp', 'blank']; - const PHP_VERSIONS = [ + public const PHP_VERSIONS = [ '80' => '8.0', '74' => '7.4', ]; From 1d62a2ecd140b37c4ced688e7088a68b32c4b246 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Wed, 26 Jan 2022 17:03:55 -0600 Subject: [PATCH 08/37] Added validation exception handling --- app/Commands/BaseCommand.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/Commands/BaseCommand.php b/app/Commands/BaseCommand.php index 6d7bd1b..85f1a96 100644 --- a/app/Commands/BaseCommand.php +++ b/app/Commands/BaseCommand.php @@ -5,6 +5,7 @@ use App\Commands\Concerns\InteractsWithIO; use App\Repositories\ConfigRepository; use App\Repositories\SpinupWpRepository; +use DeliciousBrains\SpinupWp\Exceptions\ValidationException; use Exception; use GuzzleHttp\Client; use LaravelZero\Framework\Commands\Command; @@ -53,6 +54,19 @@ public function handle(): int } return $this->action(); + } catch (ValidationException $e) { + $errorRows = []; + foreach ($e->errors()['errors'] as $field => $errors) { + $errorRows[] = [$field, implode("\n", $errors)]; + } + + $this->error('Validation errors occurred.'); + $this->stepTable([ + 'Field', + 'Error Message', + ], $errorRows); + + return self::FAILURE; } catch (Exception $e) { $this->error($e->getMessage()); return self::FAILURE; From f872af2a179bd82168cc1e542646e8027223d64e Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Thu, 27 Jan 2022 16:03:24 -0600 Subject: [PATCH 09/37] Implement `SelectsServer` merged in. --- app/Commands/Sites/CreateCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 079d2ef..79aa31d 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -5,6 +5,7 @@ use App\Commands\BaseCommand; use App\Commands\Concerns\HasOptionsIO; use App\Commands\Concerns\InteractsWithIO; +use App\Commands\Concerns\SelectsServer; use App\Helpers\OptionsHelper; use App\OptionsIO\Sites\DbName; use App\OptionsIO\Sites\DbPass; @@ -24,6 +25,7 @@ class CreateCommand extends BaseCommand { use InteractsWithIO; use HasOptionsIO; + use SelectsServer; protected $signature = 'sites:create {installation_method : Type of installation (wp or blank)} From 7daf5176e2d6d4b5ebcbaa57e84ab02516825dba Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Thu, 27 Jan 2022 17:05:20 -0600 Subject: [PATCH 10/37] Added `$defaultWhenSkipped` to allow prompt and non-interactive mode to have different defaults. --- app/Commands/Concerns/HasOptionsIO.php | 6 +++--- app/OptionsIO/Option.php | 7 ++++++- app/OptionsIO/Sites/HttpsEnabled.php | 4 +++- app/OptionsIO/Sites/PageCacheEnabled.php | 4 +++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/Commands/Concerns/HasOptionsIO.php b/app/Commands/Concerns/HasOptionsIO.php index 78de41c..09dfade 100644 --- a/app/Commands/Concerns/HasOptionsIO.php +++ b/app/Commands/Concerns/HasOptionsIO.php @@ -11,7 +11,7 @@ trait HasOptionsIO * * @param bool|string|array $defaultOverride */ - protected function resolveOptionIO(string $optionClass, $defaultOverride = null, $returnDefault = false): ?string + protected function resolveOptionIO(string $optionClass, $defaultOverride = null, bool $skipUserInput = false): ?string { $optionClass = resolve($optionClass); @@ -19,8 +19,8 @@ protected function resolveOptionIO(string $optionClass, $defaultOverride = null, $optionClass->default = $defaultOverride; } - if ($returnDefault) { - return $optionClass->default; + if ($skipUserInput) { + return $optionClass->defaultWhenSkipped ?? $optionClass->default; } return $this->promptForOption($optionClass); diff --git a/app/OptionsIO/Option.php b/app/OptionsIO/Option.php index d92d07a..93d9cf9 100644 --- a/app/OptionsIO/Option.php +++ b/app/OptionsIO/Option.php @@ -5,10 +5,15 @@ abstract class Option { /** - * @var string|array|null + * @var mixed default value when prompt */ protected $default = null; + /** + * @var mixed default value when prompt is not displayed + */ + protected $defaultWhenSkipped = null; + protected string $promptType = 'ask'; protected string $promptValue = ''; diff --git a/app/OptionsIO/Sites/HttpsEnabled.php b/app/OptionsIO/Sites/HttpsEnabled.php index d278d43..e4d9299 100644 --- a/app/OptionsIO/Sites/HttpsEnabled.php +++ b/app/OptionsIO/Sites/HttpsEnabled.php @@ -6,7 +6,9 @@ class HttpsEnabled extends Option { - protected $default = true; + protected $default = 1; + + protected $defaultWhenSkipped = 0; protected string $promptType = 'confirm'; diff --git a/app/OptionsIO/Sites/PageCacheEnabled.php b/app/OptionsIO/Sites/PageCacheEnabled.php index 604806b..3ef8857 100644 --- a/app/OptionsIO/Sites/PageCacheEnabled.php +++ b/app/OptionsIO/Sites/PageCacheEnabled.php @@ -6,7 +6,9 @@ class PageCacheEnabled extends Option { - protected $default = true; + protected $default = 1; + + protected $defaultWhenSkipped = 0; protected string $promptType = 'confirm'; From 10c0dd83a4eb7f42a9967f723f3ae4cf3486e89a Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Thu, 27 Jan 2022 17:05:55 -0600 Subject: [PATCH 11/37] Skip server prompt in non-interactive mode --- app/Commands/Concerns/SelectsServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Commands/Concerns/SelectsServer.php b/app/Commands/Concerns/SelectsServer.php index 49b0195..6a0f100 100644 --- a/app/Commands/Concerns/SelectsServer.php +++ b/app/Commands/Concerns/SelectsServer.php @@ -10,7 +10,7 @@ public function selectServer(string $action): Collection { $serverId = $this->argument('server_id'); - if (empty($serverId)) { + if (empty($serverId) && !$this->forced()) { $serverId = $this->askToSelectServer("Which server would you like to $action"); } From 0f673736782adfba7f67470d59462c53b200372c Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Thu, 27 Jan 2022 17:08:59 -0600 Subject: [PATCH 12/37] Renamed "forced" to the more standard "non-interactive" --- app/Commands/Concerns/HasOptionsIO.php | 6 +++--- app/Commands/Concerns/InteractsWithIO.php | 2 +- app/Commands/Concerns/SelectsServer.php | 2 +- app/Commands/Sites/CreateCommand.php | 2 +- app/OptionsIO/Option.php | 2 +- app/OptionsIO/Sites/HttpsEnabled.php | 2 +- app/OptionsIO/Sites/PageCacheEnabled.php | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/Commands/Concerns/HasOptionsIO.php b/app/Commands/Concerns/HasOptionsIO.php index 09dfade..e613822 100644 --- a/app/Commands/Concerns/HasOptionsIO.php +++ b/app/Commands/Concerns/HasOptionsIO.php @@ -11,7 +11,7 @@ trait HasOptionsIO * * @param bool|string|array $defaultOverride */ - protected function resolveOptionIO(string $optionClass, $defaultOverride = null, bool $skipUserInput = false): ?string + protected function resolveOptionIO(string $optionClass, $defaultOverride = null, bool $nonInteractive = false): ?string { $optionClass = resolve($optionClass); @@ -19,8 +19,8 @@ protected function resolveOptionIO(string $optionClass, $defaultOverride = null, $optionClass->default = $defaultOverride; } - if ($skipUserInput) { - return $optionClass->defaultWhenSkipped ?? $optionClass->default; + if ($nonInteractive) { + return $optionClass->nonInteractiveDefault ?? $optionClass->default; } return $this->promptForOption($optionClass); diff --git a/app/Commands/Concerns/InteractsWithIO.php b/app/Commands/Concerns/InteractsWithIO.php index 528a893..5d6cec9 100644 --- a/app/Commands/Concerns/InteractsWithIO.php +++ b/app/Commands/Concerns/InteractsWithIO.php @@ -235,7 +235,7 @@ public function queueResources(Collection $resources, string $endpoint, string $ ], $events); } - protected function forced(): bool + protected function nonInteractive(): bool { return (bool) $this->option('force'); } diff --git a/app/Commands/Concerns/SelectsServer.php b/app/Commands/Concerns/SelectsServer.php index 6a0f100..75c6dfd 100644 --- a/app/Commands/Concerns/SelectsServer.php +++ b/app/Commands/Concerns/SelectsServer.php @@ -10,7 +10,7 @@ public function selectServer(string $action): Collection { $serverId = $this->argument('server_id'); - if (empty($serverId) && !$this->forced()) { + if (empty($serverId) && !$this->nonInteractive()) { $serverId = $this->askToSelectServer("Which server would you like to $action"); } diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 79aa31d..ea9dc92 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -83,7 +83,7 @@ protected function action(): int $default = $this->domain; } - $userInput[$optionKey] = $this->resolveOptionIO($optionClass, $default, $this->forced()); + $userInput[$optionKey] = $this->resolveOptionIO($optionClass, $default, $this->nonInteractive()); } if ($optionKey === 'domain') { diff --git a/app/OptionsIO/Option.php b/app/OptionsIO/Option.php index 93d9cf9..3ef48fc 100644 --- a/app/OptionsIO/Option.php +++ b/app/OptionsIO/Option.php @@ -12,7 +12,7 @@ abstract class Option /** * @var mixed default value when prompt is not displayed */ - protected $defaultWhenSkipped = null; + protected $nonInteractiveDefault = null; protected string $promptType = 'ask'; diff --git a/app/OptionsIO/Sites/HttpsEnabled.php b/app/OptionsIO/Sites/HttpsEnabled.php index e4d9299..5fccde3 100644 --- a/app/OptionsIO/Sites/HttpsEnabled.php +++ b/app/OptionsIO/Sites/HttpsEnabled.php @@ -8,7 +8,7 @@ class HttpsEnabled extends Option { protected $default = 1; - protected $defaultWhenSkipped = 0; + protected $nonInteractiveDefault = 0; protected string $promptType = 'confirm'; diff --git a/app/OptionsIO/Sites/PageCacheEnabled.php b/app/OptionsIO/Sites/PageCacheEnabled.php index 3ef8857..776d27b 100644 --- a/app/OptionsIO/Sites/PageCacheEnabled.php +++ b/app/OptionsIO/Sites/PageCacheEnabled.php @@ -8,7 +8,7 @@ class PageCacheEnabled extends Option { protected $default = 1; - protected $defaultWhenSkipped = 0; + protected $nonInteractiveDefault = 0; protected string $promptType = 'confirm'; From 0cb3e30cb5f473c48fda29ef5893a7fe8ce5ae26 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Fri, 28 Jan 2022 11:02:04 -0600 Subject: [PATCH 13/37] Minor reorganization --- app/Commands/Concerns/HasOptionsIO.php | 24 +++++-------- app/Commands/Sites/CreateCommand.php | 49 +++++++++++++++----------- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/app/Commands/Concerns/HasOptionsIO.php b/app/Commands/Concerns/HasOptionsIO.php index e613822..df10efc 100644 --- a/app/Commands/Concerns/HasOptionsIO.php +++ b/app/Commands/Concerns/HasOptionsIO.php @@ -7,33 +7,25 @@ trait HasOptionsIO { /** - * Initializes an options object, outputs prompt for and return user input. - * - * @param bool|string|array $defaultOverride + * @return mixed */ - protected function resolveOptionIO(string $optionClass, $defaultOverride = null, bool $nonInteractive = false): ?string + protected function getOptionValue(Option $option, bool $nonInteractive = false) { - $optionClass = resolve($optionClass); - - if (!is_null($defaultOverride)) { - $optionClass->default = $defaultOverride; - } - if ($nonInteractive) { - return $optionClass->nonInteractiveDefault ?? $optionClass->default; + return $option->nonInteractiveDefault ?? $option->default; } - return $this->promptForOption($optionClass); + return $this->promptForOption($option); } /** * @return mixed */ - protected function promptForOption(Option $optionClass) + protected function promptForOption(Option $option) { - if (in_array('App\OptionsIO\HasChoices', class_uses($optionClass))) { - return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->choices, $optionClass->default); + if (in_array('App\OptionsIO\HasChoices', class_uses($option))) { + return $this->{$option->promptType}($option->promptValue, $option->choices, $option->default); } - return $this->{$optionClass->promptType}($optionClass->promptValue, $optionClass->default); + return $this->{$option->promptType}($option->promptValue, $option->default); } } diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index ea9dc92..2180fc3 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -47,8 +47,6 @@ class CreateCommand extends BaseCommand protected $description = 'Create a site'; - protected string $domain = ''; - protected array $availableOptionIO = [ 'domain' => Domain::class, 'https_enabled' => HttpsEnabled::class, @@ -72,26 +70,9 @@ protected function action(): int return self::INVALID; } - $userInput = []; $server = $this->selectServer('deploy to')->first(); - $optionIO = $this->getAvailableOptionIO($this->argument('installation_method')); - - foreach ($optionIO as $optionKey => $optionClass) { - if (empty($this->option($optionKey))) { - $default = null; - if ($optionKey === 'site_user' || $optionKey === 'db_name' || $optionKey === 'db_user' || $optionKey === 'wp_title') { - $default = $this->domain; - } - - $userInput[$optionKey] = $this->resolveOptionIO($optionClass, $default, $this->nonInteractive()); - } - - if ($optionKey === 'domain') { - $this->domain = $userInput[$optionKey] ?? $this->option('domain'); - } - } - - $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), $userInput)); + $userInput = $this->getUserInput(); + $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), $userInput)); $this->successfulStep("{$site->domain} is {$site->status} (event_id = {$site->eventId()})"); @@ -117,4 +98,30 @@ protected function getAvailableOptionIO(string $type): array return $this->availableOptionIO; } } + + protected function getUserInput(): array + { + $domain = ''; + $userInput = []; + $optionIO = $this->getAvailableOptionIO($this->argument('installation_method')); + + foreach ($optionIO as $optionKey => $optionClass) { + // skip if option already set + if (empty($this->option($optionKey))) { + $optionClass = resolve($optionClass); + + // these options use the domain to "seed" default values + if ($optionKey === 'site_user' || $optionKey === 'db_name' || $optionKey === 'db_user' || $optionKey === 'wp_title') { + $optionClass->default = $domain; + } + + $userInput[$optionKey] = $this->getOptionValue($optionClass, $this->nonInteractive()); + } + + if ($optionKey === 'domain') { + $domain = $userInput[$optionKey] ?? $this->option('domain'); + } + } + return $userInput; + } } From 490ea1839446eba5b7e0c74d62a21c65dd5fcc65 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Fri, 28 Jan 2022 16:36:04 -0600 Subject: [PATCH 14/37] Added tests --- .../Commands/SitesCreateCommandTest.php | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 tests/Feature/Commands/SitesCreateCommandTest.php diff --git a/tests/Feature/Commands/SitesCreateCommandTest.php b/tests/Feature/Commands/SitesCreateCommandTest.php new file mode 100644 index 0000000..845cc1e --- /dev/null +++ b/tests/Feature/Commands/SitesCreateCommandTest.php @@ -0,0 +1,165 @@ +inputParamDefaults = [ + 'installation_method' => null, + 'domain' => null, + 'php_version' => '8.0', + 'site_user' => null, + 'page_cache' => [ + 'enabled' => 0, + ], + 'https' => [ + 'enabled' => 0, + ], + 'database' => [ + 'name' => null, + 'username' => null, + 'password' => null, + ], + 'wordpress' => [ + 'title' => null, + 'admin_user' => null, + 'admin_email' => null, + 'admin_password' => null, + ], + ]; + + $this->clientMock->shouldReceive('request')->with('GET', 'servers/1', [])->andReturn( + new Response(200, [], json_encode(['data' => ['id' => 1, 'name' => 'hellfish-media']])) + ); +}); + +test('"sites:create blank" fails with invalid data', function () { + $params = array_merge($this->inputParamDefaults, [ + 'installation_method' => 'blank', + 'server_id' => 1, + ]); + + $this->clientMock->shouldReceive('request')->with('POST', 'sites', [ + 'form_params' => $params, + ])->andReturn( + new Response(422, [], json_encode([ + 'message' => 'The given data was invalid.', + 'errors' => [ + ['field' => 'error message'], + ], + ])) + ); + + $this->artisan('sites:create blank 1 -f') + ->expectsOutput('Validation errors occurred.') + ->assertExitCode(1); +}); + +test('"sites:create blank" succeeds with correct params', function () { + $params = array_merge($this->inputParamDefaults, [ + 'installation_method' => 'blank', + 'domain' => 'hellfish.media', + 'server_id' => 1, + 'php_version' => '7.4', + + 'site_user' => 'hellfishmedia', + 'https' => ['enabled' => true], + 'page_cache' => ['enabled' => true], + ]); + + $this->clientMock->shouldReceive('request')->with('POST', 'sites', [ + 'form_params' => $params, + ])->andReturn(new Response(200, [], json_encode([ + 'event_id' => '100', + 'data' => [ + 'id' => 1, + 'domain' => 'hellfish.media', + 'status' => 'deploying', + ], + ]))); + + $this->artisan('sites:create blank 1 --domain=hellfish.media --https_enabled --page_cache_enabled --php_version="74" -f') + ->assertExitCode(0); +}); + +test('"sites:create wp" fails with invalid data', function () { + $params = array_merge($this->inputParamDefaults, [ + 'installation_method' => 'wp', + 'server_id' => 1, + 'site_user' => '', + 'database' => [ + 'name' => '', + 'username' => '', + 'password' => 'password', + ], + 'wordpress' => [ + 'title' => null, + 'admin_user' => null, + 'admin_email' => null, + 'admin_password' => 'password', + ], + ]); + + $this->clientMock->shouldReceive('request')->with('POST', 'sites', [ + 'form_params' => $params, + ])->andReturn( + new Response(422, [], json_encode([ + 'message' => 'The given data was invalid.', + 'errors' => [ + ['field' => 'error message'], + ], + ])) + ); + + $this->artisan('sites:create wp 1 --db_pass=password --wp_admin_pass=password -f') + ->expectsOutput('Validation errors occurred.') + ->assertExitCode(1); +}); + +test('"sites:create wp" succeeds with correct data', function () { + $params = array_merge($this->inputParamDefaults, [ + 'installation_method' => 'wp', + 'server_id' => 1, + 'domain' => 'hellfish.media', + 'site_user' => 'test', + 'https' => ['enabled' => true], + 'database' => [ + 'name' => 'dbname', + 'username' => 'dbuser', + 'password' => 'password', + ], + 'wordpress' => [ + 'title' => 'Site Title', + 'admin_user' => 'abe', + 'admin_email' => 'flying@hellfish.media', + 'admin_password' => 'password', + ], + ]); + + $this->clientMock->shouldReceive('request')->with('POST', 'sites', [ + 'form_params' => $params, + ])->andReturn( + new Response(200, [], json_encode([ + 'event_id' => '100', + 'data' => [ + 'id' => 1, + 'domain' => 'hellfish.media', + 'status' => 'deploying', + ], + ])) + ); + + $this->artisan('sites:create wp 1 + --domain="hellfish.media" + --site_user=test + --https_enabled + --db_name=dbname + --db_user=dbuser + --db_pass=password + --wp_title="Site Title" + --wp_admin_user="abe" + --wp_admin_email="flying@hellfish.media" + --wp_admin_pass=password -f') + ->assertExitCode(0); +}); From 2cf6a2e460b988d7c9d4ae32ce60d70841faaac9 Mon Sep 17 00:00:00 2001 From: ohryan Date: Fri, 28 Jan 2022 22:37:00 +0000 Subject: [PATCH 15/37] Apply php-cs-fixer changes --- tests/Feature/Commands/SitesCreateCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/Commands/SitesCreateCommandTest.php b/tests/Feature/Commands/SitesCreateCommandTest.php index 845cc1e..5d812a0 100644 --- a/tests/Feature/Commands/SitesCreateCommandTest.php +++ b/tests/Feature/Commands/SitesCreateCommandTest.php @@ -43,7 +43,7 @@ $this->clientMock->shouldReceive('request')->with('POST', 'sites', [ 'form_params' => $params, ])->andReturn( - new Response(422, [], json_encode([ + new Response(422, [], json_encode([ 'message' => 'The given data was invalid.', 'errors' => [ ['field' => 'error message'], From ba6e7de09bdf8a28da6cacd1904dc1f7c37adf59 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 1 Feb 2022 16:20:31 -0600 Subject: [PATCH 16/37] Refactored "OptionsIO" approach to "HasPrompts". --- app/Commands/Concerns/HasOptionsIO.php | 31 ----- app/Commands/Concerns/HasPrompts.php | 52 ++++++++ app/Commands/Sites/CreateCommand.php | 118 +++++++++--------- app/Helpers/OptionsHelper.php | 4 +- app/Helpers/PromptHelper.php | 29 +++++ app/OptionsIO/HasChoices.php | 16 --- app/OptionsIO/Option.php | 33 ----- app/OptionsIO/Sites/DbName.php | 15 --- app/OptionsIO/Sites/DbPass.php | 16 --- app/OptionsIO/Sites/DbUser.php | 15 --- app/OptionsIO/Sites/Domain.php | 10 -- app/OptionsIO/Sites/HttpsEnabled.php | 16 --- app/OptionsIO/Sites/PageCacheEnabled.php | 16 --- app/OptionsIO/Sites/PhpVersion.php | 21 ---- app/OptionsIO/Sites/SiteUser.php | 15 --- app/OptionsIO/Sites/WpAdminEmail.php | 10 -- app/OptionsIO/Sites/WpAdminPass.php | 16 --- app/OptionsIO/Sites/WpAdminUser.php | 10 -- app/OptionsIO/Sites/WpTitle.php | 10 -- .../Commands/SitesCreateCommandTest.php | 2 +- 20 files changed, 140 insertions(+), 315 deletions(-) delete mode 100644 app/Commands/Concerns/HasOptionsIO.php create mode 100644 app/Commands/Concerns/HasPrompts.php create mode 100644 app/Helpers/PromptHelper.php delete mode 100644 app/OptionsIO/HasChoices.php delete mode 100644 app/OptionsIO/Option.php delete mode 100644 app/OptionsIO/Sites/DbName.php delete mode 100644 app/OptionsIO/Sites/DbPass.php delete mode 100644 app/OptionsIO/Sites/DbUser.php delete mode 100644 app/OptionsIO/Sites/Domain.php delete mode 100644 app/OptionsIO/Sites/HttpsEnabled.php delete mode 100644 app/OptionsIO/Sites/PageCacheEnabled.php delete mode 100644 app/OptionsIO/Sites/PhpVersion.php delete mode 100644 app/OptionsIO/Sites/SiteUser.php delete mode 100644 app/OptionsIO/Sites/WpAdminEmail.php delete mode 100644 app/OptionsIO/Sites/WpAdminPass.php delete mode 100644 app/OptionsIO/Sites/WpAdminUser.php delete mode 100644 app/OptionsIO/Sites/WpTitle.php diff --git a/app/Commands/Concerns/HasOptionsIO.php b/app/Commands/Concerns/HasOptionsIO.php deleted file mode 100644 index df10efc..0000000 --- a/app/Commands/Concerns/HasOptionsIO.php +++ /dev/null @@ -1,31 +0,0 @@ -nonInteractiveDefault ?? $option->default; - } - - return $this->promptForOption($option); - } - - /** - * @return mixed - */ - protected function promptForOption(Option $option) - { - if (in_array('App\OptionsIO\HasChoices', class_uses($option))) { - return $this->{$option->promptType}($option->promptValue, $option->choices, $option->default); - } - return $this->{$option->promptType}($option->promptValue, $option->default); - } -} diff --git a/app/Commands/Concerns/HasPrompts.php b/app/Commands/Concerns/HasPrompts.php new file mode 100644 index 0000000..8ead283 --- /dev/null +++ b/app/Commands/Concerns/HasPrompts.php @@ -0,0 +1,52 @@ +prompt($prompt, $default); + } + + /** + * @return mixed + */ + protected function prompt(array $prompt, $default) + { + if ($prompt['type'] === 'choice') { + return $this->{$prompt['type']}($prompt['prompt'], $prompt['choices'], $default); + } + return $this->{$prompt['type']}($prompt['prompt'], $default); + } + + protected function promptForAnswers(bool $nonInteractive = false, string $type = 'option'): array + { + $userInput = []; + + foreach ($this->getPrompts() as $paramName => $config) { + $userInput[$paramName] = $this->$type($paramName) ?? $this->resolveAnswer($config, $nonInteractive); + } + + return $userInput; + } + + protected function getPrompts(): array + { + return $this->prompts; + } +} diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 2180fc3..f8d7758 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -3,28 +3,17 @@ namespace App\Commands\Sites; use App\Commands\BaseCommand; -use App\Commands\Concerns\HasOptionsIO; +use App\Commands\Concerns\HasPrompts; use App\Commands\Concerns\InteractsWithIO; use App\Commands\Concerns\SelectsServer; use App\Helpers\OptionsHelper; -use App\OptionsIO\Sites\DbName; -use App\OptionsIO\Sites\DbPass; -use App\OptionsIO\Sites\DbUser; -use App\OptionsIO\Sites\Domain; -use App\OptionsIO\Sites\HttpsEnabled; -use App\OptionsIO\Sites\PageCacheEnabled; -use App\OptionsIO\Sites\PhpVersion; -use App\OptionsIO\Sites\SiteUser; -use App\OptionsIO\Sites\WpAdminEmail; -use App\OptionsIO\Sites\WpAdminPass; -use App\OptionsIO\Sites\WpAdminUser; -use App\OptionsIO\Sites\WpTitle; use Illuminate\Support\Arr; +use Illuminate\Support\Str; class CreateCommand extends BaseCommand { use InteractsWithIO; - use HasOptionsIO; + use HasPrompts; use SelectsServer; protected $signature = 'sites:create @@ -47,20 +36,7 @@ class CreateCommand extends BaseCommand protected $description = 'Create a site'; - protected array $availableOptionIO = [ - 'domain' => Domain::class, - 'https_enabled' => HttpsEnabled::class, - 'site_user' => SiteUser::class, - 'db_name' => DbName::class, - 'db_user' => DbUser::class, - 'db_pass' => DbPass::class, - 'wp_title' => WpTitle::class, - 'wp_admin_user' => WpAdminUser::class, - 'wp_admin_email' => WpAdminEmail::class, - 'wp_admin_pass' => WpAdminPass::class, - 'php_version' => PhpVersion::class, - 'page_cache_enabled' => PageCacheEnabled::class, - ]; + protected ?string $domain = ''; protected function action(): int { @@ -70,58 +46,76 @@ protected function action(): int return self::INVALID; } - $server = $this->selectServer('deploy to')->first(); - $userInput = $this->getUserInput(); - $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), $userInput)); + $server = $this->selectServer('deploy to')->first(); + $this->domain = $this->option('domain') ?? $this->resolveAnswer(['prompt' => 'Domain Name'], $this->nonInteractive()); + $userInput = $this->promptForAnswers($this->nonInteractive()); + + $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), ['domain' => $this->domain], $userInput)); $this->successfulStep("{$site->domain} is {$site->status} (event_id = {$site->eventId()})"); return self::SUCCESS; } - /** - * Use different options depending on site install type. - */ - protected function getAvailableOptionIO(string $type): array + protected function getPrompts(): array { - switch ($type) { + $prompts = [ + 'https_enabled' => [ + 'default' => 1, + 'nonInteractiveDefault' => 0, + 'type' => 'confirm', + 'prompt' => 'Enable HTTPS', + ], + 'site_user' => [ + 'prompt' => 'Site User', + 'defaultCallback' => [$this, 'getDomainSlug'], + ], + 'db_name' => [ + 'prompt' => 'Database name', + 'defaultCallback' => [$this, 'getDomainSlug'], + ], + 'db_pass' => [ + 'prompt' => 'Database Password', + 'defaultCallback' => fn () => Str::random(12), + ], + 'wp_title' => ['prompt' => 'WordPress Title'], + 'wp_admin_email' => ['prompt' => 'WordPress admin email address'], + 'wp_admin_user' => ['prompt' => 'WordPress admin username'], + 'wp_admin_pass' => [ + 'prompt' => 'WordPress admin password', + 'defaultCallback' => fn () => Str::random(12), + ], + 'php_version' => [ + 'type' => 'choice', + 'prompt' => 'PHP Version', + 'default' => '8.0', + 'choices' => OptionsHelper::PHP_VERSIONS, + ], + 'page_cache_enabled' => [ + 'default' => 1, + 'nonInteractiveDefault' => 0, + 'type' => 'confirm', + 'prompt' => 'Enable page cache', + ], + ]; + + switch ($this->argument('installation_method')) { case 'blank': - return Arr::except($this->availableOptionIO, [ + return Arr::except($prompts, [ 'db_name', 'db_user', 'db_pass', 'wp_title', 'wp_admin_user', 'wp_admin_email', 'wp_admin_pass', ]); case 'git': - return Arr::except($this->availableOptionIO, [ + return Arr::except($prompts, [ 'wp_title', 'wp_admin_user', 'wp_admin_email', 'wp_admin_pass', ]); default: - return $this->availableOptionIO; + return $prompts; } } - protected function getUserInput(): array + public function getDomainSlug(): string { - $domain = ''; - $userInput = []; - $optionIO = $this->getAvailableOptionIO($this->argument('installation_method')); - - foreach ($optionIO as $optionKey => $optionClass) { - // skip if option already set - if (empty($this->option($optionKey))) { - $optionClass = resolve($optionClass); - - // these options use the domain to "seed" default values - if ($optionKey === 'site_user' || $optionKey === 'db_name' || $optionKey === 'db_user' || $optionKey === 'wp_title') { - $optionClass->default = $domain; - } - - $userInput[$optionKey] = $this->getOptionValue($optionClass, $this->nonInteractive()); - } - - if ($optionKey === 'domain') { - $domain = $userInput[$optionKey] ?? $this->option('domain'); - } - } - return $userInput; + return str_replace('.', '', $this->domain); } } diff --git a/app/Helpers/OptionsHelper.php b/app/Helpers/OptionsHelper.php index d3a6e47..d6eb4e2 100644 --- a/app/Helpers/OptionsHelper.php +++ b/app/Helpers/OptionsHelper.php @@ -8,7 +8,7 @@ class OptionsHelper public const INSTALLATION_METHODS = ['wp', 'blank']; public const PHP_VERSIONS = [ - '80' => '8.0', - '74' => '7.4', + '8.0' => '8.0', + '7.4' => '7.4', ]; } diff --git a/app/Helpers/PromptHelper.php b/app/Helpers/PromptHelper.php new file mode 100644 index 0000000..820510a --- /dev/null +++ b/app/Helpers/PromptHelper.php @@ -0,0 +1,29 @@ + 'ask', + 'prompt' => '', + 'default' => null, + 'defaultCallback' => null, + 'nonInteractiveDefault' => null, + 'choices' => [], + ]; + + public static function config(array $config): array + { + return array_merge(self::DEFAULTS, $config); + } + + public static function default(array $config) + { + if (!is_null($config['defaultCallback'])) { + return call_user_func($config['defaultCallback']); + } + + return $config['default']; + } +} diff --git a/app/OptionsIO/HasChoices.php b/app/OptionsIO/HasChoices.php deleted file mode 100644 index f6208f7..0000000 --- a/app/OptionsIO/HasChoices.php +++ /dev/null @@ -1,16 +0,0 @@ -choices ?? []; - } - - public function getPromptType(): string - { - return 'askToSelect'; - } -} diff --git a/app/OptionsIO/Option.php b/app/OptionsIO/Option.php deleted file mode 100644 index 3ef48fc..0000000 --- a/app/OptionsIO/Option.php +++ /dev/null @@ -1,33 +0,0 @@ -$method(); - } - return $this->{$name}; - } - - public function __set(string $name, $value): void - { - $this->{$name} = $value; - } -} diff --git a/app/OptionsIO/Sites/DbName.php b/app/OptionsIO/Sites/DbName.php deleted file mode 100644 index 67e7009..0000000 --- a/app/OptionsIO/Sites/DbName.php +++ /dev/null @@ -1,15 +0,0 @@ -default); - } -} diff --git a/app/OptionsIO/Sites/DbPass.php b/app/OptionsIO/Sites/DbPass.php deleted file mode 100644 index b5d442a..0000000 --- a/app/OptionsIO/Sites/DbPass.php +++ /dev/null @@ -1,16 +0,0 @@ -default); - } -} diff --git a/app/OptionsIO/Sites/Domain.php b/app/OptionsIO/Sites/Domain.php deleted file mode 100644 index 464bbb8..0000000 --- a/app/OptionsIO/Sites/Domain.php +++ /dev/null @@ -1,10 +0,0 @@ -default); - } -} diff --git a/app/OptionsIO/Sites/WpAdminEmail.php b/app/OptionsIO/Sites/WpAdminEmail.php deleted file mode 100644 index 1663d30..0000000 --- a/app/OptionsIO/Sites/WpAdminEmail.php +++ /dev/null @@ -1,10 +0,0 @@ -artisan('sites:create blank 1 --domain=hellfish.media --https_enabled --page_cache_enabled --php_version="74" -f') + $this->artisan('sites:create blank 1 --domain=hellfish.media --https_enabled --page_cache_enabled --php_version="7.4" -f') ->assertExitCode(0); }); From 4bd6eab10a7d872e0fc488b60c0fb9f0eb1b356f Mon Sep 17 00:00:00 2001 From: ohryan Date: Tue, 1 Feb 2022 22:20:57 +0000 Subject: [PATCH 17/37] Apply php-cs-fixer changes --- app/Helpers/PromptHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Helpers/PromptHelper.php b/app/Helpers/PromptHelper.php index 820510a..adf53be 100644 --- a/app/Helpers/PromptHelper.php +++ b/app/Helpers/PromptHelper.php @@ -4,7 +4,7 @@ class PromptHelper { - const DEFAULTS = [ + public const DEFAULTS = [ 'type' => 'ask', 'prompt' => '', 'default' => null, From 2d84767a0eaca6a1762f21ff3c88057fceb2a04d Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Wed, 2 Feb 2022 13:42:36 -0600 Subject: [PATCH 18/37] Simplified HasPrompts and related --- app/Commands/Concerns/HasPrompts.php | 43 +++++--------- app/Commands/Sites/CreateCommand.php | 78 +++++++++++++++---------- app/Helpers/PromptHelper.php | 29 --------- app/Repositories/SpinupWpRepository.php | 2 - 4 files changed, 62 insertions(+), 90 deletions(-) delete mode 100644 app/Helpers/PromptHelper.php diff --git a/app/Commands/Concerns/HasPrompts.php b/app/Commands/Concerns/HasPrompts.php index 8ead283..88e828c 100644 --- a/app/Commands/Concerns/HasPrompts.php +++ b/app/Commands/Concerns/HasPrompts.php @@ -2,51 +2,36 @@ namespace App\Commands\Concerns; -use App\Helpers\PromptHelper; - trait HasPrompts { - protected array $prompts = []; - - /** - * @return mixed - */ - protected function resolveAnswer(array $promptConfig, bool $nonInteractive = false) - { - $prompt = PromptHelper::config($promptConfig); - $default = PromptHelper::default($prompt); - - if ($nonInteractive) { - return $promptConfig['nonInteractiveDefault'] ?? $default ?? null; - } - - return $this->prompt($prompt, $default); - } + protected array $questions = []; /** + * @param array $prompt * @return mixed */ - protected function prompt(array $prompt, $default) + protected function doPrompt(array $prompt) { if ($prompt['type'] === 'choice') { - return $this->{$prompt['type']}($prompt['prompt'], $prompt['choices'], $default); + return $this->{$prompt['type']}($prompt['prompt'], $prompt['choices'], $prompt['default']); } - return $this->{$prompt['type']}($prompt['prompt'], $default); + return $this->{$prompt['type']}($prompt['prompt'], $prompt['default']); } - protected function promptForAnswers(bool $nonInteractive = false, string $type = 'option'): array + protected function doPrompts(array $prompts, bool $nonInteractive = false, string $type = 'option'): array { $userInput = []; - foreach ($this->getPrompts() as $paramName => $config) { - $userInput[$paramName] = $this->$type($paramName) ?? $this->resolveAnswer($config, $nonInteractive); + foreach ($prompts as $paramName => $prompt) { + $cliInput = $this->$type($paramName); + + if (!empty($cliInput) || $nonInteractive) { + $userInput[$paramName] = $cliInput ?? $prompt['default']; + } else { + $userInput[$paramName] = $this->doPrompt($prompt); + } } return $userInput; } - - protected function getPrompts(): array - { - return $this->prompts; - } } diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index f8d7758..ec5ad79 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -36,7 +36,7 @@ class CreateCommand extends BaseCommand protected $description = 'Create a site'; - protected ?string $domain = ''; + protected array $userInput; protected function action(): int { @@ -46,11 +46,18 @@ protected function action(): int return self::INVALID; } - $server = $this->selectServer('deploy to')->first(); - $this->domain = $this->option('domain') ?? $this->resolveAnswer(['prompt' => 'Domain Name'], $this->nonInteractive()); - $userInput = $this->promptForAnswers($this->nonInteractive()); + $server = $this->selectServer('deploy to')->first(); - $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), ['domain' => $this->domain], $userInput)); + $this->userInput = $this->doPrompts([ + 'domain' => [ + 'type' => 'ask', + 'prompt' => 'Domain Name', + 'default' => !$this->nonInteractive(), + ], + ], $this->nonInteractive()); + $this->userInput += $this->doPrompts($this->getPrompts(), $this->nonInteractive()); + + $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), $this->userInput)); $this->successfulStep("{$site->domain} is {$site->status} (event_id = {$site->eventId()})"); @@ -61,29 +68,45 @@ protected function getPrompts(): array { $prompts = [ 'https_enabled' => [ - 'default' => 1, - 'nonInteractiveDefault' => 0, - 'type' => 'confirm', - 'prompt' => 'Enable HTTPS', + 'type' => 'confirm', + 'prompt' => 'Enable HTTPS', + 'default' => (int) !$this->nonInteractive(), ], 'site_user' => [ - 'prompt' => 'Site User', - 'defaultCallback' => [$this, 'getDomainSlug'], + 'type' => 'ask', + 'prompt' => 'Site User', + 'default' => $this->getDomainSlug(), ], 'db_name' => [ - 'prompt' => 'Database name', - 'defaultCallback' => [$this, 'getDomainSlug'], + 'type' => 'ask', + 'prompt' => 'Database name', + 'default' => $this->getDomainSlug(), ], 'db_pass' => [ - 'prompt' => 'Database Password', - 'defaultCallback' => fn () => Str::random(12), + 'type' => 'ask', + 'prompt' => 'Database Password', + 'default' => Str::random(12), + + ], + 'wp_title' => [ + 'type' => 'ask', + 'prompt' => 'WordPress Title', + 'default' => null, + ], + 'wp_admin_email' => [ + 'type' => 'ask', + 'prompt' => 'WordPress admin email address', + 'default' => null, ], - 'wp_title' => ['prompt' => 'WordPress Title'], - 'wp_admin_email' => ['prompt' => 'WordPress admin email address'], - 'wp_admin_user' => ['prompt' => 'WordPress admin username'], - 'wp_admin_pass' => [ - 'prompt' => 'WordPress admin password', - 'defaultCallback' => fn () => Str::random(12), + 'wp_admin_user' => [ + 'type' => 'ask', + 'prompt' => 'WordPress admin username', + 'default' => null, + ], + 'wp_admin_pass' => [ + 'type' => 'ask', + 'prompt' => 'WordPress admin password', + 'default' => Str::random(12), ], 'php_version' => [ 'type' => 'choice', @@ -92,10 +115,9 @@ protected function getPrompts(): array 'choices' => OptionsHelper::PHP_VERSIONS, ], 'page_cache_enabled' => [ - 'default' => 1, - 'nonInteractiveDefault' => 0, - 'type' => 'confirm', - 'prompt' => 'Enable page cache', + 'type' => 'confirm', + 'prompt' => 'Enable page cache', + 'default' => (int) !$this->nonInteractive(), ], ]; @@ -105,10 +127,6 @@ protected function getPrompts(): array 'db_name', 'db_user', 'db_pass', 'wp_title', 'wp_admin_user', 'wp_admin_email', 'wp_admin_pass', ]); - case 'git': - return Arr::except($prompts, [ - 'wp_title', 'wp_admin_user', 'wp_admin_email', 'wp_admin_pass', - ]); default: return $prompts; } @@ -116,6 +134,6 @@ protected function getPrompts(): array public function getDomainSlug(): string { - return str_replace('.', '', $this->domain); + return str_replace('.', '', $this->userInput['domain']); } } diff --git a/app/Helpers/PromptHelper.php b/app/Helpers/PromptHelper.php deleted file mode 100644 index adf53be..0000000 --- a/app/Helpers/PromptHelper.php +++ /dev/null @@ -1,29 +0,0 @@ - 'ask', - 'prompt' => '', - 'default' => null, - 'defaultCallback' => null, - 'nonInteractiveDefault' => null, - 'choices' => [], - ]; - - public static function config(array $config): array - { - return array_merge(self::DEFAULTS, $config); - } - - public static function default(array $config) - { - if (!is_null($config['defaultCallback'])) { - return call_user_func($config['defaultCallback']); - } - - return $config['default']; - } -} diff --git a/app/Repositories/SpinupWpRepository.php b/app/Repositories/SpinupWpRepository.php index b6c3601..3ea325e 100644 --- a/app/Repositories/SpinupWpRepository.php +++ b/app/Repositories/SpinupWpRepository.php @@ -3,7 +3,6 @@ namespace App\Repositories; use App\Helpers\OptionsHelper; -use App\OptionsIO\Sites\PhpVersion; use DeliciousBrains\SpinupWp\Endpoints\Event; use DeliciousBrains\SpinupWp\Endpoints\Server; use DeliciousBrains\SpinupWp\Endpoints\Site; @@ -11,7 +10,6 @@ use DeliciousBrains\SpinupWp\Resources\Site as SiteResource; use DeliciousBrains\SpinupWp\SpinupWp; use GuzzleHttp\Client; -use Illuminate\Support\Arr; use Illuminate\Support\Collection; /** From 6ebcabd96bc55e1add5934618e2c351bbc30b4ff Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Wed, 2 Feb 2022 14:36:50 -0600 Subject: [PATCH 19/37] Added missing prompt. --- app/Commands/Sites/CreateCommand.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index ec5ad79..fd06061 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -74,7 +74,7 @@ protected function getPrompts(): array ], 'site_user' => [ 'type' => 'ask', - 'prompt' => 'Site User', + 'prompt' => 'Site user', 'default' => $this->getDomainSlug(), ], 'db_name' => [ @@ -82,15 +82,20 @@ protected function getPrompts(): array 'prompt' => 'Database name', 'default' => $this->getDomainSlug(), ], + 'db_user' => [ + 'type' => 'ask', + 'prompt' => 'Database username', + 'default' => $this->getDomainSlug(), + ], 'db_pass' => [ 'type' => 'ask', - 'prompt' => 'Database Password', + 'prompt' => 'Database password', 'default' => Str::random(12), ], 'wp_title' => [ 'type' => 'ask', - 'prompt' => 'WordPress Title', + 'prompt' => 'WordPress title', 'default' => null, ], 'wp_admin_email' => [ @@ -110,7 +115,7 @@ protected function getPrompts(): array ], 'php_version' => [ 'type' => 'choice', - 'prompt' => 'PHP Version', + 'prompt' => 'PHP version', 'default' => '8.0', 'choices' => OptionsHelper::PHP_VERSIONS, ], From 9118ec51e746cbc5adbb9aead3512c97981b3af3 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Wed, 2 Feb 2022 14:44:55 -0600 Subject: [PATCH 20/37] Fixed incorrect default. --- app/Commands/Sites/CreateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index fd06061..1376a85 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -52,7 +52,7 @@ protected function action(): int 'domain' => [ 'type' => 'ask', 'prompt' => 'Domain Name', - 'default' => !$this->nonInteractive(), + 'default' => null, ], ], $this->nonInteractive()); $this->userInput += $this->doPrompts($this->getPrompts(), $this->nonInteractive()); From fac797fb5dcb1bc968c47f25f74e3386c38ba742 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Fri, 4 Feb 2022 10:12:23 -0600 Subject: [PATCH 21/37] Added "Questions" classes --- app/Questions/Ask.php | 11 +++++ app/Questions/Choice.php | 27 ++++++++++++ app/Questions/Confirm.php | 11 +++++ app/Questions/HasQuestions.php | 25 +++++++++++ app/Questions/Question.php | 78 ++++++++++++++++++++++++++++++++++ app/Questions/WithChoices.php | 8 ++++ 6 files changed, 160 insertions(+) create mode 100644 app/Questions/Ask.php create mode 100644 app/Questions/Choice.php create mode 100644 app/Questions/Confirm.php create mode 100644 app/Questions/HasQuestions.php create mode 100644 app/Questions/Question.php create mode 100644 app/Questions/WithChoices.php diff --git a/app/Questions/Ask.php b/app/Questions/Ask.php new file mode 100644 index 0000000..9a37854 --- /dev/null +++ b/app/Questions/Ask.php @@ -0,0 +1,11 @@ +command->ask($this->prompt, $this->default); + } +} diff --git a/app/Questions/Choice.php b/app/Questions/Choice.php new file mode 100644 index 0000000..c59b008 --- /dev/null +++ b/app/Questions/Choice.php @@ -0,0 +1,27 @@ + */ + private array $choices = []; + + /** + * @param array $choices + * @return static + */ + public function withChoices(array $choices): self + { + $this->choices = $choices; + return $this; + } + + /** @return string|array */ + public function question() + { + return $this->command->choice($this->prompt, $this->choices, $this->default); + } +} diff --git a/app/Questions/Confirm.php b/app/Questions/Confirm.php new file mode 100644 index 0000000..3bcad80 --- /dev/null +++ b/app/Questions/Confirm.php @@ -0,0 +1,11 @@ +command->confirm($this->prompt, $this->default); + } +} diff --git a/app/Questions/HasQuestions.php b/app/Questions/HasQuestions.php new file mode 100644 index 0000000..5507026 --- /dev/null +++ b/app/Questions/HasQuestions.php @@ -0,0 +1,25 @@ + */ + public function questions(): array + { + return []; + } + + public function askQuestions(bool $nonInteractive = false): array + { + $answers = []; + foreach ($this->questions() as $question) { + $question->nonInteractive($nonInteractive); + $answers += [ + $question->flag => $question->resolveAnswer($this), + ]; + } + + return $answers; + } +} diff --git a/app/Questions/Question.php b/app/Questions/Question.php new file mode 100644 index 0000000..9cce002 --- /dev/null +++ b/app/Questions/Question.php @@ -0,0 +1,78 @@ +prompt = $prompt; + $this->flag = Str::snake($prompt); + } + + /** @return static */ + public static function make(string $prompt): self + { + return new static($prompt); + } + + /** + * @param mixed $default + * @return static + */ + public function withDefault($default): self + { + $this->default = $default; + + return $this; + } + + /** @return static */ + public function withFlag(string $flag): self + { + $this->flag = $flag; + return $this; + } + + /** @return static */ + public function nonInteractive(bool $nonInteractive = true): self + { + $this->nonInteractive = $nonInteractive; + + return $this; + } + + /** @return mixed */ + public function resolveAnswer(Command $command) + { + $this->command = $command; + + $flagAnswer = $this->command->option(); + + if ($flagAnswer || $this->nonInteractive) { + return $flagAnswer; + } + + return $this->question(); + } + + /** @return mixed */ + abstract protected function question(); +} diff --git a/app/Questions/WithChoices.php b/app/Questions/WithChoices.php new file mode 100644 index 0000000..2f1913e --- /dev/null +++ b/app/Questions/WithChoices.php @@ -0,0 +1,8 @@ + Date: Fri, 4 Feb 2022 11:14:01 -0600 Subject: [PATCH 22/37] Implemented `Questions` --- app/Commands/Concerns/HasPrompts.php | 37 ------- app/Commands/Sites/CreateCommand.php | 147 ++++++++++++--------------- 2 files changed, 65 insertions(+), 119 deletions(-) delete mode 100644 app/Commands/Concerns/HasPrompts.php diff --git a/app/Commands/Concerns/HasPrompts.php b/app/Commands/Concerns/HasPrompts.php deleted file mode 100644 index 88e828c..0000000 --- a/app/Commands/Concerns/HasPrompts.php +++ /dev/null @@ -1,37 +0,0 @@ -{$prompt['type']}($prompt['prompt'], $prompt['choices'], $prompt['default']); - } - return $this->{$prompt['type']}($prompt['prompt'], $prompt['default']); - } - - protected function doPrompts(array $prompts, bool $nonInteractive = false, string $type = 'option'): array - { - $userInput = []; - - foreach ($prompts as $paramName => $prompt) { - $cliInput = $this->$type($paramName); - - if (!empty($cliInput) || $nonInteractive) { - $userInput[$paramName] = $cliInput ?? $prompt['default']; - } else { - $userInput[$paramName] = $this->doPrompt($prompt); - } - } - - return $userInput; - } -} diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 1376a85..018da0e 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -3,17 +3,17 @@ namespace App\Commands\Sites; use App\Commands\BaseCommand; -use App\Commands\Concerns\HasPrompts; -use App\Commands\Concerns\InteractsWithIO; use App\Commands\Concerns\SelectsServer; use App\Helpers\OptionsHelper; -use Illuminate\Support\Arr; +use App\Questions\Ask; +use App\Questions\Choice; +use App\Questions\Confirm; +use App\Questions\HasQuestions; use Illuminate\Support\Str; class CreateCommand extends BaseCommand { - use InteractsWithIO; - use HasPrompts; + use HasQuestions; use SelectsServer; protected $signature = 'sites:create @@ -48,14 +48,11 @@ protected function action(): int $server = $this->selectServer('deploy to')->first(); - $this->userInput = $this->doPrompts([ - 'domain' => [ - 'type' => 'ask', - 'prompt' => 'Domain Name', - 'default' => null, - ], - ], $this->nonInteractive()); - $this->userInput += $this->doPrompts($this->getPrompts(), $this->nonInteractive()); + $this->userInput['domain'] = Ask::make('Domain') + ->nonInteractive($this->nonInteractive()) + ->resolveAnswer($this); + + $this->userInput += $this->askQuestions($this->nonInteractive()); $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), $this->userInput)); @@ -64,81 +61,67 @@ protected function action(): int return self::SUCCESS; } - protected function getPrompts(): array + public function getDomainSlug(): string + { + return str_replace('.', '', $this->userInput['domain']); + } + + public function questions(): array { - $prompts = [ - 'https_enabled' => [ - 'type' => 'confirm', - 'prompt' => 'Enable HTTPS', - 'default' => (int) !$this->nonInteractive(), - ], - 'site_user' => [ - 'type' => 'ask', - 'prompt' => 'Site user', - 'default' => $this->getDomainSlug(), - ], - 'db_name' => [ - 'type' => 'ask', - 'prompt' => 'Database name', - 'default' => $this->getDomainSlug(), - ], - 'db_user' => [ - 'type' => 'ask', - 'prompt' => 'Database username', - 'default' => $this->getDomainSlug(), - ], - 'db_pass' => [ - 'type' => 'ask', - 'prompt' => 'Database password', - 'default' => Str::random(12), - - ], - 'wp_title' => [ - 'type' => 'ask', - 'prompt' => 'WordPress title', - 'default' => null, - ], - 'wp_admin_email' => [ - 'type' => 'ask', - 'prompt' => 'WordPress admin email address', - 'default' => null, - ], - 'wp_admin_user' => [ - 'type' => 'ask', - 'prompt' => 'WordPress admin username', - 'default' => null, - ], - 'wp_admin_pass' => [ - 'type' => 'ask', - 'prompt' => 'WordPress admin password', - 'default' => Str::random(12), - ], - 'php_version' => [ - 'type' => 'choice', - 'prompt' => 'PHP version', - 'default' => '8.0', - 'choices' => OptionsHelper::PHP_VERSIONS, - ], - 'page_cache_enabled' => [ - 'type' => 'confirm', - 'prompt' => 'Enable page cache', - 'default' => (int) !$this->nonInteractive(), - ], + $commonStart = [ + Confirm::make('Https Enabled') + ->withDefault((bool) !$this->nonInteractive()), + + Ask::make('Site User') + ->withDefault($this->getDomainSlug()), + ]; + + $db = [ + Ask::make('Db Name') + ->withDefault($this->getDomainSlug()), + + Ask::make('Db User') + ->withDefault($this->getDomainSlug()), + + Ask::make('Db Pass') + ->withDefault(Str::random(12)), + ]; + + $wp = [ + Ask::make('WordPress Title') + ->withFlag('wp_title'), + + Ask::make('WordPress admin email address') + ->withFlag('wp_admin_email'), + + Ask::make('WordPress admin username') + ->withFlag('wp_admin_user'), + + Ask::make('WordPress admin password') + ->withFlag('wp_admin_pass') + ->withDefault(Str::random(12)), + ]; + + $commonEnd = [ + Choice::make('PHP Version') + ->withFlag('php_version') + ->withChoices(OptionsHelper::PHP_VERSIONS) + ->withDefault('8.0'), + + Confirm::make('Page Cache Enabled') + ->withDefault((bool) !$this->nonInteractive()), ]; switch ($this->argument('installation_method')) { case 'blank': - return Arr::except($prompts, [ - 'db_name', 'db_user', 'db_pass', - 'wp_title', 'wp_admin_user', 'wp_admin_email', 'wp_admin_pass', - ]); + return array_merge($commonStart, $commonEnd); default: - return $prompts; + return array_merge( + $commonStart, + $db, + $wp, + $commonEnd + ); } } - - public function getDomainSlug(): string - { - return str_replace('.', '', $this->userInput['domain']); - } } From d7124f0c97dbfc17ce18b9d6249390b3c23d6ff0 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Fri, 4 Feb 2022 11:14:27 -0600 Subject: [PATCH 23/37] Bug fix --- app/Questions/Question.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Questions/Question.php b/app/Questions/Question.php index 9cce002..6103934 100644 --- a/app/Questions/Question.php +++ b/app/Questions/Question.php @@ -64,10 +64,10 @@ public function resolveAnswer(Command $command) { $this->command = $command; - $flagAnswer = $this->command->option(); + $flagInput = $this->command->option($this->flag); - if ($flagAnswer || $this->nonInteractive) { - return $flagAnswer; + if ($flagInput || $this->nonInteractive) { + return $flagInput ?? $this->default ?? null; } return $this->question(); From 1e410f4d2142c5ff41b56967eb1f6eceedaed99a Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Fri, 4 Feb 2022 14:36:46 -0600 Subject: [PATCH 24/37] Better trait name --- .../Concerns/{SelectsServer.php => HasServerIdParameter.php} | 2 +- app/Commands/Servers/DeleteCommand.php | 4 ++-- app/Commands/Servers/RebootCommand.php | 4 ++-- app/Commands/Servers/SshCommand.php | 4 ++-- app/Commands/Services/MysqlCommand.php | 4 ++-- app/Commands/Services/NginxCommand.php | 4 ++-- app/Commands/Services/PhpCommand.php | 4 ++-- app/Commands/Sites/CreateCommand.php | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) rename app/Commands/Concerns/{SelectsServer.php => HasServerIdParameter.php} (97%) diff --git a/app/Commands/Concerns/SelectsServer.php b/app/Commands/Concerns/HasServerIdParameter.php similarity index 97% rename from app/Commands/Concerns/SelectsServer.php rename to app/Commands/Concerns/HasServerIdParameter.php index 75c6dfd..4b97d09 100644 --- a/app/Commands/Concerns/SelectsServer.php +++ b/app/Commands/Concerns/HasServerIdParameter.php @@ -4,7 +4,7 @@ use Illuminate\Support\Collection; -trait SelectsServer +trait HasServerIdParameter { public function selectServer(string $action): Collection { diff --git a/app/Commands/Servers/DeleteCommand.php b/app/Commands/Servers/DeleteCommand.php index 19074e4..5a167f2 100644 --- a/app/Commands/Servers/DeleteCommand.php +++ b/app/Commands/Servers/DeleteCommand.php @@ -3,11 +3,11 @@ namespace App\Commands\Servers; use App\Commands\BaseCommand; -use App\Commands\Concerns\SelectsServer; +use App\Commands\Concerns\HasServerIdParameter; class DeleteCommand extends BaseCommand { - use SelectsServer; + use HasServerIdParameter; protected $signature = 'servers:delete {server_id? : The server to delete} diff --git a/app/Commands/Servers/RebootCommand.php b/app/Commands/Servers/RebootCommand.php index 7f76b8d..c9c2497 100644 --- a/app/Commands/Servers/RebootCommand.php +++ b/app/Commands/Servers/RebootCommand.php @@ -3,11 +3,11 @@ namespace App\Commands\Servers; use App\Commands\BaseCommand; -use App\Commands\Concerns\SelectsServer; +use App\Commands\Concerns\HasServerIdParameter; class RebootCommand extends BaseCommand { - use SelectsServer; + use HasServerIdParameter; protected $signature = 'servers:reboot {server_id? : The server to reboot} diff --git a/app/Commands/Servers/SshCommand.php b/app/Commands/Servers/SshCommand.php index 3996a81..da462c7 100644 --- a/app/Commands/Servers/SshCommand.php +++ b/app/Commands/Servers/SshCommand.php @@ -3,13 +3,13 @@ namespace App\Commands\Servers; use App\Commands\BaseCommand; +use App\Commands\Concerns\HasServerIdParameter; use App\Commands\Concerns\InteractsWithRemote; -use App\Commands\Concerns\SelectsServer; class SshCommand extends BaseCommand { use InteractsWithRemote; - use SelectsServer; + use HasServerIdParameter; protected $signature = 'servers:ssh {server_id? : The server to connect to} diff --git a/app/Commands/Services/MysqlCommand.php b/app/Commands/Services/MysqlCommand.php index 4b7f13c..0a30d64 100644 --- a/app/Commands/Services/MysqlCommand.php +++ b/app/Commands/Services/MysqlCommand.php @@ -3,11 +3,11 @@ namespace App\Commands\Services; use App\Commands\BaseCommand; -use App\Commands\Concerns\SelectsServer; +use App\Commands\Concerns\HasServerIdParameter; class MysqlCommand extends BaseCommand { - use SelectsServer; + use HasServerIdParameter; protected $signature = 'services:mysql {server_id? : The server to restart MySQL on} diff --git a/app/Commands/Services/NginxCommand.php b/app/Commands/Services/NginxCommand.php index 463ac37..e74ecaf 100644 --- a/app/Commands/Services/NginxCommand.php +++ b/app/Commands/Services/NginxCommand.php @@ -3,11 +3,11 @@ namespace App\Commands\Services; use App\Commands\BaseCommand; -use App\Commands\Concerns\SelectsServer; +use App\Commands\Concerns\HasServerIdParameter; class NginxCommand extends BaseCommand { - use SelectsServer; + use HasServerIdParameter; protected $signature = 'services:nginx {server_id? : The server to restart Nginx on} diff --git a/app/Commands/Services/PhpCommand.php b/app/Commands/Services/PhpCommand.php index f435161..d13fce5 100644 --- a/app/Commands/Services/PhpCommand.php +++ b/app/Commands/Services/PhpCommand.php @@ -3,11 +3,11 @@ namespace App\Commands\Services; use App\Commands\BaseCommand; -use App\Commands\Concerns\SelectsServer; +use App\Commands\Concerns\HasServerIdParameter; class PhpCommand extends BaseCommand { - use SelectsServer; + use HasServerIdParameter; protected $signature = 'services:php {server_id? : The server to restart PHP on} diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 018da0e..efe8c35 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -3,7 +3,7 @@ namespace App\Commands\Sites; use App\Commands\BaseCommand; -use App\Commands\Concerns\SelectsServer; +use App\Commands\Concerns\HasServerIdParameter; use App\Helpers\OptionsHelper; use App\Questions\Ask; use App\Questions\Choice; @@ -14,7 +14,7 @@ class CreateCommand extends BaseCommand { use HasQuestions; - use SelectsServer; + use HasServerIdParameter; protected $signature = 'sites:create {installation_method : Type of installation (wp or blank)} From 8768882a9e43ed787ad5f9dab5159f79f07954b9 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 22 Feb 2022 10:26:35 -0600 Subject: [PATCH 25/37] bug fix: should bail when no server selected --- app/Commands/Sites/CreateCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index efe8c35..97c4d2d 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -48,6 +48,10 @@ protected function action(): int $server = $this->selectServer('deploy to')->first(); + if (is_null($server)) { + return self::INVALID; + } + $this->userInput['domain'] = Ask::make('Domain') ->nonInteractive($this->nonInteractive()) ->resolveAnswer($this); From 047aae0e6fb215c1b577732bd9284b1bfe3ee016 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 22 Feb 2022 12:48:37 -0600 Subject: [PATCH 26/37] Label updates --- app/Commands/Sites/CreateCommand.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 97c4d2d..ba54ef4 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -52,7 +52,7 @@ protected function action(): int return self::INVALID; } - $this->userInput['domain'] = Ask::make('Domain') + $this->userInput['domain'] = Ask::make('Primary Domain') ->nonInteractive($this->nonInteractive()) ->resolveAnswer($this); @@ -73,7 +73,7 @@ public function getDomainSlug(): string public function questions(): array { $commonStart = [ - Confirm::make('Https Enabled') + Confirm::make('Enable HTTPS') ->withDefault((bool) !$this->nonInteractive()), Ask::make('Site User') @@ -81,13 +81,13 @@ public function questions(): array ]; $db = [ - Ask::make('Db Name') + Ask::make('Database Name') ->withDefault($this->getDomainSlug()), - Ask::make('Db User') + Ask::make('Database Username') ->withDefault($this->getDomainSlug()), - Ask::make('Db Pass') + Ask::make('Database Password') ->withDefault(Str::random(12)), ]; @@ -95,13 +95,13 @@ public function questions(): array Ask::make('WordPress Title') ->withFlag('wp_title'), - Ask::make('WordPress admin email address') + Ask::make('WordPress Admin Email') ->withFlag('wp_admin_email'), - Ask::make('WordPress admin username') + Ask::make('WordPress Admin Username') ->withFlag('wp_admin_user'), - Ask::make('WordPress admin password') + Ask::make('WordPress Admin Password') ->withFlag('wp_admin_pass') ->withDefault(Str::random(12)), ]; @@ -112,7 +112,7 @@ public function questions(): array ->withChoices(OptionsHelper::PHP_VERSIONS) ->withDefault('8.0'), - Confirm::make('Page Cache Enabled') + Confirm::make('Enable Page Cache') ->withDefault((bool) !$this->nonInteractive()), ]; From 3c2eadb3580acd2c5ad118060955e2ec7203629f Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 22 Feb 2022 13:06:12 -0600 Subject: [PATCH 27/37] Added missing flag values --- app/Commands/Sites/CreateCommand.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index ba54ef4..6c3710e 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -53,6 +53,7 @@ protected function action(): int } $this->userInput['domain'] = Ask::make('Primary Domain') + ->withFlag('domain') ->nonInteractive($this->nonInteractive()) ->resolveAnswer($this); @@ -74,6 +75,7 @@ public function questions(): array { $commonStart = [ Confirm::make('Enable HTTPS') + ->withFlag('https_enabled') ->withDefault((bool) !$this->nonInteractive()), Ask::make('Site User') @@ -82,12 +84,15 @@ public function questions(): array $db = [ Ask::make('Database Name') + ->withFlag('db_name') ->withDefault($this->getDomainSlug()), Ask::make('Database Username') + ->withFlag('db_user') ->withDefault($this->getDomainSlug()), Ask::make('Database Password') + ->withFlag('db_pass') ->withDefault(Str::random(12)), ]; @@ -113,6 +118,7 @@ public function questions(): array ->withDefault('8.0'), Confirm::make('Enable Page Cache') + ->withFlag('page_cache_enabled') ->withDefault((bool) !$this->nonInteractive()), ]; From 64c82465bafc52b2fa15323101429822b93ee78e Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 22 Feb 2022 14:30:13 -0600 Subject: [PATCH 28/37] Added table output for successful creation --- app/Commands/Sites/CreateCommand.php | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 6c3710e..f140428 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -59,9 +59,11 @@ protected function action(): int $this->userInput += $this->askQuestions($this->nonInteractive()); - $site = $this->spinupwp->createSite($server->id, array_merge($this->arguments(), $this->options(), $this->userInput)); + $this->userInput = array_merge($this->arguments(), $this->options(), $this->userInput); - $this->successfulStep("{$site->domain} is {$site->status} (event_id = {$site->eventId()})"); + $site = $this->spinupwp->createSite($server->id, $this->userInput); + + $this->displaySuccess($site->eventId()); return self::SUCCESS; } @@ -134,4 +136,33 @@ public function questions(): array ); } } + + protected function displaySuccess($eventId): void + { + $tableHeadings = [ + 'Event ID', + 'Site', + ]; + + $tableRow = [ + $eventId, + $this->userInput['domain'], + ]; + + if ($this->userInput['installation_method'] === 'wp') { + $tableHeadings = array_merge($tableHeadings, [ + 'Database Password', + 'WordPress Admin Password', + ]); + + $tableRow = array_merge($tableRow, [ + $this->userInput['db_pass'], + $this->userInput['wp_admin_pass'], + ]); + } + + $this->successfulStep('Site queued for creation.'); + + $this->stepTable($tableHeadings, [$tableRow]); + } } From 6552bbd630d7682d7e50c99fac2ff4961f45f7e2 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 22 Feb 2022 17:31:57 -0600 Subject: [PATCH 29/37] Added validation key labelling --- app/Commands/BaseCommand.php | 14 +++++++++++++- app/Commands/Sites/CreateCommand.php | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/Commands/BaseCommand.php b/app/Commands/BaseCommand.php index 85f1a96..10527b3 100644 --- a/app/Commands/BaseCommand.php +++ b/app/Commands/BaseCommand.php @@ -8,6 +8,7 @@ use DeliciousBrains\SpinupWp\Exceptions\ValidationException; use Exception; use GuzzleHttp\Client; +use Illuminate\Support\Str; use LaravelZero\Framework\Commands\Command; abstract class BaseCommand extends Command @@ -24,6 +25,8 @@ abstract class BaseCommand extends Command protected array $columnsMaxWidths = []; + protected array $validationLabels = []; + public function __construct(ConfigRepository $configuration, SpinupWpRepository $spinupWp) { parent::__construct(); @@ -57,7 +60,7 @@ public function handle(): int } catch (ValidationException $e) { $errorRows = []; foreach ($e->errors()['errors'] as $field => $errors) { - $errorRows[] = [$field, implode("\n", $errors)]; + $errorRows[] = [$this->applyValidationLabel($field), implode("\n", $errors)]; } $this->error('Validation errors occurred.'); @@ -93,5 +96,14 @@ protected function profile(): string return 'default'; } + protected function applyValidationLabel(string $key): string + { + if (empty($this->validationLabels) || !array_key_exists($key, $this->validationLabels)) { + return Str::title(str_replace('_', ' ', $key)); + } + + return $this->validationLabels[$key]; + } + abstract protected function action(): int; } diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index f140428..4ccdb94 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -38,6 +38,19 @@ class CreateCommand extends BaseCommand protected array $userInput; + protected array $validationLabels = [ + 'domain' => 'Primary Domain', + 'page_cache.enabled' => 'Enable Page Cache', + 'https.enabled' => 'Enable HTTPS', + 'database.name' => 'Database Name', + 'database.username' => 'Database Username', + 'database.password' => 'Database Password', + 'wordpress.title' => 'WordPress Title', + 'wordpress.admin_user' => 'WordPress Admin Username', + 'wordpress.admin_email' => 'WordPress Admin Email', + 'wordpress.admin_password' => 'WordPress Admin Password', + ]; + protected function action(): int { if (!in_array($this->argument('installation_method'), OptionsHelper::INSTALLATION_METHODS, true)) { From bb48ebcf4dc1291fa15e9def291c87f6d72c3518 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Fri, 25 Feb 2022 14:24:04 -0600 Subject: [PATCH 30/37] Switched `installation_method` to option. --- app/Commands/Sites/CreateCommand.php | 19 ++++++++++++------- .../Commands/SitesCreateCommandTest.php | 9 +++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 4ccdb94..8372a69 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -17,8 +17,8 @@ class CreateCommand extends BaseCommand use HasServerIdParameter; protected $signature = 'sites:create - {installation_method : Type of installation (wp or blank)} {server_id? : Server ID} + {--installation_method= : Type of installation (wp or blank)} {--domain= : Domain name} {--site_user=} {--db_name=} @@ -53,15 +53,20 @@ class CreateCommand extends BaseCommand protected function action(): int { - if (!in_array($this->argument('installation_method'), OptionsHelper::INSTALLATION_METHODS, true)) { - $this->error('Invalid site type.'); - $this->newLine(1); + $server = $this->selectServer('deploy to')->first(); + + if (is_null($server)) { return self::INVALID; } - $server = $this->selectServer('deploy to')->first(); + $this->userInput['installation_method'] = Choice::make('Installation Method') + ->withChoices(OptionsHelper::INSTALLATION_METHODS) + ->nonInteractive($this->nonInteractive()) + ->resolveAnswer($this); - if (is_null($server)) { + if (!in_array($this->userInput['installation_method'], OptionsHelper::INSTALLATION_METHODS, true)) { + $this->error('Invalid site type.'); + $this->newLine(1); return self::INVALID; } @@ -137,7 +142,7 @@ public function questions(): array ->withDefault((bool) !$this->nonInteractive()), ]; - switch ($this->argument('installation_method')) { + switch ($this->userInput['installation_method']) { case 'blank': return array_merge($commonStart, $commonEnd); default: diff --git a/tests/Feature/Commands/SitesCreateCommandTest.php b/tests/Feature/Commands/SitesCreateCommandTest.php index 08434f5..81c045d 100644 --- a/tests/Feature/Commands/SitesCreateCommandTest.php +++ b/tests/Feature/Commands/SitesCreateCommandTest.php @@ -51,7 +51,7 @@ ])) ); - $this->artisan('sites:create blank 1 -f') + $this->artisan('sites:create 1 --installation_method=blank -f') ->expectsOutput('Validation errors occurred.') ->assertExitCode(1); }); @@ -79,7 +79,7 @@ ], ]))); - $this->artisan('sites:create blank 1 --domain=hellfish.media --https_enabled --page_cache_enabled --php_version="7.4" -f') + $this->artisan('sites:create 1 --installation_method=blank --domain=hellfish.media --https_enabled --page_cache_enabled --php_version="7.4" -f') ->assertExitCode(0); }); @@ -112,7 +112,7 @@ ])) ); - $this->artisan('sites:create wp 1 --db_pass=password --wp_admin_pass=password -f') + $this->artisan('sites:create 1 --installation_method=wp --db_pass=password --wp_admin_pass=password -f') ->expectsOutput('Validation errors occurred.') ->assertExitCode(1); }); @@ -150,7 +150,8 @@ ])) ); - $this->artisan('sites:create wp 1 + $this->artisan('sites:create 1 + --installation_method=wp --domain="hellfish.media" --site_user=test --https_enabled From 34fdf1dd8ab109e60e59c4e900063a61bf3d0135 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Fri, 25 Feb 2022 14:28:18 -0600 Subject: [PATCH 31/37] Removed unnecessary array keys --- app/Helpers/OptionsHelper.php | 5 +---- app/Repositories/SpinupWpRepository.php | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/Helpers/OptionsHelper.php b/app/Helpers/OptionsHelper.php index d6eb4e2..e49943f 100644 --- a/app/Helpers/OptionsHelper.php +++ b/app/Helpers/OptionsHelper.php @@ -7,8 +7,5 @@ class OptionsHelper // SpinupWP CLI only supports a subset of installation methods available via the REST API public const INSTALLATION_METHODS = ['wp', 'blank']; - public const PHP_VERSIONS = [ - '8.0' => '8.0', - '7.4' => '7.4', - ]; + public const PHP_VERSIONS = ['8.0', '7.4']; } diff --git a/app/Repositories/SpinupWpRepository.php b/app/Repositories/SpinupWpRepository.php index 3ea325e..e48a72f 100644 --- a/app/Repositories/SpinupWpRepository.php +++ b/app/Repositories/SpinupWpRepository.php @@ -83,7 +83,7 @@ public function createSite(int $serverId, array $inputParams): SiteResource $inputParams = [ 'installation_method' => $inputParams['installation_method'], 'domain' => $inputParams['domain'], - 'php_version' => OptionsHelper::PHP_VERSIONS[$inputParams['php_version']], + 'php_version' => $inputParams['php_version'], 'site_user' => $inputParams['site_user'], 'page_cache' => [ 'enabled' => $inputParams['page_cache_enabled'], From 8f0cc21035d479dc1e63349e668358cc485dbc12 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Mon, 28 Feb 2022 14:06:35 -0600 Subject: [PATCH 32/37] Update app/Commands/Sites/CreateCommand.php Co-authored-by: James Clark --- app/Commands/Sites/CreateCommand.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 8372a69..ca0f1a4 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -20,17 +20,17 @@ class CreateCommand extends BaseCommand {server_id? : Server ID} {--installation_method= : Type of installation (wp or blank)} {--domain= : Domain name} - {--site_user=} - {--db_name=} - {--db_user=} - {--db_pass=} - {--wp_title=} - {--wp_admin_user=} - {--wp_admin_email=} - {--wp_admin_pass=} - {--php_version=} - {--page_cache_enabled} - {--https_enabled} + {--site_user= : name for unique system user who will have ownership permission of all the site files} + {--db_name= : name of a database to be created. Must be unique for the server} + {--db_user= : database level username to use when accessing the database} + {--db_pass= : database level password to use when accessing the database} + {--wp_title= : the title of your WordPress site} + {--wp_admin_user= : for a WordPress site, the admin user\'s username} + {--wp_admin_email= : for a WordPress site, the admin user\'s email} + {--wp_admin_pass= : for a Wordpress site, the admin user\'s password} + {--php_version= : PHP version the site will run under} + {--page_cache_enabled : enabling this option will configure Nginx FastCGI caching that is optimized for WordPress} + {--https_enabled : enabling secures your site by serving traffic over HTTPS} {--profile=} {--f|force}'; From 68924fc2ee3a7fed27e0732cb6cb5e58d291e510 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Mon, 28 Feb 2022 15:23:54 -0600 Subject: [PATCH 33/37] use kebab not snake --- app/Questions/Question.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Questions/Question.php b/app/Questions/Question.php index 6103934..267a50a 100644 --- a/app/Questions/Question.php +++ b/app/Questions/Question.php @@ -24,7 +24,7 @@ abstract class Question final public function __construct(string $prompt) { $this->prompt = $prompt; - $this->flag = Str::snake($prompt); + $this->flag = Str::kebab($prompt); } /** @return static */ From 81777572661fc2979db0e9d40c81d74dbc80e0c6 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Mon, 28 Feb 2022 15:25:58 -0600 Subject: [PATCH 34/37] refactor to use kebab case options --- app/Commands/Sites/CreateCommand.php | 56 +++++++++---------- app/Repositories/SpinupWpRepository.php | 24 ++++---- .../Commands/SitesCreateCommandTest.php | 26 ++++----- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index ca0f1a4..a1f5adc 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -18,19 +18,19 @@ class CreateCommand extends BaseCommand protected $signature = 'sites:create {server_id? : Server ID} - {--installation_method= : Type of installation (wp or blank)} + {--installation-method= : Type of installation (wp or blank)} {--domain= : Domain name} - {--site_user= : name for unique system user who will have ownership permission of all the site files} - {--db_name= : name of a database to be created. Must be unique for the server} - {--db_user= : database level username to use when accessing the database} - {--db_pass= : database level password to use when accessing the database} - {--wp_title= : the title of your WordPress site} - {--wp_admin_user= : for a WordPress site, the admin user\'s username} - {--wp_admin_email= : for a WordPress site, the admin user\'s email} - {--wp_admin_pass= : for a Wordpress site, the admin user\'s password} - {--php_version= : PHP version the site will run under} - {--page_cache_enabled : enabling this option will configure Nginx FastCGI caching that is optimized for WordPress} - {--https_enabled : enabling secures your site by serving traffic over HTTPS} + {--site-user= : name for unique system user who will have ownership permission of all the site files} + {--db-name= : name of a database to be created. Must be unique for the server} + {--db-user= : database level username to use when accessing the database} + {--db-pass= : database level password to use when accessing the database} + {--wp-title= : the title of your WordPress site} + {--wp-admin-user= : for a WordPress site, the admin user\'s username} + {--wp-admin-email= : for a WordPress site, the admin user\'s email} + {--wp-admin-pass= : for a Wordpress site, the admin user\'s password} + {--php-version= : PHP version the site will run under} + {--page-cache-enabled : enabling this option will configure Nginx FastCGI caching that is optimized for WordPress} + {--https-enabled : enabling secures your site by serving traffic over HTTPS} {--profile=} {--f|force}'; @@ -59,12 +59,12 @@ protected function action(): int return self::INVALID; } - $this->userInput['installation_method'] = Choice::make('Installation Method') + $this->userInput['installation-method'] = Choice::make('Installation Method') ->withChoices(OptionsHelper::INSTALLATION_METHODS) ->nonInteractive($this->nonInteractive()) ->resolveAnswer($this); - if (!in_array($this->userInput['installation_method'], OptionsHelper::INSTALLATION_METHODS, true)) { + if (!in_array($this->userInput['installation-method'], OptionsHelper::INSTALLATION_METHODS, true)) { $this->error('Invalid site type.'); $this->newLine(1); return self::INVALID; @@ -95,7 +95,7 @@ public function questions(): array { $commonStart = [ Confirm::make('Enable HTTPS') - ->withFlag('https_enabled') + ->withFlag('https-enabled') ->withDefault((bool) !$this->nonInteractive()), Ask::make('Site User') @@ -104,45 +104,45 @@ public function questions(): array $db = [ Ask::make('Database Name') - ->withFlag('db_name') + ->withFlag('db-name') ->withDefault($this->getDomainSlug()), Ask::make('Database Username') - ->withFlag('db_user') + ->withFlag('db-user') ->withDefault($this->getDomainSlug()), Ask::make('Database Password') - ->withFlag('db_pass') + ->withFlag('db-pass') ->withDefault(Str::random(12)), ]; $wp = [ Ask::make('WordPress Title') - ->withFlag('wp_title'), + ->withFlag('wp-title'), Ask::make('WordPress Admin Email') - ->withFlag('wp_admin_email'), + ->withFlag('wp-admin-email'), Ask::make('WordPress Admin Username') - ->withFlag('wp_admin_user'), + ->withFlag('wp-admin-user'), Ask::make('WordPress Admin Password') - ->withFlag('wp_admin_pass') + ->withFlag('wp-admin-pass') ->withDefault(Str::random(12)), ]; $commonEnd = [ Choice::make('PHP Version') - ->withFlag('php_version') + ->withFlag('php-version') ->withChoices(OptionsHelper::PHP_VERSIONS) ->withDefault('8.0'), Confirm::make('Enable Page Cache') - ->withFlag('page_cache_enabled') + ->withFlag('page-cache-enabled') ->withDefault((bool) !$this->nonInteractive()), ]; - switch ($this->userInput['installation_method']) { + switch ($this->userInput['installation-method']) { case 'blank': return array_merge($commonStart, $commonEnd); default: @@ -167,15 +167,15 @@ protected function displaySuccess($eventId): void $this->userInput['domain'], ]; - if ($this->userInput['installation_method'] === 'wp') { + if ($this->userInput['installation-method'] === 'wp') { $tableHeadings = array_merge($tableHeadings, [ 'Database Password', 'WordPress Admin Password', ]); $tableRow = array_merge($tableRow, [ - $this->userInput['db_pass'], - $this->userInput['wp_admin_pass'], + $this->userInput['db-pass'], + $this->userInput['wp-admin-pass'], ]); } diff --git a/app/Repositories/SpinupWpRepository.php b/app/Repositories/SpinupWpRepository.php index e48a72f..d3c40f0 100644 --- a/app/Repositories/SpinupWpRepository.php +++ b/app/Repositories/SpinupWpRepository.php @@ -81,26 +81,26 @@ public function listSites(int $serverId = null): Collection public function createSite(int $serverId, array $inputParams): SiteResource { $inputParams = [ - 'installation_method' => $inputParams['installation_method'], + 'installation_method' => $inputParams['installation-method'], 'domain' => $inputParams['domain'], - 'php_version' => $inputParams['php_version'], - 'site_user' => $inputParams['site_user'], + 'php_version' => $inputParams['php-version'], + 'site_user' => $inputParams['site-user'], 'page_cache' => [ - 'enabled' => $inputParams['page_cache_enabled'], + 'enabled' => $inputParams['page-cache-enabled'], ], 'https' => [ - 'enabled' => $inputParams['https_enabled'], + 'enabled' => $inputParams['https-enabled'], ], 'database' => [ - 'name' => $inputParams['db_name'], - 'username' => $inputParams['db_user'], - 'password' => $inputParams['db_pass'], + 'name' => $inputParams['db-name'], + 'username' => $inputParams['db-user'], + 'password' => $inputParams['db-pass'], ], 'wordpress' => [ - 'title' => $inputParams['wp_title'], - 'admin_user' => $inputParams['wp_admin_user'], - 'admin_email' => $inputParams['wp_admin_email'], - 'admin_password' => $inputParams['wp_admin_pass'], + 'title' => $inputParams['wp-title'], + 'admin_user' => $inputParams['wp-admin-user'], + 'admin_email' => $inputParams['wp-admin-email'], + 'admin_password' => $inputParams['wp-admin-pass'], ], ]; diff --git a/tests/Feature/Commands/SitesCreateCommandTest.php b/tests/Feature/Commands/SitesCreateCommandTest.php index 81c045d..5476037 100644 --- a/tests/Feature/Commands/SitesCreateCommandTest.php +++ b/tests/Feature/Commands/SitesCreateCommandTest.php @@ -51,7 +51,7 @@ ])) ); - $this->artisan('sites:create 1 --installation_method=blank -f') + $this->artisan('sites:create 1 --installation-method=blank -f') ->expectsOutput('Validation errors occurred.') ->assertExitCode(1); }); @@ -79,7 +79,7 @@ ], ]))); - $this->artisan('sites:create 1 --installation_method=blank --domain=hellfish.media --https_enabled --page_cache_enabled --php_version="7.4" -f') + $this->artisan('sites:create 1 --installation-method=blank --domain=hellfish.media --https-enabled --page-cache-enabled --php-version="7.4" -f') ->assertExitCode(0); }); @@ -112,7 +112,7 @@ ])) ); - $this->artisan('sites:create 1 --installation_method=wp --db_pass=password --wp_admin_pass=password -f') + $this->artisan('sites:create 1 --installation-method=wp --db-pass=password --wp-admin-pass=password -f') ->expectsOutput('Validation errors occurred.') ->assertExitCode(1); }); @@ -151,16 +151,16 @@ ); $this->artisan('sites:create 1 - --installation_method=wp + --installation-method=wp --domain="hellfish.media" - --site_user=test - --https_enabled - --db_name=dbname - --db_user=dbuser - --db_pass=password - --wp_title="Site Title" - --wp_admin_user="abe" - --wp_admin_email="flying@hellfish.media" - --wp_admin_pass=password -f') + --site-user=test + --https-enabled + --db-name=dbname + --db-user=dbuser + --db-pass=password + --wp-title="Site Title" + --wp-admin-user="abe" + --wp-admin-email="flying@hellfish.media" + --wp-admin-pass=password -f') ->assertExitCode(0); }); From 15a4ae908b07c9af7865191cc11c6d7bba5677a9 Mon Sep 17 00:00:00 2001 From: Ashley Rich Date: Tue, 1 Mar 2022 11:28:44 +0000 Subject: [PATCH 35/37] Update create site option descriptions --- app/Commands/Sites/CreateCommand.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index a1f5adc..273dc71 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -20,17 +20,17 @@ class CreateCommand extends BaseCommand {server_id? : Server ID} {--installation-method= : Type of installation (wp or blank)} {--domain= : Domain name} - {--site-user= : name for unique system user who will have ownership permission of all the site files} - {--db-name= : name of a database to be created. Must be unique for the server} - {--db-user= : database level username to use when accessing the database} - {--db-pass= : database level password to use when accessing the database} - {--wp-title= : the title of your WordPress site} - {--wp-admin-user= : for a WordPress site, the admin user\'s username} - {--wp-admin-email= : for a WordPress site, the admin user\'s email} - {--wp-admin-pass= : for a Wordpress site, the admin user\'s password} + {--site-user= : Name for unique system user who will have ownership permission of all the site files} + {--db-name= : Name of a database to be created. Must be unique for the server} + {--db-user= : Database username to use when accessing the database} + {--db-pass= : Database password to use when accessing the database} + {--wp-title= : The title of your WordPress site} + {--wp-admin-user= : For a WordPress site, the admin user\'s username} + {--wp-admin-email= : For a WordPress site, the admin user\'s email} + {--wp-admin-pass= : For a Wordpress site, the admin user\'s password} {--php-version= : PHP version the site will run under} - {--page-cache-enabled : enabling this option will configure Nginx FastCGI caching that is optimized for WordPress} - {--https-enabled : enabling secures your site by serving traffic over HTTPS} + {--page-cache-enabled : Enabling this option will configure page caching that is optimized for WordPress} + {--https-enabled : Enabling secures your site by serving traffic over HTTPS} {--profile=} {--f|force}'; From eac3a0f2c5df4cc1863f111131e899a678413b52 Mon Sep 17 00:00:00 2001 From: Ryan Neudorf Date: Tue, 1 Mar 2022 09:50:41 -0600 Subject: [PATCH 36/37] Updated installation method labels --- app/Commands/Sites/CreateCommand.php | 7 ++++--- app/Helpers/OptionsHelper.php | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 273dc71..91414cd 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -59,13 +59,14 @@ protected function action(): int return self::INVALID; } - $this->userInput['installation-method'] = Choice::make('Installation Method') + $this->userInput['installation-method'] = Choice::make('What files would you like SpinupWP to install?') + ->withFlag('installation-method') ->withChoices(OptionsHelper::INSTALLATION_METHODS) ->nonInteractive($this->nonInteractive()) ->resolveAnswer($this); - if (!in_array($this->userInput['installation-method'], OptionsHelper::INSTALLATION_METHODS, true)) { - $this->error('Invalid site type.'); + if (!array_key_exists($this->userInput['installation-method'], OptionsHelper::INSTALLATION_METHODS)) { + $this->error('Invalid installation method.'); $this->newLine(1); return self::INVALID; } diff --git a/app/Helpers/OptionsHelper.php b/app/Helpers/OptionsHelper.php index e49943f..58eb91b 100644 --- a/app/Helpers/OptionsHelper.php +++ b/app/Helpers/OptionsHelper.php @@ -5,7 +5,10 @@ class OptionsHelper { // SpinupWP CLI only supports a subset of installation methods available via the REST API - public const INSTALLATION_METHODS = ['wp', 'blank']; + public const INSTALLATION_METHODS = [ + 'wp' => 'WordPress', + 'blank' => 'Don\'t Install Any Files', + ]; public const PHP_VERSIONS = ['8.0', '7.4']; } From 91845b28a6fe214e8c8500e97c7f58bf4a88b96f Mon Sep 17 00:00:00 2001 From: Ashley Rich Date: Tue, 1 Mar 2022 16:57:32 +0000 Subject: [PATCH 37/37] Set default installation method --- app/Commands/Sites/CreateCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Commands/Sites/CreateCommand.php b/app/Commands/Sites/CreateCommand.php index 91414cd..3a5c825 100644 --- a/app/Commands/Sites/CreateCommand.php +++ b/app/Commands/Sites/CreateCommand.php @@ -62,6 +62,7 @@ protected function action(): int $this->userInput['installation-method'] = Choice::make('What files would you like SpinupWP to install?') ->withFlag('installation-method') ->withChoices(OptionsHelper::INSTALLATION_METHODS) + ->withDefault(array_key_first(OptionsHelper::INSTALLATION_METHODS)) ->nonInteractive($this->nonInteractive()) ->resolveAnswer($this);