Skip to content

Commit

Permalink
Update migration logic to use a single file to avoid race conditions (#…
Browse files Browse the repository at this point in the history
…81)

* Update migration logic to use a single file to avoid race conditions

* Delete the old config refresh migration

* Bugfix/5.2.1/phpmyadmin and update note (#82)

* Ensure initial phpmyadmin run is detached

* Let the user know the update check is cached

* Display cache last updated time

* Replace bash only here-string when creating databases (#84)

* Loop bootstrap validation until it passes (#83)

* Loop bootstrap validation until it passes

* Set test class to final
  • Loading branch information
defunctl authored Aug 24, 2021
1 parent b017f68 commit 606545f
Show file tree
Hide file tree
Showing 19 changed files with 314 additions and 267 deletions.
4 changes: 2 additions & 2 deletions app/Commands/GlobalDocker/MyAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function handle( Runner $runner ): void {
$start = $runner->run( 'docker start tribe-phpmyadmin' );

if ( ! $start->ok() ) {
$run = $runner->run( $this->getRunCommand() );
$run = $runner->tty( true )->run( $this->getRunCommand() );

if ( ! $run->ok() ) {
$runner->run( 'docker rm /tribe-phpmyadmin' );
Expand All @@ -61,7 +61,7 @@ public function handle( Runner $runner ): void {
* @return string
*/
protected function getRunCommand(): string {
return 'docker run --name tribe-phpmyadmin --link tribe-mysql:db --network="global_proxy" -p 8080:80 phpmyadmin/phpmyadmin';
return 'docker run -d --name tribe-phpmyadmin --link tribe-mysql:db --network="global_proxy" -p 8080:80 phpmyadmin/phpmyadmin';
}

}
54 changes: 30 additions & 24 deletions app/Commands/LocalDocker/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,34 +44,40 @@ public function handle( Config $config, ProjectBootstrapper $bootstrapper ) {

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

$email = $this->ask( 'Enter your email address' );
$username = $this->ask( 'Enter your admin username' );
$password = $this->secret( 'Enter your password' );
$passwordConfirmation = $this->secret( 'Confirm your password' );

$validator = Validator::make( [
'email' => $email,
'username' => $username,
'password' => $password,
'password_confirmation' => $passwordConfirmation,
], [
'email' => [ 'required', 'email' ],
'username' => [ 'required' ],
'password' => [ 'required', 'same:password_confirmation' ],
'password_confirmation' => [ 'required' ],
], [
'required' => 'The :attribute field is required',
'same' => 'The :attribute and :other must match',
'email' => 'Invalid email address',
] );
while ( true ) {
$email = $this->ask( 'Enter your email address' );
$username = $this->ask( 'Enter your admin username' );
$password = $this->secret( 'Enter your password' );
$passwordConfirmation = $this->secret( 'Confirm your password' );

$validator = Validator::make( [
'email' => $email,
'username' => $username,
'password' => $password,
'password_confirmation' => $passwordConfirmation,
], [
'email' => [ 'required', 'email' ],
'username' => [ 'required' ],
'password' => [ 'required', 'same:password_confirmation' ],
'password_confirmation' => [ 'required' ],
], [
'required' => 'The :attribute field is required',
'same' => 'The :attribute and :other must match',
'email' => 'Invalid email address',
] );

if ( ! $validator->fails() ) {
break;
}

if ( $validator->fails() ) {
$this->error( 'The following errors occurred, please try again: ' );

$count = 1;

foreach ( $validator->errors()->all() as $error ) {
$this->error( $error );
$this->error( sprintf( '%d. %s', $count, $error ) );
$count++;
}

return self::EXIT_ERROR;
}

$bootstrapper->renameObjectCache( $config->getProjectRoot() );
Expand Down
9 changes: 9 additions & 0 deletions app/Commands/Self/UpdateCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Commands\Self;

use App\Services\Config\Github;
use Carbon\Carbon;
use Composer\Semver\Comparator;
use App\Services\Update\Updater;
use LaravelZero\Framework\Commands\Command;
Expand Down Expand Up @@ -101,6 +102,14 @@ public function handle( Updater $updater, Github $github ): void {
sprintf( self::RELEASES_URL, $release->version ),
)
);

if ( ! $this->option( 'force' ) ) {
$this->info( 'Note: this check is cached. Run "so self:update-check --force" to see if a newer version is available' );
$this->info( sprintf(
'Cache last updated: %s',
Carbon::createFromDate( $release->updatedAt() )->diffForHumans()
) );
}
} elseif ( ! $this->option( 'only-new' ) ) {
$this->info( sprintf( "You're running the latest version: %s", $this->version ) );
}
Expand Down
63 changes: 27 additions & 36 deletions app/Listeners/MigrationListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

namespace App\Listeners;

use Filebase\Document;
use Composer\Semver\Comparator;
use App\Services\Update\Updater;
use Symfony\Component\Finder\Finder;
use App\Services\Migrations\MigrationChecker;
use App\Services\Migrations\Migrator;
use App\Services\Update\Updater;
use Illuminate\Console\Events\CommandStarting;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;

/**
* Run migrations, if available.
Expand Down Expand Up @@ -38,6 +37,13 @@ class MigrationListener {
*/
protected $migrator;

/**
* The migration checker.
*
* @var \App\Services\Migrations\MigrationChecker
*/
protected $migrationChecker;

/**
* The running application's version.
*
Expand All @@ -48,25 +54,29 @@ class MigrationListener {
/**
* UpdateCheck constructor.
*
* @param Finder $finder
* @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\Migrations\MigrationChecker $migrationChecker
* @param \App\Services\Update\Updater $updater
* @param string $version
*/
public function __construct( Finder $finder, Migrator $migrator, Updater $updater, string $version ) {
$this->finder = $finder;
$this->migrator = $migrator;
$this->updater = $updater;
$this->version = $version;
public function __construct( Finder $finder, Migrator $migrator, MigrationChecker $migrationChecker, Updater $updater, string $version ) {
$this->finder = $finder;
$this->migrator = $migrator;
$this->migrationChecker = $migrationChecker;
$this->updater = $updater;
$this->version = $version;
}

/**
* Run the update checker.
*
* @param \Illuminate\Console\Events\CommandStarting $event
*
* @return bool
* @throws \Illuminate\Contracts\Container\BindingResolutionException
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*
* @return bool
*/
public function handle( CommandStarting $event ): bool {
if ( $this->shouldRun( $event->command ) ) {
Expand Down Expand Up @@ -97,26 +107,7 @@ protected function shouldRun( ?string $command = '' ): bool {
return false;
}

$release = $this->getRelease();

if ( empty( $release->version ) ) {
return true;
}

if ( Comparator::greaterThan( $this->version, $release->version ) ) {
return true;
}

return false;
}

/**
* Get release data.
*
* @return \Filebase\Document
*/
protected function getRelease(): Document {
return $this->updater->getCachedRelease();
return $this->migrationChecker->shouldMigrate();
}

/**
Expand All @@ -125,14 +116,14 @@ protected function getRelease(): Document {
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function runMigration( OutputInterface $output ): void {
$this->finder->files()->name( '*.php' )->in( storage_path( 'migrations' ) );

if ( iterator_count( $this->finder ) > 0 ) {
if ( $this->finder->count() > 0 ) {
$this->migrator->run( $this->finder, $output );
}

}

}
5 changes: 5 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use App\Services\Docker\Dns\OsSupport\BaseSupport;
use App\Services\Docker\Local\Config;
use App\Services\HomeDir;
use App\Services\Migrations\MigrationChecker;
use App\Services\OperatingSystem;
use App\Services\Update\Updater;
use App\Support\Yaml;
Expand Down Expand Up @@ -234,6 +235,10 @@ public function register(): void {
->give( config( 'squareone.config-dir' ) );

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

$this->app->when( MigrationChecker::class )
->needs( '$configDir' )
->give( config( 'squareone.config-dir' ) );
}

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

namespace App\Services\Migrations;

use Symfony\Component\Filesystem\Filesystem;

/**
* Manages the state of when migrations should run.
*/
class MigrationChecker {

public const MIGRATION_FILE = '.migrated';

/**
* @var \Symfony\Component\Filesystem\Filesystem;
*/
protected $filesystem;

/**
* The full path to the migration file. If this file does not exist,
* we need to run a migration check.
*
* @var string
*/
protected $migrationFile;

/**
* @param string $configDir The path to the SquareOne configuration directory.
*/
public function __construct( Filesystem $filesystem, string $configDir ) {
$this->filesystem = $filesystem;
$this->migrationFile = sprintf( '%s/%s', $configDir, self::MIGRATION_FILE );
}

/**
* Whether a migration should take place.
*
* @return bool
*/
public function shouldMigrate(): bool {
return ! $this->filesystem->exists( $this->migrationFile );
}

/**
* Clear the migration file.
*/
public function clear(): void {
$this->filesystem->remove( $this->migrationFile );
}

/**
* Create the migration file.
*
* @throws \Symfony\Component\Filesystem\Exception\IOException
*/
public function update(): void {
$this->filesystem->touch( $this->migrationFile );
}

}
18 changes: 14 additions & 4 deletions app/Services/Migrations/Migrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,25 @@ class Migrator {
*/
protected $app;

/**
* The migration checker.
*
* @var \App\Services\Migrations\MigrationChecker
*/
protected $migrationChecker;

/**
* Migrator constructor.
*
* @param Database $db The migrations database
* @param \Illuminate\Filesystem\Filesystem $filesystem Illuminate filesystem.
* @param \Illuminate\Contracts\Foundation\Application $app The laravel service container.
*/
public function __construct( Database $db, Filesystem $filesystem, Application $app ) {
$this->db = $db;
$this->filesystem = $filesystem;
$this->app = $app;
public function __construct( Database $db, Filesystem $filesystem, Application $app, MigrationChecker $migrationChecker ) {
$this->db = $db;
$this->filesystem = $filesystem;
$this->app = $app;
$this->migrationChecker = $migrationChecker;
}

/**
Expand Down Expand Up @@ -93,6 +101,8 @@ public function run( Finder $migrations, OutputInterface $output ): Collection {
}
}

$this->migrationChecker->update();

return collect( $results );
}

Expand Down
4 changes: 2 additions & 2 deletions app/Services/ProjectBootstrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ public function createDatabases( string $projectName, OutputInterface $output ):

// Create the WordPress database
$this->runner->run( sprintf(
'docker exec -i tribe-mysql mysql -uroot -ppassword <<< "CREATE DATABASE tribe_%s;"',
'docker exec -i tribe-mysql mysql -uroot -ppassword -e "CREATE DATABASE tribe_%s;"',
$projectName
) );

// Create test databases
$this->runner->run( sprintf(
'docker exec -i tribe-mysql mysql -uroot -ppassword <<< "CREATE DATABASE tribe_%s_tests; CREATE DATABASE tribe_%s_acceptance;"',
'docker exec -i tribe-mysql mysql -uroot -ppassword -e "CREATE DATABASE tribe_%s_tests; CREATE DATABASE tribe_%s_acceptance;"',
$projectName,
$projectName
) )->throw();
Expand Down
Loading

0 comments on commit 606545f

Please sign in to comment.