Skip to content

Commit

Permalink
Port dump command to new migrations backend
Browse files Browse the repository at this point in the history
Add test coverage based on what we had before.
  • Loading branch information
markstory committed Mar 17, 2024
1 parent 2706a4c commit a4c1a16
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 23 deletions.
123 changes: 123 additions & 0 deletions src/Command/DumpCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
declare(strict_types=1);

/**
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @license https://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Migrations\Command;

use Cake\Command\Command;
use Cake\Console\Arguments;
use Cake\Console\ConsoleIo;
use Cake\Console\ConsoleOptionParser;
use Cake\Database\Connection;
use Cake\Datasource\ConnectionManager;
use Migrations\Config\ConfigInterface;
use Migrations\Migration\ManagerFactory;
use Migrations\TableFinderTrait;

/**
* Dump command class.
* A "dump" is a snapshot of a database at a given point in time. It is stored in a
* .lock file in the same folder as migrations files.
*/
class DumpCommand extends Command
{
use TableFinderTrait;

protected string $connection;

/**
* The default name added to the application command list
*
* @return string
*/
public static function defaultName(): string
{
return 'migrations dump';
}

/**
* Configure the option parser
*
* @param \Cake\Console\ConsoleOptionParser $parser The option parser to configure
* @return \Cake\Console\ConsoleOptionParser
*/
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
{
$parser->setDescription([
'Dumps the current scheam of the database to be used while baking a diff',
'',
'<info>migrations dump -c secondary</info>',
])->addOption('plugin', [
'short' => 'p',
'help' => 'The plugin to dump migrations for',
])->addOption('connection', [
'short' => 'c',
'help' => 'The datasource connection to use',
'default' => 'default',
])->addOption('source', [
'short' => 's',
'help' => 'The folder under src/Config that migrations are in',
'default' => ConfigInterface::DEFAULT_MIGRATION_FOLDER,
]);

return $parser;
}

/**
* Execute the command.
*
* @param \Cake\Console\Arguments $args The command arguments.
* @param \Cake\Console\ConsoleIo $io The console io
* @return int|null The exit code or null for success
*/
public function execute(Arguments $args, ConsoleIo $io): ?int
{
$factory = new ManagerFactory([
'plugin' => $args->getOption('plugin'),
'source' => $args->getOption('source'),
'connection' => $args->getOption('connection'),
]);
$config = $factory->createConfig();
$path = $config->getMigrationPaths()[0];
$connectionName = (string)$config->getConnection();
$connection = ConnectionManager::get($connectionName);
assert($connection instanceof Connection);

$collection = $connection->getSchemaCollection();
$options = [
'require-table' => false,
'plugin' => $args->getOption('plugin'),
];
// The connection property is used by the trait methods.
$this->connection = $connectionName;
$tables = $this->getTablesToBake($collection, $options);

$dump = [];
if ($tables) {
foreach ($tables as $table) {
$schema = $collection->describe($table);
$dump[$table] = $schema;
}
}

$filePath = $path . DS . 'schema-dump-' . $connectionName . '.lock';
$io->out("<info>Writing dump file `{$filePath}`...</info>");
if (file_put_contents($filePath, serialize($dump))) {
$io->out("<info>Dump file `{$filePath}` was successfully written</info>");

return self::CODE_SUCCESS;
}
$io->out("<error>An error occurred while writing dump file `{$filePath}`</error>");

return self::CODE_ERROR;
}
}
6 changes: 0 additions & 6 deletions src/Command/MigrateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,10 @@
use Cake\Console\Arguments;
use Cake\Console\ConsoleIo;
use Cake\Console\ConsoleOptionParser;
use Cake\Console\Exception\StopException;
use Cake\Core\Plugin;
use Cake\Datasource\ConnectionManager;
use Cake\Event\EventDispatcherTrait;
use Cake\Utility\Inflector;
use DateTime;
use Exception;
use Migrations\Config\Config;
use Migrations\Config\ConfigInterface;
use Migrations\Migration\Manager;
use Migrations\Migration\ManagerFactory;
use Throwable;

