Skip to content

Commit

Permalink
Support --path and --namespace options for migrate:redo command (
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov committed Nov 21, 2023
1 parent 1ceda56 commit e8ad9e3
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 10 deletions.
45 changes: 35 additions & 10 deletions src/Command/RedoCommand.php
Expand Up @@ -30,9 +30,11 @@
* For example:
*
* ```shell
* ./yii migrate:redo # redo the last applied migration
* ./yii migrate:redo --limit=3 # redo last 3 applied migrations
* ./yii migrate:redo --all # redo all migrations
* ./yii migrate:redo # redo the last applied migration
* ./yii migrate:redo --limit=3 # redo last 3 applied migrations
* ./yii migrate:redo --all # redo all migrations
* ./yii migrate:redo --path=@vendor/yiisoft/rbac-db/migrations # redo the last migration from the directory
* ./yii migrate:redo --namespace=Yiisoft\\Rbac\\Db\\Migrations # redo the last migration from the namespace
* ```
*/
#[AsCommand('migrate:redo', 'Redoes the last few migrations.')]
Expand All @@ -51,7 +53,9 @@ protected function configure(): void
{
$this
->addOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Number of migrations to redo.', 1)
->addOption('all', 'a', InputOption::VALUE_NONE, 'All migrations.');
->addOption('all', 'a', InputOption::VALUE_NONE, 'Redo all migrations.')
->addOption('path', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Path to migrations to redo.')
->addOption('namespace', 'ns', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Namespace of migrations to redo.');
}

protected function execute(InputInterface $input, OutputInterface $output): int
Expand All @@ -75,15 +79,36 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::INVALID;
}

$migrations = $this->migrator->getHistory($limit);
/** @psalm-var string[] $paths */
$paths = $input->getOption('path');
/** @psalm-var string[] $namespaces */
$namespaces = $input->getOption('namespace');

if (empty($migrations)) {
$io->warning('No migration has been done before.');
if (!empty($paths) || !empty($namespaces)) {
$migrations = $this->migrator->getHistory();
$migrations = array_keys($migrations);
$migrations = $this->migrationService->filterMigrations($migrations, $namespaces, $paths);

return Command::FAILURE;
}
if (empty($migrations)) {
$io->warning('No applied migrations found.');

return Command::FAILURE;
}

if ($limit !== null) {
$migrations = array_slice($migrations, 0, $limit);
}
} else {
$migrations = $this->migrator->getHistory($limit);

$migrations = array_keys($migrations);
if (empty($migrations)) {
$io->warning('No migration has been done before.');

return Command::FAILURE;
}

$migrations = array_keys($migrations);
}

$n = count($migrations);
$migrationWord = $n === 1 ? 'migration' : 'migrations';
Expand Down
138 changes: 138 additions & 0 deletions tests/Common/Command/AbstractRedoCommandTest.php
Expand Up @@ -17,7 +17,10 @@
use Yiisoft\Db\Migration\Tests\Support\Helper\CommandHelper;
use Yiisoft\Db\Migration\Tests\Support\Helper\DbHelper;
use Yiisoft\Db\Migration\Tests\Support\Helper\MigrationHelper;
use Yiisoft\Db\Migration\Tests\Support\Migrations\M231015155500ExecuteSql;
use Yiisoft\Db\Migration\Tests\Support\Migrations\M231017150317EmptyDown;
use Yiisoft\Db\Migration\Tests\Support\MigrationsExtra\M231108183919Empty;
use Yiisoft\Db\Migration\Tests\Support\MigrationsExtra\M231108183919Empty2;
use Yiisoft\Db\Migration\Tests\Support\Stub\StubMigration;

abstract class AbstractRedoCommandTest extends TestCase
Expand Down Expand Up @@ -326,6 +329,141 @@ public function testRevertedButNotApplied(): void
DbHelper::dropTable($db, 'chapter');
}

public function testOptionsNamespaceAndPath(): void
{
MigrationHelper::useMigrationsPath($this->container);

$migrator = $this->container->get(Migrator::class);
$migrator->up(new M231015155500ExecuteSql());
$migrator->up(new M231108183919Empty());

MigrationHelper::useMigrationsNamespace($this->container);
MigrationHelper::createAndApplyMigration(
$this->container,
'Create_User',
'table',
'user',
['name:string(50)'],
);

$command = $this->createCommand($this->container);
$options = [
'--namespace' => ['Yiisoft\Db\Migration\Tests\Support\Migrations'],
'-ns' => ['Yiisoft\Db\Migration\Tests\Support\Migrations'],
'--path' => [dirname(__DIR__, 2) . '/Support/Migrations'],
];

foreach ($options as $option => $value) {
$exitCode = $command->setInputs(['no'])->execute([$option => $value, '-a' => true]);
$output = $command->getDisplay(true);

$this->assertSame(Command::SUCCESS, $exitCode);
$this->assertStringContainsString('Total 1 migration to be redone:', $output);
$this->assertStringContainsString('1. ' . M231015155500ExecuteSql::class, $output);
}
}

/**
* No migrations by the passed namespace and path.
*/
public function testOptionsNamespaceAndPathWithoutMigrations(): void
{
MigrationHelper::useMigrationsNamespace($this->container);

MigrationHelper::createAndApplyMigration(
$this->container,
'Create_User',
'table',
'user',
['name:string(50)'],
);

$command = $this->createCommand($this->container);
$options = [
'--namespace' => ['Yiisoft\Db\Migration\Tests\Support\Migrations'],
'-ns' => ['Yiisoft\Db\Migration\Tests\Support\Migrations'],
'--path' => [dirname(__DIR__, 2) . '/Support/Migrations'],
];

foreach ($options as $option => $value) {
$exitCode = $command->execute([$option => $value]);
$output = $command->getDisplay(true);

$this->assertSame(Command::FAILURE, $exitCode);
$this->assertStringContainsString('[WARNING] No applied migrations found.', $output);
}
}

/**
* Namespace `Yiisoft\Db\Migration\Tests\Support\MigrationsExtra` matches to two paths,
* all migrations by the passed namespace should be redone.
*/
public function testOptionsNamespaceWithDifferentPaths(): void
{
MigrationHelper::useMigrationsPath($this->container);

$migrator = $this->container->get(Migrator::class);
$migrator->up(new M231108183919Empty());
$migrator->up(new M231108183919Empty2());

MigrationHelper::useMigrationsNamespace($this->container);
MigrationHelper::createAndApplyMigration(
$this->container,
'Create_User',
'table',
'user',
['name:string(50)'],
);

$command = $this->createCommand($this->container);
$options = [
'--namespace' => ['Yiisoft\Db\Migration\Tests\Support\MigrationsExtra'],
'-ns' => ['Yiisoft\Db\Migration\Tests\Support\MigrationsExtra'],
];

foreach ($options as $option => $value) {
$exitCode = $command->setInputs(['no'])->execute([$option => $value, '-a' => true]);
$output = $command->getDisplay(true);

$this->assertSame(Command::SUCCESS, $exitCode);
$this->assertStringContainsString('Total 2 migrations to be redone:', $output);
$this->assertStringContainsString('1. ' . M231108183919Empty2::class, $output);
$this->assertStringContainsString('2. ' . M231108183919Empty::class, $output);
}
}

/**
* Namespace `Yiisoft\Db\Migration\Tests\Support\MigrationsExtra` matches to two paths,
* but only migrations by the specified path should be redone.
*/
public function testOptionsPathForNamespaceWithDifferentPaths(): void
{
MigrationHelper::useMigrationsPath($this->container);

$migrator = $this->container->get(Migrator::class);
$migrator->up(new M231108183919Empty());
$migrator->up(new M231108183919Empty2());

MigrationHelper::useMigrationsNamespace($this->container);
MigrationHelper::createAndApplyMigration(
$this->container,
'Create_User',
'table',
'user',
['name:string(50)'],
);

$command = $this->createCommand($this->container);

$path = dirname(__DIR__, 2) . '/Support/MigrationsExtra';
$exitCode = $command->setInputs(['no'])->execute(['--path' => [$path], '-a' => true]);
$output = $command->getDisplay(true);

$this->assertSame(Command::SUCCESS, $exitCode);
$this->assertStringContainsString('Total 1 migration to be redone:', $output);
$this->assertStringContainsString('1. ' . M231108183919Empty::class, $output);
}

public function createCommand(ContainerInterface $container): CommandTester
{
return CommandHelper::getCommandTester($container, RedoCommand::class);
Expand Down

0 comments on commit e8ad9e3

Please sign in to comment.