Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ please refer to the [Code BC breaks](#code-bc-breaks) section.
please update your scripts.
Console output is not covered by the BC promise, so please try not to rely on specific a output.
Different levels of verbosity are available now (`-v`, `-vv` and `-vvv` ).
- The `--show-versions` option from `migrations:status` command has been removed,
use `migrations:list` instead.

## Migrations table

Expand Down
4 changes: 3 additions & 1 deletion docs/en/reference/custom-configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ Once you have your custom integration setup, you can modify it to look like the
new Command\ExecuteCommand($dependencyFactory),
new Command\GenerateCommand($dependencyFactory),
new Command\LatestCommand($dependencyFactory),
new Command\ListCommand($dependencyFactory),
new Command\MigrateCommand($dependencyFactory),
new Command\RollupCommand($dependencyFactory),
new Command\StatusCommand($dependencyFactory),
new Command\VersionCommand($dependencyFactory)
new Command\SyncMetadataCommand($dependencyFactory),
new Command\VersionCommand($dependencyFactory),
));

$cli->run();
Expand Down
4 changes: 3 additions & 1 deletion docs/en/reference/custom-integration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ Now place the following code in the ``migrations`` file:
new Command\ExecuteCommand($dependencyFactory),
new Command\GenerateCommand($dependencyFactory),
new Command\LatestCommand($dependencyFactory),
new Command\ListCommand($dependencyFactory),
new Command\MigrateCommand($dependencyFactory),
new Command\RollupCommand($dependencyFactory),
new Command\StatusCommand($dependencyFactory),
new Command\VersionCommand($dependencyFactory)
new Command\SyncMetadataCommand($dependencyFactory),
new Command\VersionCommand($dependencyFactory),
));

$cli->run();
Expand Down
128 changes: 128 additions & 0 deletions lib/Doctrine/Migrations/Tools/Console/Command/ListCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php

declare(strict_types=1);

namespace Doctrine\Migrations\Tools\Console\Command;

use DateTimeInterface;
use Doctrine\Migrations\Metadata\AvailableMigration;
use Doctrine\Migrations\Metadata\AvailableMigrationsList;
use Doctrine\Migrations\Metadata\ExecutedMigration;
use Doctrine\Migrations\Metadata\ExecutedMigrationsSet;
use Doctrine\Migrations\Version\Version;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use function array_map;
use function array_merge;
use function array_unique;
use function uasort;

/**
* The ListCommand class is responsible for outputting a list of all available migrations and their status.
*/
final class ListCommand extends DoctrineCommand
{
/** @var string */
protected static $defaultName = 'migrations:list';

protected function configure() : void
{
$this
->setAliases(['list-migrations'])
->setDescription('Display a list of all available migrations and their status.')
->setHelp(<<<EOT
The <info>%command.name%</info> command outputs a list of all available migrations and their status:

<info>%command.full_name%</info>
EOT
);

parent::configure();
}

public function execute(InputInterface $input, OutputInterface $output) : int
{
$this->showVersions(
$this->getDependencyFactory()->getMigrationRepository()->getMigrations(), // available migrations
$this->getDependencyFactory()->getMetadataStorage()->getExecutedMigrations(), // executed migrations
$output
);

return 0;
}

private function showVersions(
AvailableMigrationsList $availableMigrations,
ExecutedMigrationsSet $executedMigrations,
OutputInterface $output
) : void {
$table = new Table($output);
$table->setHeaders(
[
[new TableCell('Migration Versions', ['colspan' => 4])],
['Migration', 'Status', 'Migrated At', 'Execution Time', 'Description'],
]
);

foreach ($this->getSortedVersions($availableMigrations, $executedMigrations) as $version) {
$description = null;
$executedAt = null;
$executionTime = null;

if ($executedMigrations->hasMigration($version)) {
$executedMigration = $executedMigrations->getMigration($version);
$executionTime = $executedMigration->getExecutionTime();
$executedAt = $executedMigration->getExecutedAt() instanceof DateTimeInterface
? $executedMigration->getExecutedAt()->format('Y-m-d H:i:s')
: null;
}

if ($availableMigrations->hasMigration($version)) {
$description = $availableMigrations->getMigration($version)->getMigration()->getDescription();
}

if ($executedMigrations->hasMigration($version) && $availableMigrations->hasMigration($version)) {
$status = '<info>migrated</info>';
} elseif ($executedMigrations->hasMigration($version)) {
$status = '<error>migrated, not available</error>';
} else {
$status = '<comment>not migrated</comment>';
}

$table->addRow([
(string) $version,
$status,
(string) $executedAt,
$executionTime !== null ? $executionTime . 's': '',
$description,
]);
}

$table->render();
}

/**
* @return Version[]
*/
private function getSortedVersions(AvailableMigrationsList $availableMigrations, ExecutedMigrationsSet $executedMigrations) : array
{
$availableVersions = array_map(static function (AvailableMigration $availableMigration) : Version {
return $availableMigration->getVersion();
}, $availableMigrations->getItems());

$executedVersions = array_map(static function (ExecutedMigration $executedMigration) : Version {
return $executedMigration->getVersion();
}, $executedMigrations->getItems());

$versions = array_unique(array_merge($availableVersions, $executedVersions));

$comparator = $this->getDependencyFactory()->getVersionComparator();
uasort($versions, static function (Version $a, Version $b) use ($comparator) : int {
return $comparator->compare($a, $b);
});

return $versions;
}
}
77 changes: 0 additions & 77 deletions lib/Doctrine/Migrations/Tools/Console/Command/StatusCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@

