Skip to content

Commit 695a2da

Browse files
Prove workflow migration install paths
1 parent b21e786 commit 695a2da

3 files changed

Lines changed: 113 additions & 2 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class() extends Migration {
10+
public function up(): void
11+
{
12+
if (
13+
! Schema::hasTable('workflow_run_summaries')
14+
|| Schema::hasColumn('workflow_run_summaries', 'memo')
15+
) {
16+
return;
17+
}
18+
19+
Schema::table('workflow_run_summaries', static function (Blueprint $table): void {
20+
$table->json('memo')
21+
->nullable();
22+
});
23+
}
24+
25+
public function down(): void
26+
{
27+
// Intentionally no-op: fresh 2.0 installs create this column in the
28+
// base workflow_run_summaries migration, and rollback must not remove it.
29+
}
30+
};

tests/Feature/MigrationTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,31 @@ public function testScheduleHistoryMigrationCanResumeAfterPartialMysqlIndexFailu
110110
$this->assertTrue(Schema::hasIndex('workflow_schedule_history_events', ['event_type', 'recorded_at']));
111111
}
112112

113+
public function testRunSummaryMemoRepairMigrationAddsMissingMemoColumn(): void
114+
{
115+
$path = __DIR__ . '/../../src/migrations/2026_04_16_000158_repair_memo_on_workflow_run_summaries_table.php';
116+
117+
Schema::create('workflow_run_summaries', static function (Blueprint $table): void {
118+
$table->string('id', 26)
119+
->primary();
120+
$table->json('visibility_labels')
121+
->nullable();
122+
$table->timestamps(6);
123+
});
124+
125+
$this->assertTrue(Schema::hasTable('workflow_run_summaries'));
126+
$this->assertFalse(Schema::hasColumn('workflow_run_summaries', 'memo'));
127+
128+
$migration = include $path;
129+
$migration->up();
130+
131+
$this->assertTrue(Schema::hasColumn('workflow_run_summaries', 'memo'));
132+
133+
$migration->up();
134+
135+
$this->assertTrue(Schema::hasColumn('workflow_run_summaries', 'memo'));
136+
}
137+
113138
public function testItPreservesV1WorkflowDataAfterV2Migration()
114139
{
115140
// Set up v1 schema and data

tests/Unit/Providers/WorkflowServiceProviderTest.php

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,44 @@ public function testProviderLoadsPackageMigrationsForFreshApps(): void
109109
$this->assertTrue(Schema::hasTable('workflow_instances'));
110110
$this->assertTrue(Schema::hasTable('workflow_runs'));
111111
$this->assertTrue(Schema::hasTable('workflow_run_summaries'));
112+
$this->assertTrue(Schema::hasColumn('workflow_run_summaries', 'memo'));
112113
$this->assertTrue(Schema::hasTable('workflow_commands'));
113114
}
114115

116+
public function testPublishedMigrationsCanRunAsInstallSource(): void
117+
{
118+
$this->deletePublishedWorkflowMigrations();
119+
120+
try {
121+
Artisan::call('vendor:publish', [
122+
'--tag' => 'migrations',
123+
'--force' => true,
124+
]);
125+
126+
$migrationFiles = glob(database_path('migrations/*.php')) ?: [];
127+
$this->assertNotEmpty($migrationFiles, 'Migrations should be published');
128+
129+
Schema::dropAllTables();
130+
131+
$this->artisan('migrate:install')
132+
->run();
133+
134+
$this->artisan('migrate', [
135+
'--path' => database_path('migrations'),
136+
'--realpath' => true,
137+
])->run();
138+
139+
$this->assertTrue(Schema::hasTable('workflow_instances'));
140+
$this->assertTrue(Schema::hasTable('workflow_runs'));
141+
$this->assertTrue(Schema::hasTable('workflow_run_summaries'));
142+
$this->assertTrue(Schema::hasColumn('workflow_run_summaries', 'memo'));
143+
$this->assertTrue(Schema::hasTable('workflow_schedules'));
144+
$this->assertTrue(Schema::hasTable('workflow_schedule_history_events'));
145+
} finally {
146+
$this->deletePublishedWorkflowMigrations();
147+
}
148+
}
149+
115150
public function testCommandsAreRegistered(): void
116151
{
117152
$registeredCommands = array_keys(Artisan::all());
@@ -218,8 +253,17 @@ public function testLoopingEventSkipsWatchdogsBeforeWorkflowTablesExist(): void
218253
Cache::forget('workflow:watchdog:looping');
219254
Cache::forget(TaskWatchdog::LOOP_THROTTLE_KEY);
220255

221-
Schema::dropIfExists('workflows');
222-
Schema::dropIfExists('workflow_worker_compatibility_heartbeats');
256+
foreach ([
257+
'workflow_relationships',
258+
'workflow_exceptions',
259+
'workflow_timers',
260+
'workflow_signals',
261+
'workflow_logs',
262+
'workflows',
263+
'workflow_worker_compatibility_heartbeats',
264+
] as $table) {
265+
Schema::dropIfExists($table);
266+
}
223267

224268
Event::dispatch(new Looping('redis', 'default'));
225269

@@ -291,4 +335,16 @@ public function testLoopingEventRepairsOverdueV2Task(): void
291335
$this->assertSame(1, $task->repair_count);
292336
$this->assertNotNull($task->last_dispatched_at);
293337
}
338+
339+
private function deletePublishedWorkflowMigrations(): void
340+
{
341+
$sourceFiles = glob(dirname(__DIR__, 3) . '/src/migrations/*.php') ?: [];
342+
$publishedNames = array_fill_keys(array_map('basename', $sourceFiles), true);
343+
344+
foreach (glob(database_path('migrations/*.php')) ?: [] as $file) {
345+
if (isset($publishedNames[basename($file)])) {
346+
@unlink($file);
347+
}
348+
}
349+
}
294350
}

0 commit comments

Comments
 (0)