Skip to content

Commit

Permalink
Show count of applied migrations (#217)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov committed Oct 18, 2023
1 parent 176070a commit 44f9ac4
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 40 deletions.
24 changes: 16 additions & 8 deletions src/Command/DownCommand.php
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
use Yiisoft\Db\Migration\Migrator;
use Yiisoft\Db\Migration\Runner\DownRunner;
Expand Down Expand Up @@ -90,8 +91,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
"<fg=yellow>Total $n $migrationWord to be reverted:</>\n"
);

foreach ($migrations as $migration) {
$output->writeln("\t<fg=yellow>$migration</>");
foreach ($migrations as $i => $migration) {
$output->writeln("\t<fg=yellow>" . ($i + 1) . ". $migration</>");
}

/** @var QuestionHelper $helper */
Expand All @@ -103,15 +104,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int
);

if ($helper->ask($input, $output, $question)) {
/** @psalm-var class-string[] $migrations */
$instances = $this->migrationService->makeRevertibleMigrations($migrations);
foreach ($instances as $instance) {
$this->downRunner->run($instance);
$migrationWas = ($n === 1 ? 'migration was' : 'migrations were');

foreach ($instances as $i => $instance) {
try {
$this->downRunner->run($instance);
} catch (Throwable $e) {
$output->writeln("\n\n\t<error>>>> [ERROR] - Not reverted " . $instance::class . '</error>');
$output->writeln("\n<fg=yellow> >>> Total $i out of $n $migrationWas reverted.</>\n");
$io->error($i > 0 ? 'Partially reverted.' : 'Not reverted.');

throw $e;
}
}

$output->writeln(
"\n<fg=green> >>> [OK] $n " . ($n === 1 ? 'migration was' : 'migrations were') . " reverted.\n"
);
$output->writeln("\n<fg=green> >>> [OK] $n $migrationWas reverted.\n");
$io->success('Migrated down successfully.');
}

Expand Down
5 changes: 2 additions & 3 deletions src/Command/NewCommand.php
Expand Up @@ -79,7 +79,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::INVALID;
}

/** @psalm-var class-string[] $migrations */
$migrations = $this->migrationService->getNewMigrations();

if (empty($migrations)) {
Expand All @@ -100,8 +99,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io->section("Found $n new $migrationWord:");
}