namespace Doctrine\Migrations\Tools\Console\Command;

use DateTimeImmutable;
use Doctrine\Migrations\Metadata\AvailableMigrationsList;
use Doctrine\Migrations\Metadata\ExecutedMigrationsSet;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use function count;

/**
* The StatusCommand class is responsible for outputting what the current state is of all your migrations. It shows
Expand All @@ -38,10 +32,6 @@ protected function configure() : void
The <info>%command.name%</info> command outputs the status of a set of migrations:

<info>%command.full_name%</info>

You can output a list of all available migrations and their status with <comment>--show-versions</comment>:

<info>%command.full_name% --show-versions</info>
EOT
);

Expand All @@ -63,73 +53,6 @@ public function execute(InputInterface $input, OutputInterface $output) : ?int
$infosHelper = $this->getDependencyFactory()->getMigrationStatusInfosHelper();
$infosHelper->showMigrationsInfo($output, $availableMigrations, $executedMigrations, $newMigrations, $executedUnavailableMigrations);

if ($input->getOption('show-versions') === false) {
return 0;
}

if (count($availableMigrations) !== 0) {
$this->showVersions($availableMigrations, $executedMigrations, $output);
}

if (count($executedUnavailableMigrations) !== 0) {
$this->showUnavailableVersions($output, $executedUnavailableMigrations);
}

return 0;
}

private function showUnavailableVersions(OutputInterface $output, ExecutedMigrationsSet $executedUnavailableMigrations) : void
{
$table = new Table($output);
$table->setHeaders(
[
[new TableCell('<error>Previously Executed Unavailable Migration Versions</error>', ['colspan' => 2])],
['Migration', 'Migrated At'],
]
);
foreach ($executedUnavailableMigrations->getItems() as $executedUnavailableMigration) {
$table->addRow([
(string) $executedUnavailableMigration->getVersion(),
$executedUnavailableMigration->getExecutedAt() !== null
? $executedUnavailableMigration->getExecutedAt()->format('Y-m-d H:i:s')
: null,
]);
}

$table->render();
}

private function showVersions(
AvailableMigrationsList $availableMigrationsSet,
ExecutedMigrationsSet $executedMigrationsSet,
OutputInterface $output
) : void {
$table = new Table($output);
$table->setHeaders(
[
[new TableCell('Available Migration Versions', ['colspan' => 4])],
['Migration', 'Migrated', 'Migrated At', 'Description'],
]
);
foreach ($availableMigrationsSet->getItems() as $availableMigration) {
$executedMigration = $executedMigrationsSet->hasMigration($availableMigration->getVersion())
? $executedMigrationsSet->getMigration($availableMigration->getVersion())
: null;

$executedAt = $executedMigration!==null && $executedMigration->getExecutedAt() instanceof DateTimeImmutable
? $executedMigration->getExecutedAt()->format('Y-m-d H:i:s')
: null;

$description = $availableMigration->getMigration()->getDescription();

$table->addRow([
(string) $availableMigration->getVersion(),
$executedMigration !== null ? '<comment>migrated</comment>' : '<error>not migrated</error>',
(string) $executedAt,
$description,
]);
}

$table->render();
}
}
2 changes: 2 additions & 0 deletions lib/Doctrine/Migrations/Tools/Console/ConsoleRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Doctrine\Migrations\Tools\Console\Command\ExecuteCommand;
use Doctrine\Migrations\Tools\Console\Command\GenerateCommand;
use Doctrine\Migrations\Tools\Console\Command\LatestCommand;
use Doctrine\Migrations\Tools\Console\Command\ListCommand;
use Doctrine\Migrations\Tools\Console\Command\MigrateCommand;
use Doctrine\Migrations\Tools\Console\Command\RollupCommand;
use Doctrine\Migrations\Tools\Console\Command\StatusCommand;
Expand Down Expand Up @@ -109,6 +110,7 @@ public static function addCommands(Application $cli, ?DependencyFactory $depende
new VersionCommand($dependencyFactory),
new UpToDateCommand($dependencyFactory),
new SyncMetadataCommand($dependencyFactory),
new ListCommand($dependencyFactory),
]);

if ($dependencyFactory === null || ! $dependencyFactory->hasEntityManager()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);

namespace Doctrine\Migrations\Tests\Tools\Console\Command;

use DateTimeImmutable;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\Configuration\Connection\ExistingConnection;
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
use Doctrine\Migrations\MigrationRepository;
use Doctrine\Migrations\Tests\MigrationTestCase;
use Doctrine\Migrations\Tools\Console\Command\ListCommand;
use Doctrine\Migrations\Version\Direction;
use Doctrine\Migrations\Version\ExecutionResult;
use Doctrine\Migrations\Version\Version;
use Symfony\Component\Console\Tester\CommandTester;
use function array_map;
use function explode;
use function sys_get_temp_dir;
use function trim;

class ListCommandTest extends MigrationTestCase
{
/** @var ListCommand */
private $command;

