Skip to content

Instantly share code, notes, and snippets.

@nenadalm
Last active August 17, 2018 06:35
Show Gist options
  • Save nenadalm/9102892 to your computer and use it in GitHub Desktop.
Save nenadalm/9102892 to your computer and use it in GitHub Desktop.
#!/usr/bin/env php
<?php
define('MIGRATIONS_DIR', 'app/DoctrineMigrations');
list(, $previousHead, $currentHead) = $argv;
$excessMigrations = getExcessMigrations($previousHead, $currentHead);
rsort($excessMigrations);
removeExcessMigrations($excessMigrations, $previousHead);
addMissingMigrations();
function addMissingMigrations()
{
passthru('php app/console --ansi doctrine:migrations:migrate --no-interaction');
}
function removeExcessMigrations(array $excessMigrations, $previousHead)
{
foreach ($excessMigrations as $missingMigration) {
$migrationFilePath = filePathOfMigration($missingMigration);
passthru(sprintf('git checkout %s %s', $previousHead, $migrationFilePath));
passthru(sprintf('git reset HEAD %s', $migrationFilePath));
$output = runProccess(sprintf('php app/console --ansi doctrine:migrations:execute %s --down --no-interaction', $missingMigration));
echo $output->getStdout(), $output->getStderr();
unlink($migrationFilePath);
if (strlen($output->getStderr())) {
exit(1);
}
}
}
function getExcessMigrations($previousHead, $currentHead)
{
exec(sprintf('git diff --name-status %s %s %s', $previousHead, $currentHead, MIGRATIONS_DIR), $output);
$missingMigrationStatusFiles = array_filter($output, function($statusFile) {
return strpos($statusFile, 'D') === 0;
});
$excessMigrations = array_map(function($statusFile) {
$matches = [];
preg_match('/Version([0-9]+)\.php$/', $statusFile, $matches);
return $matches[1];
}, $missingMigrationStatusFiles);
return $excessMigrations;
}
function filePathOfMigration($version)
{
return sprintf('%s/Version%s.php', MIGRATIONS_DIR, $version);
}
function runProccess($cmd)
{
$proc = proc_open($cmd, [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
], $pipes);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
array_map('fclose', $pipes);
proc_close($proc);
return new ProcOutput($stdout, $stderr);
}
class ProcOutput
{
private $stdout;
private $stderr;
public function __construct($stdout = '', $stderr = '')
{
$this->stdout = $stdout;
$this->stderr = $stderr;
}
public function getStdout()
{
return $this->stdout;
}
public function getStderr()
{
return $this->stderr;
}
}
@YKWeyer
Copy link

YKWeyer commented May 22, 2017

Great script!

You also have the possibility to use git show to get migrations to revert line #20:

passthru(sprintf('git show %1$s:%2$s > %2$s', $previousHead, $migrationFilePath));

instead of

passthru(sprintf('git checkout %s %s', $previousHead, $migrationFilePath));
passthru(sprintf('git reset HEAD %s', $migrationFilePath));

@nenadalm
Copy link
Author

nenadalm commented Jun 3, 2017

Thanks. I am thinking about removing this gist though - as I didn't use it for several years (the project it was useful on is no longer under development and projects I am currently working on don't require such script).

The script was written because an app I was working on was hard and time consuming to reinstall (old migrations were broken, they took very long time to run...) and I had to switch between several development branches each with different migrations (migrations were often renamed when branch was merged into another branch - so that newly merged migrations were after all previously run migrations of the other branch).

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