From 93282f73765b09a9ae38f992dd20d097cb4f6425 Mon Sep 17 00:00:00 2001 From: Brian Stanley Date: Wed, 6 Aug 2025 11:43:49 -0400 Subject: [PATCH 1/6] Suppress mysqldump password warning --- src/Commands/MigrateDumpCommand.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Commands/MigrateDumpCommand.php b/src/Commands/MigrateDumpCommand.php index 578badd..6e96611 100644 --- a/src/Commands/MigrateDumpCommand.php +++ b/src/Commands/MigrateDumpCommand.php @@ -142,14 +142,15 @@ public static function reorderMigrationRows(array $output) : array */ private static function mysqlSchemaDump(array $db_config, string $schema_sql_path) : int { - // TODO: Suppress warning about insecure password. // CONSIDER: Intercepting stdout and stderr and converting to colorized // console output with `$this->info` and `->error`. passthru( - static::mysqlCommandPrefix($db_config) + 'bash -c "' + . static::mysqlCommandPrefix($db_config) . ' --result-file=' . escapeshellarg($schema_sql_path) . ' --no-data' - . ' --routines', + . ' --routines' + . ' 2> >(grep -v \'Using a password on the command line interface can be insecure.\')"', $exit_code ); @@ -170,13 +171,15 @@ private static function mysqlSchemaDump(array $db_config, string $schema_sql_pat // Include migration rows to avoid unnecessary reruns conflicting. exec( - static::mysqlCommandPrefix($db_config) + 'bash -c "' + . static::mysqlCommandPrefix($db_config) . ' ' . ($db_config['prefix'] ?? '') . 'migrations' . ' --no-create-info' . ' --skip-extended-insert' . ' --skip-routines' . ' --single-transaction' - . ' --compact', + . ' --compact' + . ' 2> >(grep -v \'Using a password on the command line interface can be insecure.\')"', $output, $exit_code ); @@ -207,11 +210,13 @@ private static function mysqlSchemaDump(array $db_config, string $schema_sql_pat private static function mysqlDataDump(array $db_config, string $data_sql_path) : int { passthru( - static::mysqlCommandPrefix($db_config) + 'bash -c "' + . static::mysqlCommandPrefix($db_config) . ' --result-file=' . escapeshellarg($data_sql_path) . ' --no-create-info --skip-routines --skip-triggers' . ' --ignore-table=' . escapeshellarg($db_config['database'] . '.' . ($db_config['prefix'] ?? '') . 'migrations') - . ' --single-transaction', // Avoid disruptive locks. + . ' --single-transaction' // Avoid disruptive locks. + . ' 2> >(grep -v \'Using a password on the command line interface can be insecure.\')"', $exit_code ); From 8fb994dfb8e77e4b0ab0e50b09617f082c4c4248 Mon Sep 17 00:00:00 2001 From: Brian Stanley Date: Wed, 6 Aug 2025 11:47:13 -0400 Subject: [PATCH 2/6] Remove unnecessay variable --- src/Commands/MigrateDumpCommand.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Commands/MigrateDumpCommand.php b/src/Commands/MigrateDumpCommand.php index 6e96611..60857b2 100644 --- a/src/Commands/MigrateDumpCommand.php +++ b/src/Commands/MigrateDumpCommand.php @@ -22,8 +22,6 @@ final class MigrateDumpCommand extends Command public function handle() { - $exit_code = null; - $database = $this->option('database') ?: DB::getDefaultConnection(); DB::setDefaultConnection($database); $db_config = DB::getConfig(); From 9346b8bcf3d2346087cb23346263fc30b01e44ca Mon Sep 17 00:00:00 2001 From: Brian Stanley Date: Thu, 7 Aug 2025 14:47:08 -0400 Subject: [PATCH 3/6] Make dump files driver specific --- src/Commands/MigrateDumpCommand.php | 23 ++++++++++++++++------- src/Commands/MigrateLoadCommand.php | 24 +++++++++++------------- src/EventServiceProvider.php | 11 ++++++++--- src/Handlers/MigrateStartingHandler.php | 8 ++++++-- tests/MigrateDumpTest.php | 5 +---- tests/MigrateHookTest.php | 9 ++++----- tests/TestCase.php | 9 +++++---- 7 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/Commands/MigrateDumpCommand.php b/src/Commands/MigrateDumpCommand.php index 60857b2..4faa1fe 100644 --- a/src/Commands/MigrateDumpCommand.php +++ b/src/Commands/MigrateDumpCommand.php @@ -8,10 +8,9 @@ final class MigrateDumpCommand extends Command { - public const SCHEMA_SQL_PATH_SUFFIX = '/migrations/sql/schema.sql'; - public const DATA_SQL_PATH_SUFFIX = '/migrations/sql/data.sql'; - public const SUPPORTED_DB_DRIVERS = ['mysql', 'pgsql', 'sqlite']; + protected const SCHEMA_SQL_PATH_SUFFIX = 'migrations/sql/schema.'; + protected const DATA_SQL_PATH_SUFFIX = 'migrations/sql/data.'; protected $signature = 'migrate:dump {--database= : The database connection to use} @@ -28,7 +27,7 @@ public function handle() // CONSIDER: Ending with ".mysql" or "-mysql.sql" unless in // compatibility mode. - $schema_sql_path = database_path() . self::SCHEMA_SQL_PATH_SUFFIX; + $schema_sql_path = self::getSchemaSqlPath($db_config['driver']); $schema_sql_directory = dirname($schema_sql_path); if (! file_exists($schema_sql_directory)) { mkdir($schema_sql_directory, 0755); @@ -36,7 +35,7 @@ public function handle() if (! in_array($db_config['driver'], self::SUPPORTED_DB_DRIVERS, true)) { throw new \InvalidArgumentException( - 'Unsupported DB driver ' . var_export($db_config['driver'], 1) + 'Unsupported database driver ' . var_export($db_config['driver'], 1) ); } @@ -59,13 +58,13 @@ public function handle() exit($exit_code); // CONSIDER: Returning instead. } - $this->info('Dumped schema'); + $this->info('Dumped ' . $db_config['driver'] . ' schema'); $data_path = null; if ($this->option('include-data')) { $this->info('Starting Data Dump'); - $data_path = database_path() . self::DATA_SQL_PATH_SUFFIX; + $data_path = self::getDataSqlPath($db_config['driver']); if ('pgsql' === $db_config['driver']) { $data_path = preg_replace('/\.sql$/', '.pgdump', $data_path); } @@ -132,6 +131,16 @@ public static function reorderMigrationRows(array $output) : array return $output; } + public static function getSchemaSqlPath(string $driver) : string + { + return database_path(self::SCHEMA_SQL_PATH_SUFFIX . $driver . '.sql'); + } + + public static function getDataSqlPath(string $driver) : string + { + return database_path(self::DATA_SQL_PATH_SUFFIX . $driver . '.sql'); + } + /** * @param array $db_config like ['host' => , 'port' => ]. * @param string $schema_sql_path like '.../schema.sql' diff --git a/src/Commands/MigrateLoadCommand.php b/src/Commands/MigrateLoadCommand.php index 50bdba4..72fa22d 100644 --- a/src/Commands/MigrateLoadCommand.php +++ b/src/Commands/MigrateLoadCommand.php @@ -20,30 +20,28 @@ final class MigrateLoadCommand extends Command public function handle() { - $exit_code = null; - if ( ! $this->option('force') && app()->environment('production') - && ! $this->confirm('Are you sure you want to load the DB schema from a file?') + && ! $this->confirm('Are you sure you want to load the database schema from a file?') ) { return; } - $schema_sql_path = database_path() . MigrateDumpCommand::SCHEMA_SQL_PATH_SUFFIX; - if (! file_exists($schema_sql_path)) { - throw new InvalidArgumentException( - 'Schema-migrations path not found, run `migrate:dump` first.' - ); - } - $database = $this->option('database') ?: DB::getDefaultConnection(); DB::setDefaultConnection($database); $db_config = DB::getConfig(); if (! in_array($db_config['driver'], MigrateDumpCommand::SUPPORTED_DB_DRIVERS, true)) { throw new InvalidArgumentException( - 'Unsupported DB driver ' . var_export($db_config['driver'], 1) + 'Unsupported database driver ' . var_export($db_config['driver'], 1) + ); + } + + $schema_sql_path = MigrateDumpCommand::getSchemaSqlPath($db_config['driver']); + if (! file_exists($schema_sql_path)) { + throw new InvalidArgumentException( + 'No schema dump found for the current database driver. Run `migrate:dump --database ' . $db_config['driver'] . '` before running this command.' ); } @@ -71,9 +69,9 @@ public function handle() exit($exit_code); // CONSIDER: Returning instead. } - $this->info('Loaded schema'); + $this->info('Loaded ' . $db_config['driver'] . ' schema'); - $data_path = database_path() . MigrateDumpCommand::DATA_SQL_PATH_SUFFIX; + $data_path = MigrateDumpCommand::getDataSqlPath($db_config['driver']); if ('pgsql' === $db_config['driver']) { $data_path = preg_replace('/\.sql$/', '.pgdump', $data_path); } diff --git a/src/EventServiceProvider.php b/src/EventServiceProvider.php index c30fc9b..4d2d3f0 100644 --- a/src/EventServiceProvider.php +++ b/src/EventServiceProvider.php @@ -3,12 +3,17 @@ namespace AlwaysOpen\MigrationSnapshot; +use AlwaysOpen\MigrationSnapshot\Handlers\MigrateFinishedHandler; +use AlwaysOpen\MigrationSnapshot\Handlers\MigrateStartingHandler; +use Illuminate\Console\Events\CommandFinished; +use Illuminate\Console\Events\CommandStarting; + final class EventServiceProvider extends \Illuminate\Foundation\Support\Providers\EventServiceProvider { protected $listen = [ // CONSIDER: Only registering these when Laravel version doesn't have // more specific hooks. - 'Illuminate\Console\Events\CommandFinished' => ['AlwaysOpen\MigrationSnapshot\Handlers\MigrateFinishedHandler'], - 'Illuminate\Console\Events\CommandStarting' => ['AlwaysOpen\MigrationSnapshot\Handlers\MigrateStartingHandler'], + CommandFinished::class => [MigrateFinishedHandler::class], + CommandStarting::class => [MigrateStartingHandler::class], ]; -} \ No newline at end of file +} diff --git a/src/Handlers/MigrateStartingHandler.php b/src/Handlers/MigrateStartingHandler.php index 5320ff5..245c37c 100644 --- a/src/Handlers/MigrateStartingHandler.php +++ b/src/Handlers/MigrateStartingHandler.php @@ -59,8 +59,6 @@ public function handle(CommandStarting $event) // Never implicitly load fresh (from file) in production since it // would need to drop first, and that would be destructive. && in_array(app()->environment(), explode(',', config('migration-snapshot.environments')), true) - // No point in implicitly loading when it's not present. - && file_exists(database_path() . MigrateDumpCommand::SCHEMA_SQL_PATH_SUFFIX) ) { // Must pass along options or it may use wrong DB or have // inconsistent output. @@ -72,6 +70,12 @@ public function handle(CommandStarting $event) return; } + // No point in continuing to load when it's not present. + if (!file_exists(MigrateDumpCommand::getSchemaSqlPath($db_driver))) { + // CONSIDER: Logging or emitting console warning. + return; + } + // Only implicitly load when DB has *not* migrated any since load // would wipe existing data. $has_migrated_any = false; diff --git a/tests/MigrateDumpTest.php b/tests/MigrateDumpTest.php index 918df5b..285a167 100644 --- a/tests/MigrateDumpTest.php +++ b/tests/MigrateDumpTest.php @@ -1,6 +1,5 @@ assertEquals(0, $result); - $schema_sql = file_get_contents( - database_path() . MigrateDumpCommand::SCHEMA_SQL_PATH_SUFFIX - ); + $schema_sql = file_get_contents($this->schemaSqlPath); $this->assertStringNotContainsString('/*', $schema_sql); } } diff --git a/tests/MigrateHookTest.php b/tests/MigrateHookTest.php index c9c76d5..d494bf0 100644 --- a/tests/MigrateHookTest.php +++ b/tests/MigrateHookTest.php @@ -1,6 +1,5 @@ assertEquals(0, $result); $output_string = $output->fetch(); - $this->assertStringContainsString('Loaded schema', $output_string); - $this->assertStringContainsString('Dumped schema', $output_string); + $this->assertStringContainsString('Loaded ' . $this->dbDefault . ' schema', $output_string); + $this->assertStringContainsString('Dumped ' . $this->dbDefault . ' schema', $output_string); } public function test_handle_dumpsOnRollback() @@ -44,7 +43,7 @@ public function test_handle_dumpsOnRollback() $this->assertEquals(0, $result); $output_string = $output->fetch(); - $this->assertStringContainsString('Dumped schema', $output_string); + $this->assertStringContainsString('Dumped ' . $this->dbDefault . ' schema', $output_string); } public function test_handle_doesNotLoadWhenDbHasMigrated() @@ -61,7 +60,7 @@ public function test_handle_doesNotLoadWhenDbHasMigrated() $this->assertEquals(0, $result); $output_string = $output->fetch(); - $this->assertStringNotContainsString('Loaded schema', $output_string); + $this->assertStringNotContainsString('Loaded ' . $this->dbDefault . ' schema', $output_string); $this->assertEquals(1, \DB::table('test_ms')->count()); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 1fbe719..d2f8d9e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -5,6 +5,7 @@ use AlwaysOpen\MigrationSnapshot\Commands\MigrateDumpCommand; +use AlwaysOpen\MigrationSnapshot\ServiceProvider; class TestCase extends \Orchestra\Testbench\TestCase { @@ -17,9 +18,9 @@ protected function setUp(): void { parent::setUp(); - $this->schemaSqlPath = realpath( - __DIR__ . '/../vendor/orchestra/testbench-core/laravel/database' - ) . MigrateDumpCommand::SCHEMA_SQL_PATH_SUFFIX; + $this->schemaSqlPath = MigrateDumpCommand::getSchemaSqlPath( + $this->app['config']->get('database.connections.' . $this->dbDefault . '.driver') + ); $this->schemaSqlDirectory = dirname($this->schemaSqlPath); // Not leaving to tearDown since it can be useful to see result after @@ -44,7 +45,7 @@ protected function getEnvironmentSetUp($app) protected function getPackageProviders($app) { - return ['\AlwaysOpen\MigrationSnapshot\ServiceProvider']; + return [ServiceProvider::class]; } protected function createTestTablesWithoutMigrate() : void From 29fb1c4657972646ad5db14636fb4f295112fb07 Mon Sep 17 00:00:00 2001 From: Brian Stanley Date: Thu, 7 Aug 2025 14:52:40 -0400 Subject: [PATCH 4/6] Remove mysql password CLI warning --- src/Commands/MigrateLoadCommand.php | 8 +++++--- tests/TestCase.php | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Commands/MigrateLoadCommand.php b/src/Commands/MigrateLoadCommand.php index 72fa22d..b3433dd 100644 --- a/src/Commands/MigrateLoadCommand.php +++ b/src/Commands/MigrateLoadCommand.php @@ -41,7 +41,7 @@ public function handle() $schema_sql_path = MigrateDumpCommand::getSchemaSqlPath($db_config['driver']); if (! file_exists($schema_sql_path)) { throw new InvalidArgumentException( - 'No schema dump found for the current database driver. Run `migrate:dump --database ' . $db_config['driver'] . '` before running this command.' + 'No schema dump found for the current database driver. Run `migrate:dump --database=' . $database . '` before running this command.' ); } @@ -116,13 +116,15 @@ private static function mysqlLoad(string $path, array $db_config, int $verbosity // CONSIDER: Making input file an option which can override default. // CONSIDER: Avoiding shell specifics like `cat` and piping using // `file_get_contents` or similar. - $command = 'cat ' . escapeshellarg($path) + $command = 'bash -c "' + . 'cat ' . escapeshellarg($path) . ' | mysql --no-beep' . ' --host=' . escapeshellarg($db_config['host']) . ' --port=' . escapeshellarg($db_config['port'] ?? 3306) . ' --user=' . escapeshellarg($db_config['username']) . ' --password=' . escapeshellarg($db_config['password']) - . ' --database=' . escapeshellarg($db_config['database']); + . ' --database=' . escapeshellarg($db_config['database']) + . ' 2> >(grep -v \'Using a password on the command line interface can be insecure.\')"'; switch($verbosity) { case OutputInterface::VERBOSITY_QUIET: $command .= ' -q'; diff --git a/tests/TestCase.php b/tests/TestCase.php index d2f8d9e..a729727 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -39,7 +39,7 @@ protected function getEnvironmentSetUp($app) $oldDbConnConfig = $app['config']->get('database.connections.' . $this->dbDefault) ?? []; $app['config']->set( 'database.connections.' . $this->dbDefault, - ['prefix' => $this->dbPrefix] + $oldDbConnConfig + ['username' => 'root', 'prefix' => $this->dbPrefix] + $oldDbConnConfig ); } From 42269beebf31097444f6d55ab1c7b89bac6bb42e Mon Sep 17 00:00:00 2001 From: Brian Stanley Date: Thu, 7 Aug 2025 15:16:02 -0400 Subject: [PATCH 5/6] Remove comment --- src/Commands/MigrateDumpCommand.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Commands/MigrateDumpCommand.php b/src/Commands/MigrateDumpCommand.php index cf5de5e..36b9d9e 100644 --- a/src/Commands/MigrateDumpCommand.php +++ b/src/Commands/MigrateDumpCommand.php @@ -25,8 +25,6 @@ public function handle() DB::setDefaultConnection($database); $db_config = DB::getConfig(); - // CONSIDER: Ending with ".mysql" or "-mysql.sql" unless in - // compatibility mode. $schema_sql_path = self::getSchemaSqlPath($db_config['driver']); $schema_sql_directory = dirname($schema_sql_path); if (! file_exists($schema_sql_directory)) { From 6db43fef95b94a32dc1cb86a0ce18c410fbad05d Mon Sep 17 00:00:00 2001 From: Brian Stanley Date: Thu, 7 Aug 2025 15:33:55 -0400 Subject: [PATCH 6/6] Fix test --- tests/MigrateHookTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MigrateHookTest.php b/tests/MigrateHookTest.php index 4a5ad34..ae9fde1 100644 --- a/tests/MigrateHookTest.php +++ b/tests/MigrateHookTest.php @@ -42,7 +42,7 @@ public function test_handle_dumpsOnFresh() $this->assertEquals(0, $result); $output_string = $output->fetch(); - $this->assertStringContainsString('Dumped schema', $output_string); + $this->assertStringContainsString('Dumped ' . $this->dbDefault . ' schema', $output_string); } public function test_handle_dumpsOnRollback()