Skip to content

Commit f2c0394

Browse files
committed
Allow version aliases to be used with execute command
1 parent 818e317 commit f2c0394

File tree

2 files changed

+119
-12
lines changed

2 files changed

+119
-12
lines changed

lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php

+27-9
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ protected function configure(): void
3838
->addArgument(
3939
'versions',
4040
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
41-
'The versions to execute.',
41+
sprintf(
42+
'The versions to execute. Use the FQCN of the migration, or the following reserved aliases: %s',
43+
implode(', ', ['first', 'current', 'prev', 'next', 'latest'])
44+
),
4245
null
4346
)
4447
->addOption(
@@ -76,6 +79,10 @@ protected function configure(): void
7679
The <info>%command.name%</info> command executes migration versions up or down manually:
7780
7881
<info>%command.full_name% FQCN</info>
82+
83+
You can use version aliases instead of the FQCN:
84+
85+
<info>%command.full_name% current</info>
7986
8087
You can show more information about the process by increasing the verbosity level. To see the
8188
executed queries, set the level to debug with <comment>-vv</comment>:
@@ -113,20 +120,31 @@ protected function execute(InputInterface $input, OutputInterface $output): int
113120
{
114121
$migratorConfigurationFactory = $this->getDependencyFactory()->getConsoleInputMigratorConfigurationFactory();
115122
$migratorConfiguration = $migratorConfigurationFactory->getMigratorConfiguration($input);
123+
$aliasResolver = $this->getDependencyFactory()->getVersionAliasResolver();
116124

117-
$question = sprintf(
118-
'WARNING! You are about to execute a migration in database "%s" that could result in schema changes and data loss. Are you sure you wish to continue?',
119-
$this->getDependencyFactory()->getConnection()->getDatabase() ?? '<unnamed>'
120-
);
121-
if (! $migratorConfiguration->isDryRun() && ! $this->canExecute($question, $input)) {
122-
$this->io->error('Migration cancelled!');
125+
$versions = $input->getArgument('versions');
123126

124-
return 1;
127+
foreach ($versions as &$version) {
128+
$version = (string) $aliasResolver->resolveVersionAlias($version);
129+
}
130+
131+
if (! $migratorConfiguration->isDryRun()) {
132+
$this->io->listing($versions);
133+
134+
$question = sprintf(
135+
'WARNING! You are about to execute the migrations listed above in database "%s" that could result in schema changes and data loss. Are you sure you wish to continue?',
136+
$this->getDependencyFactory()->getConnection()->getDatabase() ?? '<unnamed>'
137+
);
138+
139+
if (! $this->canExecute($question, $input)) {
140+
$this->io->error('Migration cancelled!');
141+
142+
return 1;
143+
}
125144
}
126145

127146
$this->getDependencyFactory()->getMetadataStorage()->ensureInitialized();
128147

129-
$versions = $input->getArgument('versions');
130148
$direction = $input->getOption('down') !== false
131149
? Direction::DOWN
132150
: Direction::UP;

tests/Doctrine/Migrations/Tests/Tools/Console/Command/ExecuteCommandTest.php

+92-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Doctrine\Migrations\Configuration\Connection\ExistingConnection;
1010
use Doctrine\Migrations\Configuration\Migration\ExistingConfiguration;
1111
use Doctrine\Migrations\DependencyFactory;
12+
use Doctrine\Migrations\Exception\UnknownMigrationVersion;
1213
use Doctrine\Migrations\Metadata\MigrationPlan;
1314
use Doctrine\Migrations\Metadata\MigrationPlanList;
1415
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
@@ -17,6 +18,7 @@
1718
use Doctrine\Migrations\QueryWriter;
1819
use Doctrine\Migrations\Tests\MigrationTestCase;
1920
use Doctrine\Migrations\Tools\Console\Command\ExecuteCommand;
21+
use Doctrine\Migrations\Version\AliasResolver;
2022
use Doctrine\Migrations\Version\Direction;
2123
use Doctrine\Migrations\Version\MigrationPlanCalculator;
2224
use Doctrine\Migrations\Version\Version;
@@ -47,6 +49,9 @@ class ExecuteCommandTest extends MigrationTestCase
4749
/** @var MigrationPlanCalculator|MockObject */
4850
private $planCalculator;
4951

52+
/** @var AliasResolver|MockObject */
53+
private $versionAliasResolver;
54+
5055
/**
5156
* @param bool|string|null $arg
5257
*
@@ -63,6 +68,13 @@ public function testWriteSql(bool $dryRun, $arg, ?string $path): void
6368
return ['A'];
6469
});
6570

71+
$this->versionAliasResolver
72+
->expects(self::once())
73+
->method('resolveVersionAlias')
74+
->with('1')
75+
->willReturn(new Version('1'))
76+
;
77+
6678
if ($arg === false) {
6779
$this->queryWriter
6880
->expects(self::never())
@@ -116,6 +128,12 @@ public function testExecute(): void
116128
return ['A'];
117129
});
118130

131+
$this->versionAliasResolver
132+
->expects(self::once())
133+
->method('resolveVersionAlias')
134+
->with('1')
135+
->willReturn(new Version('1'));
136+
119137
$this->executeCommandTester->execute([
120138
'versions' => ['1'],
121139
'--down' => true,
@@ -125,6 +143,63 @@ public function testExecute(): void
125143
self::assertStringContainsString('[notice] Executing 1 up', trim($this->executeCommandTester->getDisplay(true)));
126144
}
127145

146+
public function testExecuteVersionAlias(): void
147+
{
148+
$this->executeCommandTester->setInputs(['yes']);
149+
150+
$this->migrator
151+
->expects(self::once())
152+
->method('migrate')
153+
->willReturnCallback(static function (MigrationPlanList $planList, MigratorConfiguration $configuration): array {
154+
self::assertFalse($configuration->isDryRun());
155+
156+
return ['A'];
157+
});
158+
159+
$this->versionAliasResolver
160+
->expects(self::once())
161+
->method('resolveVersionAlias')
162+
->with('current')
163+
->willReturn(new Version('1'));
164+
165+
$this->executeCommandTester->execute([
166+
'versions' => ['current'],
167+
'--down' => true,
168+
]);
169+
170+
self::assertSame(0, $this->executeCommandTester->getStatusCode());
171+
self::assertStringContainsString('[notice] Executing 1 up', trim($this->executeCommandTester->getDisplay(true)));
172+
}
173+
174+
public function testExecuteVersionAliasException(): void
175+
{
176+
$this->executeCommandTester->setInputs(['yes']);
177+
178+
$this->migrator
179+
->expects(self::never())
180+
->method('migrate')
181+
->willReturnCallback(static function (MigrationPlanList $planList, MigratorConfiguration $configuration): array {
182+
self::assertFalse($configuration->isDryRun());
183+
184+
return ['A'];
185+
});
186+
187+
$exception = new UnknownMigrationVersion('not_a_valid_version_alias');
188+
189+
$this->versionAliasResolver
190+
->expects(self::once())
191+
->method('resolveVersionAlias')
192+
->with('not_a_valid_version_alias')
193+
->willThrowException($exception);
194+
195+
self::expectExceptionObject($exception);
196+
197+
$this->executeCommandTester->execute([
198+
'versions' => ['not_a_valid_version_alias'],
199+
'--down' => true,
200+
]);
201+
}
202+
128203
public function testExecuteMultiple(): void
129204
{
130205
$migration = $this->createMock(AbstractMigration::class);
@@ -148,6 +223,12 @@ public function testExecuteMultiple(): void
148223
return ['A'];
149224
});
150225

226+
$this->versionAliasResolver
227+
->expects(self::exactly(2))
228+
->method('resolveVersionAlias')
229+
->withConsecutive(['1'], ['2'])
230+
->willReturnOnConsecutiveCalls(new Version('1'), new Version('2'));
231+
151232
$this->executeCommandTester->execute([
152233
'versions' => ['1', '2'],
153234
'--down' => true,
@@ -174,6 +255,12 @@ public function testExecuteCancel(): void
174255
return ['A'];
175256
});
176257

258+
$this->versionAliasResolver
259+
->expects(self::once())
260+
->method('resolveVersionAlias')
261+
->with('1')
262+
->willReturn(new Version('1'));
263+
177264
$this->executeCommandTester->execute([
178265
'versions' => ['1'],
179266
'--down' => true,
@@ -186,9 +273,10 @@ protected function setUp(): void
186273
{
187274
$connection = $this->getSqliteConnection();
188275

189-
$this->migrator = $this->createMock(Migrator::class);
190-
$this->queryWriter = $this->createMock(QueryWriter::class);
191-
$migration = $this->createMock(AbstractMigration::class);
276+
$this->migrator = $this->createMock(Migrator::class);
277+
$this->queryWriter = $this->createMock(QueryWriter::class);
278+
$this->versionAliasResolver = $this->createMock(AliasResolver::class);
279+
$migration = $this->createMock(AbstractMigration::class);
192280

193281
$p1 = new MigrationPlan(new Version('1'), $migration, Direction::UP);
194282
$pl = new MigrationPlanList([$p1], Direction::UP);
@@ -207,6 +295,7 @@ protected function setUp(): void
207295
$this->dependencyFactory->setService(Migrator::class, $this->migrator);
208296
$this->dependencyFactory->setService(MigrationPlanCalculator::class, $this->planCalculator);
209297
$this->dependencyFactory->setService(QueryWriter::class, $this->queryWriter);
298+
$this->dependencyFactory->setService(AliasResolver::class, $this->versionAliasResolver);
210299

211300
$this->executeCommand = new ExecuteCommand($this->dependencyFactory);
212301

0 commit comments

Comments
 (0)