Skip to content

Commit

Permalink
Merge pull request #125 from HavokInspiration/mark-migrated-all
Browse files Browse the repository at this point in the history
Allow to migrate all migrations with one "mark_migrated" call
  • Loading branch information
lorenzo committed Sep 30, 2015
2 parents eacaa3c + b38c91d commit 6f9f3da
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 3 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ bin/cake migrations status -c my_datasource
# The following will mark targeted migration as marked without actually running it.
# The expected argument is the migration version number
bin/cake migrations mark_migrated 20150417223600

# Since Migrations 1.3.1, a new `all` special value for the version argumentwas added.
# The following will mark all migrations found as migrated.
bin/cake migrations mark_migrated all
```

### Creating Migrations
Expand Down
80 changes: 79 additions & 1 deletion src/Command/MarkMigrated.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,37 @@ class MarkMigrated extends AbstractCommand

use ConfigurationTrait;

/**
* The console output instance
*
* @var \Symfony\Component\Console\Output\OutputInterface
*/
protected $output;

/**
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return mixed
*/
public function output(OutputInterface $output = null)
{
if ($output !== null) {
$this->output = $output;
}
return $this->output;
}

/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('mark_migrated')
->setDescription('Mark a migration as migrated')
->addArgument('version', InputArgument::REQUIRED, 'What is the version of the migration?')
->addArgument(
'version',
InputArgument::REQUIRED,
'What is the version of the migration? Use the special value `all` to mark all migrations as migrated.'
)
->setHelp(sprintf(
'%sMark a migration migrated based on its version number%s',
PHP_EOL,
Expand All @@ -42,6 +65,8 @@ protected function configure()

/**
* Mark a migration migrated
* If the `version` argument has the value `all`, all migrations found will be marked as
* migrated
*
* @param \Symfony\Component\Console\Input\InputInterface $input the input object
* @param \Symfony\Component\Console\Output\OutputInterface $output the output object
Expand All @@ -51,10 +76,16 @@ protected function execute(InputInterface $input, OutputInterface $output)
{
$this->setInput($input);
$this->bootstrap($input, $output);
$this->output($output);

$path = $this->getConfig()->getMigrationPath();
$version = $input->getArgument('version');

if ($version === 'all' || $version === '*') {
$this->markAllMigrated($path);
return;
}

if ($this->getManager()->isMigrated($version)) {
$output->writeln(
sprintf(
Expand All @@ -72,4 +103,51 @@ protected function execute(InputInterface $input, OutputInterface $output)
$output->writeln(sprintf('<error>An error occurred : %s</error>', $e->getMessage()));
}
}

/**
* Mark all migrations found in $path as migrated
*
* It will start a transaction and rollback in case one of the operation raises an exception
*
* @param string $path Path where to look for migrations
* @return void
*/
protected function markAllMigrated($path)
{
$manager = $this->getManager();
$adapter = $manager->getEnvironment('default')->getAdapter();
$migrations = $manager->getMigrations();
$output = $this->output();

if (empty($migrations)) {
$output->writeln('<info>No migrations were found. Nothing to mark as migrated.</info>');
return;
}

$adapter->beginTransaction();
foreach ($migrations as $version => $migration) {
if ($manager->isMigrated($version)) {
$output->writeln(sprintf('<info>Skipping migration `%s` (already migrated).</info>', $version));
} else {
try {
$this->getManager()->markMigrated($version, $path);
$output->writeln(
sprintf('<info>Migration `%s` successfully marked migrated !</info>', $version)
);
} catch (\Exception $e) {
$adapter->rollbackTransaction();
$output->writeln(
sprintf(
'<error>An error occurred while marking migration `%s` as migrated : %s</error>',
$version,
$e->getMessage()
)
);
$output->writeln('<error>All marked migrations during this process were unmarked.</error>');
return;
}
}
}
$adapter->commitTransaction();
}
}
89 changes: 89 additions & 0 deletions tests/TestCase/Command/MarkMigratedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Cake\Datasource\ConnectionManager;
use Cake\TestSuite\TestCase;
use Migrations\MigrationsDispatcher;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Tester\CommandTester;

/**
Expand Down Expand Up @@ -133,4 +134,92 @@ public function testExecute()
$result = $this->Connection->newQuery()->select(['*'])->from('phinxlog')->execute()->count();
$this->assertEquals(1, $result);
}

/**
* Test executing "mark_migration"
*
* @return void
*/
public function testExecuteAll()
{
$this->commandTester->execute([
'command' => $this->command->getName(),
'version' => 'all',
'--connection' => 'test',
'--source' => 'TestsMigrations'
]);

$this->assertContains(
'Migration `20150826191400` successfully marked migrated !',
$this->commandTester->getDisplay()
);
$this->assertContains(
'Migration `20150724233100` successfully marked migrated !',
$this->commandTester->getDisplay()
);
$this->assertContains(
'Migration `20150704160200` successfully marked migrated !',
$this->commandTester->getDisplay()
);

$result = $this->Connection->newQuery()->select(['*'])->from('phinxlog')->execute()->fetchAll('assoc');
$this->assertEquals('20150704160200', $result[0]['version']);
$this->assertEquals('20150724233100', $result[1]['version']);
$this->assertEquals('20150826191400', $result[2]['version']);

$this->commandTester->execute([
'command' => $this->command->getName(),
'version' => 'all',
'--connection' => 'test',
'--source' => 'TestsMigrations'
]);

$this->assertContains(
'Skipping migration `20150704160200` (already migrated).',
$this->commandTester->getDisplay()
);
$this->assertContains(
'Skipping migration `20150724233100` (already migrated).',
$this->commandTester->getDisplay()
);
$this->assertContains(
'Skipping migration `20150826191400` (already migrated).',
$this->commandTester->getDisplay()
);

$config = $this->command->getConfig();
$env = $this->command->getManager()->getEnvironment('default');
$migrations = $this->command->getManager()->getMigrations();

$manager = $this->getMock(
'\Migrations\CakeManager',
['getEnvironment', 'markMigrated'],
[$config, new StreamOutput(fopen('php://memory', 'a', false))]
);

$manager->expects($this->any())
->method('getEnvironment')->will($this->returnValue($env));
$manager->expects($this->any())
->method('getMigrations')->will($this->returnValue($migrations));
$manager
->method('markMigrated')->will($this->throwException(new \Exception('Error during marking process')));

$this->Connection->execute('DELETE FROM phinxlog');

$application = new MigrationsDispatcher('testing');
$buggyCommand = $application->find('mark_migrated');
$buggyCommand->setManager($manager);
$buggyCommandTester = new CommandTester($buggyCommand);
$buggyCommandTester->execute([
'command' => $this->command->getName(),
'version' => 'all',
'--connection' => 'test',
'--source' => 'TestsMigrations'
]);

$this->assertContains(
'An error occurred while marking migration `20150704160200` as migrated : Error during marking process',
$buggyCommandTester->getDisplay()
);
}
}
3 changes: 1 addition & 2 deletions tests/TestCase/MigrationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,7 @@ public function testMigrateErrors()
*/
public function testRollbackErrors()
{
$this->migrations->markMigrated(20150704160200);
$this->migrations->markMigrated(20150724233100);
$this->migrations->markMigrated('all');
$this->migrations->rollback();
}

Expand Down

0 comments on commit 6f9f3da

Please sign in to comment.