foreach ($migrations as $migration) {
$output->writeln("<info>\t{$migration}</info>");
foreach ($migrations as $i => $migration) {
$output->writeln("<info>\t" . ($i + 1) . ". $migration</info>");
}

$this->migrationService->databaseConnection();
Expand Down
43 changes: 31 additions & 12 deletions src/Command/RedoCommand.php
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
use Yiisoft\Db\Migration\Migrator;
use Yiisoft\Db\Migration\Runner\DownRunner;
Expand Down Expand Up @@ -89,32 +90,50 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$migrations = array_keys($migrations);

$n = count($migrations);
$output->writeln("<warning>Total $n " . ($n === 1 ? 'migration' : 'migrations') . " to be redone:</warning>\n");
$migrationWord = $n === 1 ? 'migration' : 'migrations';

foreach ($migrations as $migration) {
$output->writeln("\t<info>$migration</info>");
$output->writeln("<warning>Total $n $migrationWord to be redone:</warning>\n");

foreach ($migrations as $i => $migration) {
$output->writeln("\t<info>" . ($i + 1) . ". $migration</info>");
}

/** @var QuestionHelper $helper */
$helper = $this->getHelper('question');
$question = new ConfirmationQuestion(
"\n<fg=cyan>Redo the above " . ($n === 1 ? 'migration y/n: ' : 'migrations y/n: '),
"\n<fg=cyan>Redo the above $migrationWord y/n: ",
true
);

if ($helper->ask($input, $output, $question)) {
/** @psalm-var class-string[] $migrations */
$instances = $this->migrationService->makeRevertibleMigrations($migrations);
foreach ($instances as $instance) {
$this->downRunner->run($instance);
$migrationWas = ($n === 1 ? 'migration was' : 'migrations were');

foreach ($instances as $i => $instance) {
try {
$this->downRunner->run($instance);
} catch (Throwable $e) {
$output->writeln("\n\n\t<error>>>> [ERROR] - Not reverted " . $instance::class . '</error>');
$output->writeln("\n<fg=yellow> >>> Total $i out of $n $migrationWas reverted.</>\n");
$io->error($i > 0 ? 'Partially reverted.' : 'Not reverted.');

throw $e;
}
}
foreach (array_reverse($instances) as $instance) {
$this->updateRunner->run($instance);

foreach (array_reverse($instances) as $i => $instance) {
try {
$this->updateRunner->run($instance);
} catch (Throwable $e) {
$output->writeln("\n\n\t<error>>>> [ERROR] - Not applied " . $instance::class . '</error>');
$output->writeln("\n<fg=yellow> >>> Total $i out of $n $migrationWas applied.</>\n");
$io->error($i > 0 ? 'Reverted but partially applied.' : 'Reverted but not applied.');

throw $e;
}
}

$output->writeln(
"\n<info> >>> $n " . ($n === 1 ? 'migration was' : 'migrations were') . " redone.</info>\n"
);
$output->writeln("\n<info> >>> $n $migrationWas redone.</info>\n");
$io->success('Migration redone successfully.');
}

Expand Down
26 changes: 17 additions & 9 deletions src/Command/UpdateCommand.php
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
use Yiisoft\Db\Migration\Migrator;
use Yiisoft\Db\Migration\Runner\UpdateRunner;
Expand Down Expand Up @@ -92,7 +93,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
}

/** @psalm-var class-string[] $migrations */
$migrations = $this->migrationService->getNewMigrations();

if (empty($migrations)) {
Expand All @@ -114,7 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$output->writeln("<fg=yellow>Total $n new $migrationWord to be applied:</>\n");
}

foreach ($migrations as $migration) {
foreach ($migrations as $i => $migration) {
$nameLimit = $this->migrator->getMigrationNameLimit();

if (strlen($migration) > $nameLimit) {
Expand All @@ -126,26 +126,34 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::INVALID;
}

$output->writeln("\t<fg=yellow>$migration</>");
$output->writeln("\t<fg=yellow>" . ($i + 1) . ". $migration</>");
}

/** @var QuestionHelper $helper */
$helper = $this->getHelper('question');

$question = new ConfirmationQuestion(
"\n<fg=cyan>Apply the above " . ($n === 1 ? 'migration y/n: ' : 'migrations y/n: '),
"\n<fg=cyan>Apply the above $migrationWord y/n: ",
true
);

if ($helper->ask($input, $output, $question)) {
$instances = $this->migrationService->makeMigrations($migrations);
foreach ($instances as $instance) {
$this->updateRunner->run($instance);
$migrationWas = ($n === 1 ? 'migration was' : 'migrations were');

foreach ($instances as $i => $instance) {
try {
$this->updateRunner->run($instance);
} catch (Throwable $e) {
$output->writeln("\n\n\t<error>>>> [ERROR] - Not applied " . $instance::class . '</error>');

Check warning on line 148 in src/Command/UpdateCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8-ubuntu-latest

Escaped Mutant for Mutator "ConcatOperandRemoval": --- Original +++ New @@ @@ try { $this->updateRunner->run($instance); } catch (Throwable $e) { - $output->writeln("\n\n\t<error>>>> [ERROR] - Not applied " . $instance::class . '</error>'); + $output->writeln("\n\n\t<error>>>> [ERROR] - Not applied " . $instance::class); $output->writeln("\n<fg=yellow> >>> Total {$i} out of {$n} new {$migrationWas} applied.</>\n"); $io->error($i > 0 ? 'Partially updated.' : 'Not updated.'); throw $e;
$output->writeln("\n<fg=yellow> >>> Total $i out of $n new $migrationWas applied.</>\n");
$io->error($i > 0 ? 'Partially updated.' : 'Not updated.');

throw $e;
}
}

$output->writeln(
"\n<fg=green> >>> $n " . ($n === 1 ? 'Migration was' : 'Migrations were') . " applied.</>\n"
);
$output->writeln("\n<fg=green> >>> Total $n new $migrationWas applied.</>\n");
$io->success('Updated successfully.');
}

Expand Down
4 changes: 2 additions & 2 deletions src/Migrator.php
Expand Up @@ -78,7 +78,7 @@ public function getMigrationNameLimit(): ?int
return $this->migrationNameLimit = $limit;
}

/** @psalm-return array<string, int|string> */
/** @psalm-return array<class-string, int|string> */
public function getHistory(?int $limit = null): array
{
$this->checkMigrationHistoryTable();
Expand All @@ -93,7 +93,7 @@ public function getHistory(?int $limit = null): array
$query->limit($limit);
}

/** @psalm-var array<string, int|string> */
/** @psalm-var array<class-string, int|string> */
return $query->column();
}

Expand Down
3 changes: 3 additions & 0 deletions src/Service/MigrationService.php
Expand Up @@ -106,6 +106,8 @@ public function before(string $defaultName): int
* Returns the migrations that are not applied.
*
* @return array List of new migrations.
*
* @psalm-return array<int, class-string>
*/
public function getNewMigrations(): array
{
Expand Down Expand Up @@ -158,6 +160,7 @@ public function getNewMigrations(): array
}
ksort($migrations);

/** @psalm-var array<int, class-string> */
return array_values($migrations);
}

Expand Down
64 changes: 64 additions & 0 deletions tests/Common/Command/AbstractDownCommandTest.php
Expand Up @@ -10,6 +10,7 @@
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
use Throwable;
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Migration\Command\DownCommand;
use Yiisoft\Db\Migration\Migrator;
Expand Down Expand Up @@ -273,6 +274,69 @@ public function testIncorrectLimit(int $limit): void
$this->assertStringContainsString('The limit option must be greater than 0.', $output);
}

public function testPartiallyReverted(): void
{
MigrationHelper::useMigrationsNamespace($this->container);
MigrationHelper::createAndApplyMigration(
$this->container,
'Create_Book',
'table',
'book',
['title:string(100)', 'author:string(80)'],
);
MigrationHelper::createAndApplyMigration(
$this->container,
'Create_Chapter',
'table',
'chapter',
['name:string(100)'],
);

$db = $this->container->get(ConnectionInterface::class);
$db->createCommand()->dropTable('book')->execute();

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

try {
$exitCode = $command->setInputs(['yes'])->execute(['-l' => 2]);
} catch (Throwable) {
}

$output = $command->getDisplay(true);

$this->assertFalse(isset($exitCode));
$this->assertStringContainsString('>>> Total 1 out of 2 migrations were reverted.', $output);
$this->assertStringContainsString('[ERROR] Partially reverted.', $output);
}

public function testNotReverted(): void
{
MigrationHelper::useMigrationsNamespace($this->container);
MigrationHelper::createAndApplyMigration(
$this->container,
'Create_Book',
'table',
'book',
['title:string(100)', 'author:string(80)'],
);

$db = $this->container->get(ConnectionInterface::class);
$db->createCommand()->dropTable('book')->execute();

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

try {
$exitCode = $command->setInputs(['yes'])->execute([]);
} catch (Throwable) {
}

$output = $command->getDisplay(true);

$this->assertFalse(isset($exitCode));
$this->assertStringContainsString('>>> Total 0 out of 1 migration was reverted.', $output);
$this->assertStringContainsString('[ERROR] Not reverted.', $output);
}

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

0 comments on commit 44f9ac4

Please sign in to comment.