diff --git a/src/Data/Casts/PathCast.php b/src/Data/Casts/PathCast.php index 2b242c12..061c4002 100644 --- a/src/Data/Casts/PathCast.php +++ b/src/Data/Casts/PathCast.php @@ -5,21 +5,30 @@ namespace DragonCode\LaravelDeployOperations\Data\Casts; use DragonCode\LaravelDeployOperations\Helpers\ConfigHelper; +use Illuminate\Support\Str; use Spatie\LaravelData\Casts\Cast; use Spatie\LaravelData\Support\Creation\CreationContext; use Spatie\LaravelData\Support\DataProperty; use function app; +use function realpath; class PathCast implements Cast { public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): string { + $path = $this->config()->basePath((string) $value); + if ($properties['realpath'] ?? false) { - return $value ?: $this->config()->basePath(); + return $value ?: $path; } - return $this->config()->basePath($value); + return $this->filename($path) ?: $path; + } + + protected function filename(string $path): false|string + { + return realpath(Str::finish($path, '.php')); } protected function config(): ConfigHelper diff --git a/src/Listeners/Listener.php b/src/Listeners/Listener.php new file mode 100644 index 00000000..a6a177ff --- /dev/null +++ b/src/Listeners/Listener.php @@ -0,0 +1,40 @@ +withOperation(); + } + + return null; + } + + protected function run(string $method, string $operation): void + { + match ($method) { + 'up' => $this->call(OperationsCommand::class, $operation), + 'down' => $this->call(RollbackCommand::class, $operation, ['--force' => true]), + }; + } + + protected function call(string $command, string $filename, array $parameters = []): void + { + Artisan::call($command, array_merge([ + '--' . Options::Path => $filename, + ], $parameters)); + } +} diff --git a/src/Listeners/MigrationEndedListener.php b/src/Listeners/MigrationEndedListener.php new file mode 100644 index 00000000..44486727 --- /dev/null +++ b/src/Listeners/MigrationEndedListener.php @@ -0,0 +1,17 @@ +withOperation($event->migration)) { + $this->run($event->method, $operation); + } + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 78f28448..c26d7bfa 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -5,6 +5,9 @@ namespace DragonCode\LaravelDeployOperations; use DragonCode\LaravelDeployOperations\Concerns\HasAbout; +use DragonCode\LaravelDeployOperations\Listeners\MigrationEndedListener; +use Illuminate\Database\Events\MigrationEnded; +use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider as BaseServiceProvider; class ServiceProvider extends BaseServiceProvider @@ -21,6 +24,8 @@ public function boot(): void $this->registerCommands(); $this->registerMigrations(); } + + $this->registerEvents(); } public function register(): void @@ -42,6 +47,11 @@ protected function registerCommands(): void ]); } + protected function registerEvents(): void + { + Event::listen(MigrationEnded::class, MigrationEndedListener::class); + } + protected function registerMigrations(): void { $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); diff --git a/src/Services/MigratorService.php b/src/Services/MigratorService.php index 41f0ba46..97ccbbf3 100644 --- a/src/Services/MigratorService.php +++ b/src/Services/MigratorService.php @@ -19,6 +19,8 @@ use Illuminate\Support\Facades\DB; use Throwable; +use function file_exists; +use function is_file; use function method_exists; use function realpath; @@ -148,6 +150,10 @@ protected function disallowBefore(Operation $operation, OptionsData $options): b protected function resolvePath(string $filename, string $path): string { + if (file_exists($path) && is_file($path)) { + return $path; + } + $withExtension = Str::finish($filename, '.php'); if ($this->file->exists($withExtension) && $this->file->isFile($withExtension)) { diff --git a/tests/Commands/OperationsTest.php b/tests/Commands/OperationsTest.php index 6cdffebc..dec1e2ab 100644 --- a/tests/Commands/OperationsTest.php +++ b/tests/Commands/OperationsTest.php @@ -7,6 +7,7 @@ use DragonCode\LaravelDeployOperations\Constants\Names; use DragonCode\LaravelDeployOperations\Jobs\OperationJob; use Exception; +use Illuminate\Database\Console\Migrations\RollbackCommand; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Queue; use Illuminate\Support\Str; @@ -746,4 +747,47 @@ public function testSync() $this->assertDatabaseOperationHas($this->table, 'foo_bar'); $this->assertDatabaseOperationDoesntLike($this->table, 'every_time'); } + + public function testViaMigrationMethod() + { + $this->copyViaMigrations(); + + $table = 'test'; + + $this->artisan(Names::Install)->assertExitCode(0); + + $this->assertDatabaseCount($table, 0); + $this->assertDatabaseCount($this->table, 0); + $this->assertDatabaseOperationDoesntLike($this->table, 'custom'); + $this->assertDatabaseOperationDoesntLike($this->table, 'invoke'); + $this->assertDatabaseOperationDoesntLike($this->table, 'up_down'); + $this->assertDatabaseOperationDoesntLike($table, 'custom', column: 'value'); + $this->assertDatabaseOperationDoesntLike($table, 'invoke', column: 'value'); + $this->assertDatabaseOperationDoesntLike($table, 'up_down', column: 'value'); + + $this->loadMigrationsFrom(__DIR__ . '/../fixtures/migrations_with_operations'); + + $this->assertDatabaseCount($table, 2); + $this->assertDatabaseCount($this->table, 2); + $this->assertDatabaseOperationDoesntLike($this->table, 'custom'); + $this->assertDatabaseOperationHas($this->table, 'invoke'); + $this->assertDatabaseOperationHas($this->table, 'up_down'); + $this->assertDatabaseOperationDoesntLike($table, 'custom', column: 'value'); + $this->assertDatabaseOperationHas($table, 'invoke', column: 'value'); + $this->assertDatabaseOperationHas($table, 'up_down', column: 'value'); + + $this->artisan(RollbackCommand::class, [ + '--path' => __DIR__ . '/../fixtures/migrations_with_operations', + '--realpath' => true, + ])->assertSuccessful(); + + $this->assertDatabaseCount($table, 1); + $this->assertDatabaseCount($this->table, 0); + $this->assertDatabaseOperationDoesntLike($this->table, 'custom'); + $this->assertDatabaseOperationDoesntLike($this->table, 'invoke'); + $this->assertDatabaseOperationDoesntLike($this->table, 'up_down'); + $this->assertDatabaseOperationDoesntLike($table, 'custom', column: 'value'); + $this->assertDatabaseOperationHas($table, 'invoke', column: 'value'); + $this->assertDatabaseOperationDoesntLike($table, 'up_down', column: 'value'); + } } diff --git a/tests/Concerns/Files.php b/tests/Concerns/Files.php index f150d233..892b8db9 100644 --- a/tests/Concerns/Files.php +++ b/tests/Concerns/Files.php @@ -50,6 +50,14 @@ protected function copyDI(): void ); } + protected function copyViaMigrations(): void + { + File::copyDirectory( + __DIR__ . '/../fixtures/app/via_migrations', + $this->targetDirectory() + ); + } + protected function copySuccessFailureMethod(): void { File::copy( diff --git a/tests/fixtures/app/via_migrations/2025_03_31_213407_custom.php b/tests/fixtures/app/via_migrations/2025_03_31_213407_custom.php new file mode 100644 index 00000000..4e566652 --- /dev/null +++ b/tests/fixtures/app/via_migrations/2025_03_31_213407_custom.php @@ -0,0 +1,22 @@ +table()->insert([ + 'value' => $some->get('custom'), + ]); + } + + protected function table(): Builder + { + return DB::table('test'); + } +}; diff --git a/tests/fixtures/app/via_migrations/2025_03_31_234251_invoke.php b/tests/fixtures/app/via_migrations/2025_03_31_234251_invoke.php new file mode 100644 index 00000000..9a95574b --- /dev/null +++ b/tests/fixtures/app/via_migrations/2025_03_31_234251_invoke.php @@ -0,0 +1,22 @@ +table()->insert([ + 'value' => $some->get('invoke'), + ]); + } + + protected function table(): Builder + { + return DB::table('test'); + } +}; diff --git a/tests/fixtures/app/via_migrations/2025_03_31_234312_up_down.php b/tests/fixtures/app/via_migrations/2025_03_31_234312_up_down.php new file mode 100644 index 00000000..c500d993 --- /dev/null +++ b/tests/fixtures/app/via_migrations/2025_03_31_234312_up_down.php @@ -0,0 +1,29 @@ +table()->insert([ + 'value' => $some->get('up_down'), + ]); + } + + public function down(Some $some): void + { + $this->table() + ->where('value', $some->get('up_down')) + ->delete(); + } + + protected function table(): Builder + { + return DB::table('test'); + } +}; diff --git a/tests/fixtures/migrations_with_operations/2025_03_31_213847_call_invokable.php b/tests/fixtures/migrations_with_operations/2025_03_31_213847_call_invokable.php new file mode 100644 index 00000000..138e8a7b --- /dev/null +++ b/tests/fixtures/migrations_with_operations/2025_03_31_213847_call_invokable.php @@ -0,0 +1,16 @@ +