diff --git a/README.md b/README.md
index bd6e266d..85a80f7d 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/src/Command/MarkMigrated.php b/src/Command/MarkMigrated.php
index 81932144..99194067 100644
--- a/src/Command/MarkMigrated.php
+++ b/src/Command/MarkMigrated.php
@@ -22,6 +22,25 @@ 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}
*/
@@ -29,7 +48,11 @@ 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,
@@ -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
@@ -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(
@@ -72,4 +103,51 @@ protected function execute(InputInterface $input, OutputInterface $output)
$output->writeln(sprintf('An error occurred : %s', $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('No migrations were found. Nothing to mark as migrated.');
+ return;
+ }
+
+ $adapter->beginTransaction();
+ foreach ($migrations as $version => $migration) {
+ if ($manager->isMigrated($version)) {
+ $output->writeln(sprintf('Skipping migration `%s` (already migrated).', $version));
+ } else {
+ try {
+ $this->getManager()->markMigrated($version, $path);
+ $output->writeln(
+ sprintf('Migration `%s` successfully marked migrated !', $version)
+ );
+ } catch (\Exception $e) {
+ $adapter->rollbackTransaction();
+ $output->writeln(
+ sprintf(
+ 'An error occurred while marking migration `%s` as migrated : %s',
+ $version,
+ $e->getMessage()
+ )
+ );
+ $output->writeln('All marked migrations during this process were unmarked.');
+ return;
+ }
+ }
+ }
+ $adapter->commitTransaction();
+ }
}
diff --git a/tests/TestCase/Command/MarkMigratedTest.php b/tests/TestCase/Command/MarkMigratedTest.php
index 24f9de8c..ad6531de 100644
--- a/tests/TestCase/Command/MarkMigratedTest.php
+++ b/tests/TestCase/Command/MarkMigratedTest.php
@@ -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;
/**
@@ -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()
+ );
+ }
}
diff --git a/tests/TestCase/MigrationsTest.php b/tests/TestCase/MigrationsTest.php
index 51d31fd7..e014c139 100644
--- a/tests/TestCase/MigrationsTest.php
+++ b/tests/TestCase/MigrationsTest.php
@@ -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();
}