Skip to content

Instantly share code, notes, and snippets.

@edgrosvenor
Created September 28, 2022 09:39
Show Gist options
  • Save edgrosvenor/c0213e2d06ed17f5228921ad25afe335 to your computer and use it in GitHub Desktop.
Save edgrosvenor/c0213e2d06ed17f5228921ad25afe335 to your computer and use it in GitHub Desktop.
The current state of my attempt to fully automate migrations upon deployment with PlanetScale
<?php
namespace App\Console\Commands\CI;
use App\Support\PlanetScale\CategorizeMigrations;
use App\Support\PlanetScale\ConnectToBranch;
use App\Support\PlanetScale\CreateBranch;
use App\Support\PlanetScale\CreateDeployRequest;
use App\Support\PlanetScale\DeleteBranch;
use App\Support\PlanetScale\DeployRequest;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Throwable;
class RunPlanetScaleMigrations extends Command
{
protected $signature = 'migrate:pscale {beforeOrAfter}';
protected $description = 'Run the migrations that should occur at this point in the deploymnent process.';
/**
* @throws Throwable
*/
public function handle(): int
{
if (!in_array($this->argument('beforeOrAfter'), ['before', 'after'])) {
$this->error('Invalid argument. Must be `php artisan migrate:pscale before` or `php artisan migrate:pscale after`');
return Command::INVALID;
}
// Move any migrations out of the migrations folder and into the before or after folder
// depending on what operations they perform.
app(CategorizeMigrations::class)();
if (File::isEmptyDirectory(database_path($this->argument('beforeOrAfter')))) {
$this->info("Nothing to migrate " . $this->argument('beforeOrAfter') . " deployment");
return Command::SUCCESS;
}
$branch = Str::orderedUuid()->toString();
app(CreateBranch::class)($branch);
sleep(config('services.pscale.sleep.create-branch'));
app(ConnectToBranch::class)($branch);
Artisan::call('migrate', [
'--path' => database_path($this->argument('beforeOrAfter')),
'--force' => true,
]);
$requestNumber = app(CreateDeployRequest::class)($branch);
app(DeployRequest::class)($requestNumber);
sleep(config('services.pscale.sleep.deploy-request'));
app(DeleteBranch::class)($branch);
return Command::SUCCESS;
}
}
@edgrosvenor
Copy link
Author

Most of the stuff in the App\Support\PlanetScale\ just wraps the PlanetScale CLI. The only thing I don't love is having to sleep in those few places because I can't find a way for PlanetScale to notify me when a newly created branch is ready to use. I don't think the sleep is required after I merge the deploy request, but I'm still experimenting.

@edgrosvenor
Copy link
Author

edgrosvenor commented Sep 28, 2022

Another thing to note here is that I ignore the contents of the database/before and database/after directories in Git. I'll also delete the contents of those folders in a post-deployment task so they're always empty when a new deployment starts. Another part of the workflow creates a fresh schema dump and prunes the migrations folder so it only ever contains new migrations. Since PlanetScale is now handling version control of my schema, there's really no benefit at all in keeping those around after they're run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment