Skip to content

Commit 44f9ac4

Browse files
authored
Show count of applied migrations (#217)
1 parent 176070a commit 44f9ac4

File tree

10 files changed

+359
-40
lines changed

10 files changed

+359
-40
lines changed

src/Command/DownCommand.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Symfony\Component\Console\Output\OutputInterface;
1313
use Symfony\Component\Console\Question\ConfirmationQuestion;
1414
use Symfony\Component\Console\Style\SymfonyStyle;
15+
use Throwable;
1516
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
1617
use Yiisoft\Db\Migration\Migrator;
1718
use Yiisoft\Db\Migration\Runner\DownRunner;
@@ -90,8 +91,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
9091
"<fg=yellow>Total $n $migrationWord to be reverted:</>\n"
9192
);
9293

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

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

105106
if ($helper->ask($input, $output, $question)) {
106-
/** @psalm-var class-string[] $migrations */
107107
$instances = $this->migrationService->makeRevertibleMigrations($migrations);
108-
foreach ($instances as $instance) {
109-
$this->downRunner->run($instance);
108+
$migrationWas = ($n === 1 ? 'migration was' : 'migrations were');
109+
110+
foreach ($instances as $i => $instance) {
111+
try {
112+
$this->downRunner->run($instance);
113+
} catch (Throwable $e) {
114+
$output->writeln("\n\n\t<error>>>> [ERROR] - Not reverted " . $instance::class . '</error>');
115+
$output->writeln("\n<fg=yellow> >>> Total $i out of $n $migrationWas reverted.</>\n");
116+
$io->error($i > 0 ? 'Partially reverted.' : 'Not reverted.');
117+
118+
throw $e;
119+
}
110120
}
111121

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

src/Command/NewCommand.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7979
return Command::INVALID;
8080
}
8181

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

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

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

107106
$this->migrationService->databaseConnection();

src/Command/RedoCommand.php

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Symfony\Component\Console\Output\OutputInterface;
1313
use Symfony\Component\Console\Question\ConfirmationQuestion;
1414
use Symfony\Component\Console\Style\SymfonyStyle;
15+
use Throwable;
1516
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
1617
use Yiisoft\Db\Migration\Migrator;
1718
use Yiisoft\Db\Migration\Runner\DownRunner;
@@ -89,32 +90,50 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8990
$migrations = array_keys($migrations);
9091

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

94-
foreach ($migrations as $migration) {
95-
$output->writeln("\t<info>$migration</info>");
95+
$output->writeln("<warning>Total $n $migrationWord to be redone:</warning>\n");
96+
97+
foreach ($migrations as $i => $migration) {
98+
$output->writeln("\t<info>" . ($i + 1) . ". $migration</info>");
9699
}
97100

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

105108
if ($helper->ask($input, $output, $question)) {
106-
/** @psalm-var class-string[] $migrations */
107109
$instances = $this->migrationService->makeRevertibleMigrations($migrations);
108-
foreach ($instances as $instance) {
109-
$this->downRunner->run($instance);
110+
$migrationWas = ($n === 1 ? 'migration was' : 'migrations were');
111+
112+
foreach ($instances as $i => $instance) {
113+
try {
114+
$this->downRunner->run($instance);
115+
} catch (Throwable $e) {
116+
$output->writeln("\n\n\t<error>>>> [ERROR] - Not reverted " . $instance::class . '</error>');
117+
$output->writeln("\n<fg=yellow> >>> Total $i out of $n $migrationWas reverted.</>\n");
118+
$io->error($i > 0 ? 'Partially reverted.' : 'Not reverted.');
119+
120+
throw $e;
121+
}
110122
}
111-
foreach (array_reverse($instances) as $instance) {
112-
$this->updateRunner->run($instance);
123+
124+
foreach (array_reverse($instances) as $i => $instance) {
125+
try {
126+
$this->updateRunner->run($instance);
127+
} catch (Throwable $e) {
128+
$output->writeln("\n\n\t<error>>>> [ERROR] - Not applied " . $instance::class . '</error>');
129+
$output->writeln("\n<fg=yellow> >>> Total $i out of $n $migrationWas applied.</>\n");
130+
$io->error($i > 0 ? 'Reverted but partially applied.' : 'Reverted but not applied.');
131+
132+
throw $e;
133+
}
113134
}
114135

115-
$output->writeln(
116-
"\n<info> >>> $n " . ($n === 1 ? 'migration was' : 'migrations were') . " redone.</info>\n"
117-
);
136+
$output->writeln("\n<info> >>> $n $migrationWas redone.</info>\n");
118137
$io->success('Migration redone successfully.');
119138
}
120139

src/Command/UpdateCommand.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Symfony\Component\Console\Output\OutputInterface;
1313
use Symfony\Component\Console\Question\ConfirmationQuestion;
1414
use Symfony\Component\Console\Style\SymfonyStyle;
15+
use Throwable;
1516
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
1617
use Yiisoft\Db\Migration\Migrator;
1718
use Yiisoft\Db\Migration\Runner\UpdateRunner;
@@ -92,7 +93,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
9293
}
9394
}
9495

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

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

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

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

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

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

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

140140
if ($helper->ask($input, $output, $question)) {
141141
$instances = $this->migrationService->makeMigrations($migrations);
142-
foreach ($instances as $instance) {
143-
$this->updateRunner->run($instance);
142+
$migrationWas = ($n === 1 ? 'migration was' : 'migrations were');
143+
144+
foreach ($instances as $i => $instance) {
145+
try {
146+
$this->updateRunner->run($instance);
147+
} catch (Throwable $e) {
148+
$output->writeln("\n\n\t<error>>>> [ERROR] - Not applied " . $instance::class . '</error>');
149+
$output->writeln("\n<fg=yellow> >>> Total $i out of $n new $migrationWas applied.</>\n");
150+
$io->error($i > 0 ? 'Partially updated.' : 'Not updated.');
151+
152+
throw $e;
153+
}
144154
}
145155

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

src/Migrator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public function getMigrationNameLimit(): ?int
7878
return $this->migrationNameLimit = $limit;
7979
}
8080

81-
/** @psalm-return array<string, int|string> */
81+
/** @psalm-return array<class-string, int|string> */
8282
public function getHistory(?int $limit = null): array
8383
{
8484
$this->checkMigrationHistoryTable();
@@ -93,7 +93,7 @@ public function getHistory(?int $limit = null): array
9393
$query->limit($limit);
9494
}
9595

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

src/Service/MigrationService.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ public function before(string $defaultName): int
106106
* Returns the migrations that are not applied.
107107
*
108108
* @return array List of new migrations.
109+
*
110+
* @psalm-return array<int, class-string>
109111
*/
110112
public function getNewMigrations(): array
111113
{
@@ -158,6 +160,7 @@ public function getNewMigrations(): array
158160
}
159161
ksort($migrations);
160162

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

tests/Common/Command/AbstractDownCommandTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use RuntimeException;
1111
use Symfony\Component\Console\Command\Command;
1212
use Symfony\Component\Console\Tester\CommandTester;
13+
use Throwable;
1314
use Yiisoft\Db\Connection\ConnectionInterface;
1415
use Yiisoft\Db\Migration\Command\DownCommand;
1516
use Yiisoft\Db\Migration\Migrator;
@@ -273,6 +274,69 @@ public function testIncorrectLimit(int $limit): void
273274
$this->assertStringContainsString('The limit option must be greater than 0.', $output);
274275
}
275276

277+
public function testPartiallyReverted(): void
278+
{
279+
MigrationHelper::useMigrationsNamespace($this->container);
280+
MigrationHelper::createAndApplyMigration(
281+
$this->container,
282+
'Create_Book',
283+
'table',
284+
'book',
285+
['title:string(100)', 'author:string(80)'],
286+
);
287+
MigrationHelper::createAndApplyMigration(
288+
$this->container,
289+
'Create_Chapter',
290+
'table',
291+
'chapter',
292+
['name:string(100)'],
293+
);
294+
295+
$db = $this->container->get(ConnectionInterface::class);
296+
$db->createCommand()->dropTable('book')->execute();
297+
298+
$command = $this->createCommand($this->container);
299+
300+
try {
301+
$exitCode = $command->setInputs(['yes'])->execute(['-l' => 2]);
302+
} catch (Throwable) {
303+
}
304+
305+
$output = $command->getDisplay(true);
306+
307+
$this->assertFalse(isset($exitCode));
308+
$this->assertStringContainsString('>>> Total 1 out of 2 migrations were reverted.', $output);
309+
$this->assertStringContainsString('[ERROR] Partially reverted.', $output);
310+
}
311+
312+
public function testNotReverted(): void
313+
{
314+
MigrationHelper::useMigrationsNamespace($this->container);
315+
MigrationHelper::createAndApplyMigration(
316+
$this->container,
317+
'Create_Book',
318+
'table',
319+
'book',
320+
['title:string(100)', 'author:string(80)'],
321+
);
322+
323+
$db = $this->container->get(ConnectionInterface::class);
324+
$db->createCommand()->dropTable('book')->execute();
325+
326+
$command = $this->createCommand($this->container);
327+
328+
try {
329+
$exitCode = $command->setInputs(['yes'])->execute([]);
330+
} catch (Throwable) {
331+
}
332+
333+
$output = $command->getDisplay(true);
334+
335+
$this->assertFalse(isset($exitCode));
336+
$this->assertStringContainsString('>>> Total 0 out of 1 migration was reverted.', $output);
337+
$this->assertStringContainsString('[ERROR] Not reverted.', $output);
338+
}
339+
276340
public function createCommand(ContainerInterface $container): CommandTester
277341
{
278342
return CommandHelper::getCommandTester($container, DownCommand::class);

0 commit comments

Comments
 (0)