/** @var MigrationRepository */
private $migrationRepository;

/** @var MetadataStorage */
private $metadataStorage;

/** @var CommandTester */
private $commandTester;

protected function setUp() : void
{
$configuration = new Configuration();
$configuration->setMetadataStorageConfiguration(new TableMetadataStorageConfiguration());
$configuration->addMigrationsDirectory('DoctrineMigrations', sys_get_temp_dir());

$conn = $this->getSqliteConnection();

$dependencyFactory = DependencyFactory::fromConnection(
new Configuration\ExistingConfiguration($configuration),
new ExistingConnection($conn)
);

$this->migrationRepository = $dependencyFactory->getMigrationRepository();
$this->metadataStorage = $dependencyFactory->getMetadataStorage();

$this->metadataStorage->ensureInitialized();

$this->command = new ListCommand($dependencyFactory);
$this->commandTester = new CommandTester($this->command);
}

public function testExecute() : void
{
$migrationClass = $this->createMock(AbstractMigration::class);
$migrationClass
->expects(self::atLeastOnce())
->method('getDescription')
->willReturn('foo');

$this->migrationRepository->registerMigrationInstance(new Version('1231'), $migrationClass);
$this->migrationRepository->registerMigrationInstance(new Version('1230'), $migrationClass);

$result = new ExecutionResult(new Version('1230'), Direction::UP, new DateTimeImmutable('2010-01-01 02:03:04'));
$result->setTime(10.0);
$this->metadataStorage->complete($result);

$result = new ExecutionResult(new Version('1229'), Direction::UP, new DateTimeImmutable('2010-01-01 02:03:04'));
$this->metadataStorage->complete($result);

$this->commandTester->execute([]);

$lines = array_map('trim', explode("\n", trim($this->commandTester->getDisplay(true))));

self::assertSame(
[
0 => '+-----------+-------------------------+---------------------+----------------+-------------+',
1 => '| Migration Versions | |',
2 => '+-----------+-------------------------+---------------------+----------------+-------------+',
3 => '| Migration | Status | Migrated At | Execution Time | Description |',
4 => '+-----------+-------------------------+---------------------+----------------+-------------+',
5 => '| 1229 | migrated, not available | 2010-01-01 02:03:04 | | |',
6 => '| 1230 | migrated | 2010-01-01 02:03:04 | 10s | foo |',
7 => '| 1231 | not migrated | | | foo |',
8 => '+-----------+-------------------------+---------------------+----------------+-------------+',
],
$lines
);
}
}
Loading