Skip to content

Commit 5b0b076

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

File tree

2 files changed

+118
-12
lines changed

2 files changed

+118
-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

+91-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,12 @@ 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+
6677
if ($arg === false) {
6778
$this->queryWriter
6879
->expects(self::never())
@@ -116,6 +127,12 @@ public function testExecute(): void
116127
return ['A'];
117128
});
118129

130+
$this->versionAliasResolver
131+
->expects(self::once())
132+
->method('resolveVersionAlias')
133+
->with('1')
134+
->willReturn(new Version('1'));
135+
119136
$this->executeCommandTester->execute([
120137
'versions' => ['1'],
121138
'--down' => true,
@@ -125,6 +142,63 @@ public function testExecute(): void
125142
self::assertStringContainsString('[notice] Executing 1 up', trim($this->executeCommandTester->getDisplay(true)));
126143
}
127144

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

225+
$this->versionAliasResolver
226+
->expects(self::exactly(2))
227+
->method('resolveVersionAlias')
228+
->withConsecutive(['1'], ['2'])
229+
->willReturnOnConsecutiveCalls(new Version('1'), new Version('2'));
230+
151231
$this->executeCommandTester->execute([
152232
'versions' => ['1', '2'],
153233
'--down' => true,
@@ -174,6 +254,12 @@ public function testExecuteCancel(): void
174254
return ['A'];
175255
});
176256

257+
$this->versionAliasResolver
258+
->expects(self::once())
259+
->method('resolveVersionAlias')
260+
->with('1')
261+
->willReturn(new Version('1'));
262+
177263
$this->executeCommandTester->execute([
178264
'versions' => ['1'],
179265
'--down' => true,
@@ -186,9 +272,10 @@ protected function setUp(): void
186272
{
187273
$connection = $this->getSqliteConnection();
188274

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

193280
$p1 = new MigrationPlan(new Version('1'), $migration, Direction::UP);
194281
$pl = new MigrationPlanList([$p1], Direction::UP);
@@ -207,6 +294,7 @@ protected function setUp(): void
207294
$this->dependencyFactory->setService(Migrator::class, $this->migrator);
208295
$this->dependencyFactory->setService(MigrationPlanCalculator::class, $this->planCalculator);
209296
$this->dependencyFactory->setService(QueryWriter::class, $this->queryWriter);
297+
$this->dependencyFactory->setService(AliasResolver::class, $this->versionAliasResolver);
210298

211299
$this->executeCommand = new ExecuteCommand($this->dependencyFactory);
212300

0 commit comments

Comments
 (0)