diff --git a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json index e7ed0aee65..d29a18c691 100644 --- a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json +++ b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json @@ -46,11 +46,11 @@ ] }, "nullable": [ - false, - false, - false, - false, - false, + true, + true, + true, + true, + true, true, true ] diff --git a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json index 36ddb8ab9f..713ccb9dd3 100644 --- a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json +++ b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - true + null ] }, "hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55" diff --git a/backend/.sqlx/query-aef927110ef4cff51d3faabb0c389730dd215f4e90d105f0e86025f0ac42f020.json b/backend/.sqlx/query-aef927110ef4cff51d3faabb0c389730dd215f4e90d105f0e86025f0ac42f020.json new file mode 100644 index 0000000000..2a90d12ad0 --- /dev/null +++ b/backend/.sqlx/query-aef927110ef4cff51d3faabb0c389730dd215f4e90d105f0e86025f0ac42f020.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO datatable_migrations (workspace_id, datatable, timestamp, name, code_up, code_down)\n SELECT $2, datatable, timestamp, name, code_up, code_down\n FROM datatable_migrations WHERE workspace_id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "aef927110ef4cff51d3faabb0c389730dd215f4e90d105f0e86025f0ac42f020" +} diff --git a/backend/windmill-api-workspaces/src/datatable_migrations.rs b/backend/windmill-api-workspaces/src/datatable_migrations.rs index c89e5720ca..e2d1cf3243 100644 --- a/backend/windmill-api-workspaces/src/datatable_migrations.rs +++ b/backend/windmill-api-workspaces/src/datatable_migrations.rs @@ -1345,6 +1345,25 @@ pub(crate) async fn cascade_datatable_migration_renames_and_deletes( Ok(()) } +/// Copy a workspace's migration definitions to another workspace, so a fork +/// inherits the same per-data-table migration history as its parent. +pub(crate) async fn clone_datatable_migrations( + tx: &mut Transaction<'_, Postgres>, + source_workspace_id: &str, + target_workspace_id: &str, +) -> Result<()> { + sqlx::query!( + "INSERT INTO datatable_migrations (workspace_id, datatable, timestamp, name, code_up, code_down) + SELECT $2, datatable, timestamp, name, code_up, code_down + FROM datatable_migrations WHERE workspace_id = $1", + source_workspace_id, + target_workspace_id, + ) + .execute(&mut **tx) + .await?; + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -1492,4 +1511,38 @@ mod tests { ] ); } + + // A fork inherits its parent's migration definitions unchanged. + #[sqlx::test(migrations = "../migrations")] + async fn clone_copies_datatable_migrations_to_target(pool: DB) { + let src = format!("src{}", uuid::Uuid::new_v4().simple()); + let dst = format!("dst{}", uuid::Uuid::new_v4().simple()); + for w in [&src, &dst] { + sqlx::query( + "INSERT INTO workspace (id, name, owner) VALUES ($1, $1, 'test@windmill.dev')", + ) + .bind(w) + .execute(&pool) + .await + .unwrap(); + } + seed_migration(&pool, &src, "customers", 1, "create_customers").await; + seed_migration(&pool, &src, "customers", 2, "add_index").await; + seed_migration(&pool, &src, "orders", 3, "create_orders").await; + + let mut tx = pool.begin().await.unwrap(); + clone_datatable_migrations(&mut tx, &src, &dst) + .await + .unwrap(); + tx.commit().await.unwrap(); + + // the target ends up with an identical set, and the source is untouched. + let expected = vec![ + ("customers".to_string(), "create_customers".to_string()), + ("customers".to_string(), "add_index".to_string()), + ("orders".to_string(), "create_orders".to_string()), + ]; + assert_eq!(migration_keys(&pool, &dst).await, expected); + assert_eq!(migration_keys(&pool, &src).await, expected); + } } diff --git a/backend/windmill-api-workspaces/src/workspaces.rs b/backend/windmill-api-workspaces/src/workspaces.rs index db5a56cec0..8544513d01 100644 --- a/backend/windmill-api-workspaces/src/workspaces.rs +++ b/backend/windmill-api-workspaces/src/workspaces.rs @@ -3974,6 +3974,15 @@ async fn clone_workspace_data( // Clone workspace settings (merge with existing basic settings) update_workspace_settings(tx, source_workspace_id, target_workspace_id).await?; + // Clone data table migration definitions (the settings above carry the data + // table config; this carries their migration history). + crate::datatable_migrations::clone_datatable_migrations( + tx, + source_workspace_id, + target_workspace_id, + ) + .await?; + // Clone workspace environment variables clone_workspace_env(tx, source_workspace_id, target_workspace_id).await?;