Merge pull request #3783 from ebean-orm/feature/init-migrations-do-not-overwrite

db-migration: Change I__ init scripts to NOT overwrite (allow customisation)
This commit is contained in:
Rob Bygrave
2026-06-13 10:33:38 +12:00
committed by GitHub
2 changed files with 67 additions and 3 deletions
@@ -397,12 +397,21 @@ public class DefaultDbMigration implements DbMigration {
}
/**
* Write (or override) the "repeatable" migration script.
* Write the "repeatable" or "init" migration script.
* <p>
* Repeatable ({@code R__}) scripts are always (re)written from their source
* (typically {@code extra-ddl.xml} views), but an init ({@code I__}) script is
* only written when it does not already exist. Init scripts run once to
* bootstrap a database and can be hand-tuned after first generation.
*/
private void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
String fullName = repeatableMigrationName(script.isInit(), script.getName());
logger.log(DEBUG, "writing repeatable script {0}", fullName);
File file = new File(migrationDir, fullName);
if (script.isInit() && file.exists()) {
logger.log(DEBUG, "skip existing init script {0}", fullName);
return;
}
logger.log(DEBUG, "writing repeatable script {0}", fullName);
try (Writer writer = IOUtils.newWriter(file)) {
writer.write(script.getValue());
writer.flush();
@@ -1,7 +1,15 @@
package io.ebeaninternal.dbmigration;
import io.ebeaninternal.extraddl.model.DdlScript;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -30,4 +38,51 @@ class DefaultDbMigrationTest {
migration.checkDropVersion("1.0", "1.0.0");
migration.checkDropVersion("1.0", "1.1");
}
@Test
void writeExtraDdl_initScript_notOverwrittenWhenExists(@TempDir Path dir) throws IOException {
File migrationDir = dir.toFile();
migration.writeExtraDdl(migrationDir, initScript("partition help", "ORIGINAL"));
File initFile = new File(migrationDir, "I__partition_help.sql");
assertThat(initFile).exists().content().isEqualTo("ORIGINAL");
// hand-tune the generated init script
Files.writeString(initFile.toPath(), "CUSTOMISED");
// regeneration must not clobber an existing init script
migration.writeExtraDdl(migrationDir, initScript("partition help", "ORIGINAL"));
assertThat(initFile).content().isEqualTo("CUSTOMISED");
}
@Test
void writeExtraDdl_repeatableScript_alwaysRewritten(@TempDir Path dir) throws IOException {
File migrationDir = dir.toFile();
migration.writeExtraDdl(migrationDir, repeatableScript("my view", "V1"));
File file = new File(migrationDir, "R__my_view.sql");
assertThat(file).exists().content().isEqualTo("V1");
Files.writeString(file.toPath(), "STALE");
// repeatable scripts are regenerated from their source every time
migration.writeExtraDdl(migrationDir, repeatableScript("my view", "V1"));
assertThat(file).content().isEqualTo("V1");
}
private static DdlScript initScript(String name, String value) {
return script(name, value, true);
}
private static DdlScript repeatableScript(String name, String value) {
return script(name, value, false);
}
private static DdlScript script(String name, String value, boolean init) {
DdlScript script = new DdlScript();
script.setName(name);
script.setValue(value);
script.setInit(init);
return script;
}
}