Expand Down
6 changes: 0 additions & 6 deletions src/Command/StatusCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@
use Cake\Console\Arguments;
use Cake\Console\ConsoleIo;
use Cake\Console\ConsoleOptionParser;
use Cake\Console\Exception\StopException;
use Cake\Core\Plugin;
use Cake\Datasource\ConnectionManager;
use Cake\Utility\Inflector;
use Migrations\Config\Config;
use Migrations\Config\ConfigInterface;
use Migrations\Migration\Manager;
use Migrations\Migration\ManagerFactory;

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function getSeedBaseClassName(bool $dropNamespace = true): string
*/
public function getConnection(): string|false
{
return $this->values['connection'] ?? false;
return $this->values['environment']['connection'] ?? false;
}

/**
Expand Down
14 changes: 12 additions & 2 deletions src/Migration/ManagerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ public function __construct(protected array $options)
{
}

/**
* Read configuration options used for this factory
*
* @param string $name The option name to read
* @return mixed Option value or null
*/
public function getOption(string $name): mixed
{
if (!isset($this->options[$name])) {
Expand All @@ -55,6 +61,11 @@ public function getOption(string $name): mixed
return $this->options[$name];
}

/**
* Create a ConfigInterface instance based on the factory options.
*
* @return \Migrations\Config\ConfigInterface
*/
public function createConfig(): ConfigInterface
{
$folder = (string)$this->getOption('source');
Expand Down Expand Up @@ -120,11 +131,10 @@ public function createConfig(): ConfigInterface
* based on the factory constructor options.
* @return \Migrations\Migration\Manager
*/
public function createManager(ConsoleIo $io, ConfigInterface|null $config = null): Manager
public function createManager(ConsoleIo $io, ?ConfigInterface $config = null): Manager
{
$config ??= $this->createConfig();

return new Manager($config, $io);
}
}

2 changes: 2 additions & 0 deletions src/MigrationsPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Migrations\Command\BakeMigrationDiffCommand;
use Migrations\Command\BakeMigrationSnapshotCommand;
use Migrations\Command\BakeSeedCommand;
use Migrations\Command\DumpCommand;
use Migrations\Command\MigrateCommand;
use Migrations\Command\MigrationsCacheBuildCommand;
use Migrations\Command\MigrationsCacheClearCommand;
Expand Down Expand Up @@ -94,6 +95,7 @@ public function console(CommandCollection $commands): CommandCollection
$classes = [
StatusCommand::class,
MigrateCommand::class,
DumpCommand::class,
];
if (class_exists(SimpleBakeCommand::class)) {
$classes[] = BakeMigrationCommand::class;
Expand Down
1 change: 1 addition & 0 deletions src/TableFinderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Cake\ORM\TableRegistry;
use ReflectionClass;

// TODO(mark) Make this into a standalone class instead of a trait.
trait TableFinderTrait
{
/**
Expand Down
102 changes: 102 additions & 0 deletions tests/TestCase/Command/DumpCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php
declare(strict_types=1);

namespace Migrations\Test\TestCase\Command;

use Cake\Console\TestSuite\ConsoleIntegrationTestTrait;
use Cake\Core\Configure;
use Cake\Core\Exception\MissingPluginException;
use Cake\Core\Plugin;
use Cake\Database\Connection;
use Cake\Database\Schema\TableSchema;
use Cake\Datasource\ConnectionManager;
use Cake\TestSuite\TestCase;
use RuntimeException;

class DumpCommandTest extends TestCase
{
use ConsoleIntegrationTestTrait;

protected Connection $connection;
protected string $_compareBasePath;
protected string $dumpFile;

public function setUp(): void
{
parent::setUp();
Configure::write('Migrations.backend', 'builtin');

/** @var \Cake\Database\Connection $this->connection */
$this->connection = ConnectionManager::get('test');
$this->connection->execute('DROP TABLE IF EXISTS numbers');
$this->connection->execute('DROP TABLE IF EXISTS letters');
$this->connection->execute('DROP TABLE IF EXISTS parts');
$this->connection->execute('DROP TABLE IF EXISTS phinxlog');

$this->dumpFile = ROOT . DS . 'config/TestsMigrations/schema-dump-test.lock';
}

public function tearDown(): void
{
parent::tearDown();

$this->connection->execute('DROP TABLE IF EXISTS numbers');
$this->connection->execute('DROP TABLE IF EXISTS letters');
$this->connection->execute('DROP TABLE IF EXISTS parts');
$this->connection->execute('DROP TABLE IF EXISTS phinxlog');
if (file_exists($this->dumpFile)) {
unlink($this->dumpFile);
}
}

public function testExecuteIncorrectConnection(): void
{
$this->expectException(RuntimeException::class);
$this->exec('migrations dump --connection lolnope');
}

public function testExecuteIncorrectPlugin(): void
{
$this->expectException(MissingPluginException::class);
$this->exec('migrations dump --plugin lolnope');
}

public function testExecuteSuccess(): void
{
// Run migrations
$this->exec('migrations migrate --connection test --source TestsMigrations --no-lock');
$this->assertExitSuccess();

// Generate dump file.
$this->exec('migrations dump --connection test --source TestsMigrations');

$this->assertExitSuccess();
$this->assertOutputContains('config/TestsMigrations/schema-dump-test.lock');

$this->assertFileExists($this->dumpFile);
/** @var array<string, TableSchema> $generatedDump */
$generatedDump = unserialize(file_get_contents($this->dumpFile));

$this->assertArrayHasKey('letters', $generatedDump);
$this->assertArrayHasKey('numbers', $generatedDump);
$this->assertInstanceOf(TableSchema::class, $generatedDump['numbers']);
$this->assertInstanceOf(TableSchema::class, $generatedDump['letters']);
$this->assertEquals(['id', 'number', 'radix'], $generatedDump['numbers']->columns());
$this->assertEquals(['id', 'letter'], $generatedDump['letters']->columns());
}

public function testExecutePlugin(): void
{
$this->loadPlugins(['Migrator']);

$this->exec('migrations dump --connection test --plugin Migrator');

$this->assertExitSuccess();
$this->assertOutputContains('Migrator/config/Migrations/schema-dump-test.lock');

$dumpFile = Plugin::path('Migrator') . '/config/Migrations/schema-dump-test.lock';
if (file_exists($dumpFile)) {
unlink($dumpFile);
}
}
}
8 changes: 0 additions & 8 deletions tests/TestCase/Db/Adapter/PhinxAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,12 @@
use Migrations\Db\Adapter\SqliteAdapter;
use Migrations\Db\Literal;
use Migrations\Db\Table\ForeignKey;
use PDO;
use PDOException;
use Phinx\Db\Table as PhinxTable;
use Phinx\Db\Table\Column as PhinxColumn;
use Phinx\Util\Literal as PhinxLiteral;
use PHPUnit\Framework\TestCase;
use RuntimeException;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\BufferedOutput;
use UnexpectedValueException;

class PhinxAdapterTest extends TestCase
{
Expand Down Expand Up @@ -1136,7 +1130,6 @@ public function testDumpCreateTable()
*/
public function testDumpInsert()
{

$table = new PhinxTable('table1', [], $this->adapter);
$table->addColumn('string_col', 'string')
->addColumn('int_col', 'integer')
Expand Down Expand Up @@ -1177,7 +1170,6 @@ public function testDumpInsert()
*/
public function testDumpBulkinsert()
{

$table = new PhinxTable('table1', [], $this->adapter);
$table->addColumn('string_col', 'string')
->addColumn('int_col', 'integer')
Expand Down

0 comments on commit a4c1a16

Please sign in to comment.