From 81b040ef02763c7cf7a3a3da1424b73177e9d433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 27 Oct 2026 00:30:08 +0500 Subject: [PATCH] Preserve database migration introduction order across merge commits --- ...0261027-merged-database-migration-order.md | 7 +++ crates/coa-core/src/release.rs | 52 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 changelog.d/20261027-merged-database-migration-order.md diff --git a/changelog.d/20261027-merged-database-migration-order.md b/changelog.d/20261027-merged-database-migration-order.md new file mode 100644 index 0000000..13f46b0 --- /dev/null +++ b/changelog.d/20261027-merged-database-migration-order.md @@ -0,0 +1,7 @@ +--- +area: manager +type: fixed +audience: admins +title: Server updates preserve the order of database migrations added during merges +--- +Older database snapshots no longer run after newer updates when preparing server packages. This prevents outdated Manastorm reward ranges from overwriting newer progression data. diff --git a/crates/coa-core/src/release.rs b/crates/coa-core/src/release.rs index 96010af..906cf3c 100644 --- a/crates/coa-core/src/release.rs +++ b/crates/coa-core/src/release.rs @@ -39,6 +39,8 @@ fn sql_in(dir: &Path) -> Vec { fn introduction_rank(repo: &Path, pathspecs: &[&str]) -> std::collections::HashMap { let mut args = vec![ "log", + "--full-history", + "--diff-merges=first-parent", "--reverse", "--diff-filter=A", "--name-only", @@ -306,6 +308,56 @@ pub fn revision(commit: &str) -> Revision { mod tests { use super::*; + #[test] + fn migrations_added_by_a_merge_precede_later_dependent_updates() { + let directory = tempfile::tempdir().unwrap(); + let root = directory.path(); + let git = |args: &[&str]| { + let output = Command::new("git") + .current_dir(root) + .args(args) + .output() + .unwrap(); + assert!( + output.status.success(), + "git {args:?}: {}", + String::from_utf8_lossy(&output.stderr) + ); + }; + git(&["init", "-b", "main"]); + git(&["config", "user.name", "Migration Test"]); + git(&["config", "user.email", "migration-test@example.invalid"]); + write( + root, + "data/sql/updates/pending_db_world/00_schema.sql", + "SELECT 1;", + ); + git(&["add", "."]); + git(&["commit", "-m", "schema"]); + git(&["switch", "-c", "side"]); + git(&["commit", "--allow-empty", "-m", "side"]); + git(&["switch", "main"]); + git(&["commit", "--allow-empty", "-m", "main"]); + git(&["merge", "--no-ff", "--no-commit", "side"]); + write( + root, + "data/sql/updates/pending_db_world/10_snapshot.sql", + "SELECT 2;", + ); + git(&["add", "."]); + git(&["commit", "-m", "merge with snapshot"]); + write( + root, + "data/sql/updates/pending_db_world/20_progression.sql", + "SELECT 3;", + ); + git(&["add", "."]); + git(&["commit", "-m", "new progression"]); + let sql = collect_core_sql(root).unwrap(); + let ids: Vec<_> = sql.iter().map(|file| file.id.as_str()).collect(); + assert_eq!(ids, ["00_schema", "10_snapshot", "20_progression"]); + } + fn write(root: &Path, rel: &str, c: &str) { let p = root.join(rel); fs::create_dir_all(p.parent().unwrap()).unwrap();