Skip to content

Commit

Permalink
Merge pull request #28 from deliciousbrains/26-add-create-site-command
Browse files Browse the repository at this point in the history
CLI can create (blank and wp) sites
  • Loading branch information
A5hleyRich authored Mar 1, 2022
2 parents bfb9d51 + 91845b2 commit 86018fe
Show file tree
Hide file tree
Showing 19 changed files with 603 additions and 14 deletions.
26 changes: 26 additions & 0 deletions app/Commands/BaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
use App\Commands\Concerns\InteractsWithIO;
use App\Repositories\ConfigRepository;
use App\Repositories\SpinupWpRepository;
use DeliciousBrains\SpinupWp\Exceptions\ValidationException;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Support\Str;
use LaravelZero\Framework\Commands\Command;

abstract class BaseCommand extends Command
Expand All @@ -21,6 +23,8 @@ abstract class BaseCommand extends Command

protected string $command;

protected array $validationLabels = [];

public function __construct(ConfigRepository $configuration, SpinupWpRepository $spinupWp)
{
parent::__construct();
Expand Down Expand Up @@ -55,6 +59,19 @@ public function handle(): int
}

return $this->action();
} catch (ValidationException $e) {
$errorRows = [];
foreach ($e->errors()['errors'] as $field => $errors) {
$errorRows[] = [$this->applyValidationLabel($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;
Expand All @@ -81,5 +98,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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

use Illuminate\Support\Collection;

trait SelectsServer
trait HasServerIdParameter
{
public function selectServer(string $action): Collection
{
$serverId = $this->argument('server_id');

if (empty($serverId)) {
if (empty($serverId) && !$this->nonInteractive()) {
$serverId = $this->askToSelectServer("Which server would you like to $action");
}

Expand Down
5 changes: 5 additions & 0 deletions app/Commands/Concerns/InteractsWithIO.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,9 @@ public function queueResources(Collection $resources, string $endpoint, string $
ucfirst($resourceName),
], $events);
}

protected function nonInteractive(): bool
{
return (bool) $this->option('force');
}
}
4 changes: 2 additions & 2 deletions app/Commands/Servers/DeleteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
4 changes: 2 additions & 2 deletions app/Commands/Servers/RebootCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
4 changes: 2 additions & 2 deletions app/Commands/Servers/SshCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
4 changes: 2 additions & 2 deletions app/Commands/Services/MysqlCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
4 changes: 2 additions & 2 deletions app/Commands/Services/NginxCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
4 changes: 2 additions & 2 deletions app/Commands/Services/PhpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
188 changes: 188 additions & 0 deletions app/Commands/Sites/CreateCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
<?php

namespace App\Commands\Sites;

use App\Commands\BaseCommand;
use App\Commands\Concerns\HasServerIdParameter;
use App\Helpers\OptionsHelper;
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 HasQuestions;
use HasServerIdParameter;

protected $signature = 'sites:create
{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 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 page caching that is optimized for WordPress}
{--https-enabled : Enabling secures your site by serving traffic over HTTPS}
{--profile=}
{--f|force}';

protected $description = 'Create a site';

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
{
$server = $this->selectServer('deploy to')->first();

if (is_null($server)) {
return self::INVALID;
}

$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);

if (!array_key_exists($this->userInput['installation-method'], OptionsHelper::INSTALLATION_METHODS)) {
$this->error('Invalid installation method.');
$this->newLine(1);
return self::INVALID;
}

$this->userInput['domain'] = Ask::make('Primary Domain')
->withFlag('domain')
->nonInteractive($this->nonInteractive())
->resolveAnswer($this);

$this->userInput += $this->askQuestions($this->nonInteractive());

$this->userInput = array_merge($this->arguments(), $this->options(), $this->userInput);

$site = $this->spinupwp->createSite($server->id, $this->userInput);

$this->displaySuccess($site->eventId());

return self::SUCCESS;
}

public function getDomainSlug(): string
{
return str_replace('.', '', $this->userInput['domain']);
}

public function questions(): array
{
$commonStart = [
Confirm::make('Enable HTTPS')
->withFlag('https-enabled')
->withDefault((bool) !$this->nonInteractive()),

Ask::make('Site User')
->withDefault($this->getDomainSlug()),
];

$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)),
];

$wp = [
Ask::make('WordPress Title')
->withFlag('wp-title'),

Ask::make('WordPress Admin Email')
->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('Enable Page Cache')
->withFlag('page-cache-enabled')
->withDefault((bool) !$this->nonInteractive()),
];

switch ($this->userInput['installation-method']) {
case 'blank':
return array_merge($commonStart, $commonEnd);
default:
return array_merge(
$commonStart,
$db,
$wp,
$commonEnd
);
}
}

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]);
}
}
14 changes: 14 additions & 0 deletions app/Helpers/OptionsHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace App\Helpers;

class OptionsHelper
{
// SpinupWP CLI only supports a subset of installation methods available via the REST API
public const INSTALLATION_METHODS = [
'wp' => 'WordPress',
'blank' => 'Don\'t Install Any Files',
];

public const PHP_VERSIONS = ['8.0', '7.4'];
}
11 changes: 11 additions & 0 deletions app/Questions/Ask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Questions;

class Ask extends Question
{
protected function question()
{
return $this->command->ask($this->prompt, $this->default);
}
}
Loading

0 comments on commit 86018fe

Please sign in to comment.