Skip to content

Commit

Permalink
Release 5.1.0 (#73)
Browse files Browse the repository at this point in the history
* add cli spinner

* Add healthcheck to mysql/mariadb container

* Pass project directory instead of changing the working dir

* Add docker HealthChecker class

* Bind cli spinner in container

* Add ability to skip global containers when using local start

* Wait for db container to be ready before creating wp databases, fix FE building and add a spinner

* Update global start test

* Update local bootstrap test to pass

* Update ProjectBootstrapperTest.php

* Test area missing from code coverage

* Add HealthCheckerTest.php

* Fix docblock

* Add global compose migration

* Fix --only-new error when running command that doesn't exist

* Run update listener check on open command

* Remove test

* Update autocomplete

* Bump to version 5.1.0

* Add multisite bootstrapping support

* Update autocompletion

* Increase HC timeout, add interval, increase retries, clean up file
  • Loading branch information
defunctl authored Jul 28, 2021
1 parent c32633f commit 398ead1
Show file tree
Hide file tree
Showing 22 changed files with 575 additions and 100 deletions.
4 changes: 2 additions & 2 deletions app/Commands/GlobalDocker/Start.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ public function handle( Handler $resolveHandler ): void {
$this->enableDnsResolvers( $resolveHandler );
}

chdir( $this->globalDirectory );

Artisan::call( DockerCompose::class, [
'--project-directory',
$this->globalDirectory,
'--project-name',
self::PROJECT_NAME,
'up',
Expand Down
20 changes: 12 additions & 8 deletions app/Commands/LocalDocker/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Services\ProjectBootstrapper;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Validator;
use App\Commands\GlobalDocker\Start as GlobalStart;

/**
* Class Bootstrap
Expand All @@ -20,7 +21,7 @@ class Bootstrap extends BaseLocalDocker {
*
* @var string
*/
protected $signature = 'bootstrap';
protected $signature = 'bootstrap {--multisite : Bootstrap for a multisite project}';

/**
* The description of the command.
Expand All @@ -39,6 +40,8 @@ class Bootstrap extends BaseLocalDocker {
* @return int
*/
public function handle( Config $config, ProjectBootstrapper $bootstrapper ) {
Artisan::call( GlobalStart::class, [], $this->output );

$this->info( 'Alright, let\'s get ready to configure WordPress!' );

$email = $this->ask( 'Enter your email address' );
Expand Down Expand Up @@ -74,7 +77,7 @@ public function handle( Config $config, ProjectBootstrapper $bootstrapper ) {
$bootstrapper->renameObjectCache( $config->getProjectRoot() );

$this->task( 'Bootstrapping project', call_user_func( [ $this, 'bootstrap' ], $config, $bootstrapper ) );
$this->task( 'Starting docker containers', call_user_func( [ $this, 'startContainers' ] ) );
$this->task( 'Starting local docker containers', call_user_func( [ $this, 'startLocalContainers' ] ) );
$this->task( 'Installing WordPress', call_user_func( [ $this, 'installWordpress' ], $config, $email, $username, $password ) );

$bootstrapper->restoreObjectCache( $config->getProjectRoot() );
Expand All @@ -90,11 +93,10 @@ public function handle( Config $config, ProjectBootstrapper $bootstrapper ) {
}

/**
* Starts all required docker containers.
*
* Starts local project docker containers.
*/
public function startContainers(): void {
Artisan::call( Start::class, [], $this->output );
public function startLocalContainers(): void {
Artisan::call( Start::class, [ '--skip-global' => true ], $this->output );
}

/**
Expand All @@ -108,7 +110,7 @@ public function startContainers(): void {
public function bootstrap( Config $config, ProjectBootstrapper $bootstrapper ): void {
$projectRoot = $config->getProjectRoot();

$bootstrapper->createDatabases( $config->getProjectName() );
$bootstrapper->createDatabases( $config->getProjectName(), $this->output );

$result = $bootstrapper->createLocalConfig( $projectRoot );

Expand All @@ -131,10 +133,12 @@ public function bootstrap( Config $config, ProjectBootstrapper $bootstrapper ):
* @param string $password
*/
public function installWordpress( Config $config, string $email, string $username, string $password ): void {
$command = $this->option( 'multisite' ) ? 'multisite-install' : 'install';

Artisan::call( Wp::class, [
'args' => [
'core',
'install',
$command,
'--url' => $config->getProjectDomain(),
'--title' => 'Square One',
'--admin_email' => $email,
Expand Down
7 changes: 5 additions & 2 deletions app/Commands/LocalDocker/Start.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class Start extends BaseLocalDocker {
*/
protected $signature = 'start {--b|browser : Automatically open the project in your browser}
{--p|path= : Path to a specific local project folder}
{--remove-orphans : Remove containers for services not in the compose file}';
{--remove-orphans : Remove containers for services not in the compose file}
{--skip-global : Skip starting global containers}';

/**
* The description of the command.
Expand Down Expand Up @@ -74,7 +75,9 @@ public function handle( Config $config, Handler $certificateHandler, Filesystem
$this->prepareComposer( $config, $filesystem, $github );

// Start global containers
Artisan::call( GlobalStart::class, [], $this->getOutput() );
if ( ! $this->option( 'skip-global') ) {
Artisan::call( GlobalStart::class, [], $this->getOutput() );
}

$this->checkCertificates( $config, $certificateHandler );

Expand Down
7 changes: 4 additions & 3 deletions app/Listeners/MigrationListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ class MigrationListener {
/**
* UpdateCheck constructor.
*
* @param \App\Services\Migrations\Migrator $migrator
* @param \App\Services\Update\Updater $updater
* @param string $version
* @param Finder $finder
* @param \App\Services\Migrations\Migrator $migrator
* @param \App\Services\Update\Updater $updater
* @param string $version
*/
public function __construct( Finder $finder, Migrator $migrator, Updater $updater, string $version ) {
$this->finder = $finder;
Expand Down
8 changes: 4 additions & 4 deletions app/Listeners/UpdateCheckListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ protected function shouldRun( ?string $command = '' ): bool {
}

if ( empty( $command ) ) {
return false;
return true;
}

if ( 'self' !== substr( $command, 0, 4 ) && 'app' !== substr( $command, 0, 3 ) ) {
return true;
if ( 'list' === $command ) {
return false;
}

return false;
return 'self' !== substr( $command, 0, 4 ) && 'app' !== substr( $command, 0, 3 );
}

/**
Expand Down
4 changes: 4 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace App\Providers;

use AlecRabbit\Snake\Contracts\SpinnerInterface;
use AlecRabbit\Snake\Spinner;
use App\Bootstrap;
use RuntimeException;
use App\Support\Yaml;
Expand Down Expand Up @@ -232,6 +234,8 @@ public function register() {
$this->app->when( Env::class )
->needs( '$directory' )
->give( config( 'squareone.config-dir' ) );

$this->app->bind( SpinnerInterface::class, Spinner::class );
}

/**
Expand Down
44 changes: 44 additions & 0 deletions app/Services/Docker/HealthChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php declare( strict_types=1 );

namespace App\Services\Docker;

use App\Contracts\Runner;
use TitasGailius\Terminal\Response;

/**
* Check the health for docker containers.
*
* @package App\Services\Docker
*/
class HealthChecker {

public const HEALTHY = 'healthy';

/**
* The command runner.
*
* @var \App\Contracts\Runner
*/
protected $runner;

public function __construct( Runner $runner ) {
$this->runner = $runner;
}

/**
* Check if a container running docker's health check has become healthy.
*
* @param string $containerName The container name to check, as shown in "docker ps".
*/
public function healthy( string $containerName ): bool {
$command = 'docker ps --filter {{ $container }} --filter "health=healthy" --format "{{ .Status }}"';

/** @var Response $response */
$response = $this->runner->with( [
'container' => "name=$containerName",
] )->command( $command )->run();

return str_contains( (string) $response, self::HEALTHY );
}

}
69 changes: 53 additions & 16 deletions app/Services/ProjectBootstrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace App\Services;

use AlecRabbit\Snake\Contracts\SpinnerInterface;
use App\Contracts\Runner;
use App\Services\Docker\HealthChecker;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Output\OutputInterface;

Expand Down Expand Up @@ -34,17 +36,33 @@ class ProjectBootstrapper {
*/
protected $runner;

/**
* The console spinner.
*
* @var \AlecRabbit\Snake\Contracts\SpinnerInterface
*/
protected $spinner;

/**
* @var \App\Services\Docker\HealthChecker
*/
protected $healthChecker;

/**
* ProjectCreator constructor.
*
* @param \Illuminate\Filesystem\Filesystem $filesystem
* @param \App\Services\HomeDir $homedir
* @param \App\Contracts\Runner $runner
* @param \Illuminate\Filesystem\Filesystem $filesystem
* @param \App\Services\HomeDir $homedir
* @param \App\Contracts\Runner $runner
* @param SpinnerInterface $spinner
* @param HealthChecker $healthChecker
*/
public function __construct( Filesystem $filesystem, HomeDir $homedir, Runner $runner ) {
$this->filesystem = $filesystem;
$this->homedir = $homedir;
$this->runner = $runner;
public function __construct( Filesystem $filesystem, HomeDir $homedir, Runner $runner, SpinnerInterface $spinner, HealthChecker $healthChecker ) {
$this->filesystem = $filesystem;
$this->homedir = $homedir;
$this->runner = $runner;
$this->spinner = $spinner;
$this->healthChecker = $healthChecker;
}

/**
Expand Down Expand Up @@ -84,11 +102,21 @@ public function restoreObjectCache( string $projectRoot ): self {
/**
* Create WordPress and test databases.
*
* @param string $projectName
* @param string $projectName
* @param OutputInterface $output
*
* @return \App\Services\ProjectBootstrapper
*/
public function createDatabases( string $projectName ): self {
public function createDatabases( string $projectName, OutputInterface $output ): self {
$output->writeln( 'Waiting for database container to become active...' );

while( $this->healthChecker->healthy( 'tribe-mysql' ) !== true ) {
$this->spinner->spin();
usleep( 500000 );
}

$this->spinner->end();

$projectName = str_replace( '-', '_', $projectName );

// Create the WordPress database
Expand All @@ -102,7 +130,7 @@ public function createDatabases( string $projectName ): self {
'docker exec -i tribe-mysql mysql -uroot -ppassword <<< "CREATE DATABASE tribe_%s_tests; CREATE DATABASE tribe_%s_acceptance;"',
$projectName,
$projectName
) );
) )->throw();

return $this;
}
Expand Down Expand Up @@ -182,22 +210,31 @@ public function buildFrontend( string $projectRoot, OutputInterface $output ): s
$output->writeln( 'Building frontend assets, this will take a while...' );

if ( $this->filesystem->exists( $isThemeBuild ) ) {
$this->runner->run( '. ~/.nvm/nvm.sh && nvm install && nvm use && npm install -g gulp-cli && npm run install:theme' )->throw();
$this->runner->run( 'bash -c ". ~/.nvm/nvm.sh; nvm install; nvm use; npm install -g gulp-cli; npm run install:theme"' )->throw();

$this->runner->with( [
'path' => $projectRoot . '/wp-content/themes/core/',
] )->run( '. ~/.nvm/nvm.sh && nvm install && nvm use && npm run --prefix {{ $path }} gulp -- dist' )->throw();
] )->run( 'bash -c ". ~/.nvm/nvm.sh; nvm install; nvm use; npm run --prefix {{ $path }} gulp -- dist"' )->throw();

} else {
$command = '. ~/.nvm/nvm.sh && nvm install && nvm use && yarn install';
$command = 'bash -c ". ~/.nvm/nvm.sh; nvm install; nvm use; npm install -g yarn; yarn install;';

if ( $this->filesystem->exists( $projectRoot . '/gulpfile.js' ) ) {
$command .= ' && npm install -g gulp-cli && gulp dist';
$command .= ' npm install -g gulp-cli; gulp dist';
} elseif ( $this->filesystem->exists( $projectRoot . '/Gruntfile.js' ) ) {
$command .= ' && npm install -g grunt-cli && grunt dist';
$command .= ' npm install -g grunt-cli; grunt dist';
}

$command .= '"';

$response = $this->runner->command( $command )->inBackground()->run();

while ( $response->process()->isRunning() ) {
usleep( 500000 );
$this->spinner->spin();
}

$this->runner->run( $command )->throw();
$this->spinner->end();
}

return $this;
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"php": "^7.3|^8.0",
"ext-json": "*",
"ext-openssl": "*",
"alecrabbit/php-cli-snake": "^0.6.0",
"composer/semver": "^3.0",
"guzzlehttp/guzzle": "^6.5.5|^7.0",
"illuminate/http": "^8.0",
Expand Down
60 changes: 59 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 398ead1

Please sign in to comment.