Skip to content

Commit 3448f10

Browse files
authored
Merge pull request #215 from zonkyio/flyway-8-plus
#207 Fix compatibility with Flyway 8 and above
2 parents b5a0bd6 + 594ca9c commit 3448f10

File tree

7 files changed

+84
-20
lines changed

7 files changed

+84
-20
lines changed

build.gradle

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ext {
2020
[name: '5.0.20', spring: '5.0.20.RELEASE', 'zonky-postgres': 'default', opentable: 'default', yandex: 'default', 'mssql-driver': 'default', 'mysql-driver': 'default', 'mariadb-driver': 'default', 'h2': 'default'],
2121
[name: '5.1.20', spring: '5.1.20.RELEASE', 'zonky-postgres': 'default', opentable: 'default', yandex: 'default', 'mssql-driver': 'default', 'mysql-driver': 'default', 'mariadb-driver': 'default', 'h2': 'default'],
2222
[name: '5.2.22', spring: '5.2.22.RELEASE', 'zonky-postgres': 'default', opentable: 'default', yandex: 'default', 'mssql-driver': 'default', 'mysql-driver': 'default', 'mariadb-driver': 'default', 'h2': 'default'],
23-
[name: '5.3.22', spring: '5.3.22', 'zonky-postgres': 'default', opentable: 'default', yandex: 'default', 'mssql-driver': 'default', 'mysql-driver': 'default', 'mariadb-driver': 'default', 'h2': 'default']
23+
[name: '5.3.23', spring: '5.3.23', 'zonky-postgres': 'default', opentable: 'default', yandex: 'default', 'mssql-driver': 'default', 'mysql-driver': 'default', 'mariadb-driver': 'default', 'h2': 'default']
2424
]],
2525
[name: 'flyway', versions: [
2626
[name: '4.0.3', flyway: '4.0.3', 'flyway-test': '4.0.1', spring: '4.3.30.RELEASE', 'spring-boot': '1.5.22.RELEASE', 'zonky-postgres': 'default'],
@@ -32,10 +32,12 @@ ext {
3232
[name: '6.0.7', flyway: '6.0.6', 'flyway-test': '6.0.0', spring: '5.2.22.RELEASE', 'spring-boot': '2.2.13.RELEASE', 'zonky-postgres': 'default'],
3333
[name: '6.3.3', flyway: '6.3.3', 'flyway-test': '6.3.3', spring: '5.2.22.RELEASE', 'spring-boot': '2.2.13.RELEASE', 'zonky-postgres': 'default'],
3434
[name: '6.5.7', flyway: '6.5.7', 'flyway-test': '6.4.0', spring: '5.2.22.RELEASE', 'spring-boot': '2.2.13.RELEASE', 'zonky-postgres': 'default'],
35-
[name: '7.6.0', flyway: '7.6.0', 'flyway-test': '7.0.0', spring: '5.3.22', 'spring-boot': '2.4.13', 'zonky-postgres': 'default'],
36-
[name: '7.15.0', flyway: '7.15.0', 'flyway-test': '7.0.0', spring: '5.3.22', 'spring-boot': '2.5.14', 'zonky-postgres': 'default'],
37-
// [name: '8.0.5', flyway: '8.0.5', 'flyway-test': '7.0.0', spring: '5.3.22', 'spring-boot': '2.6.11', 'zonky-postgres': 'default'],
38-
// [name: '8.5.13', flyway: '8.5.13', 'flyway-test': '7.0.0', spring: '5.3.22', 'spring-boot': '2.7.3', 'zonky-postgres': 'default'],
35+
[name: '7.6.0', flyway: '7.6.0', 'flyway-test': '7.0.0', spring: '5.3.23', 'spring-boot': '2.4.13', 'zonky-postgres': 'default'],
36+
[name: '7.15.0', flyway: '7.15.0', 'flyway-test': '7.0.0', spring: '5.3.23', 'spring-boot': '2.5.14', 'zonky-postgres': 'default'],
37+
[name: '8.0.5', flyway: '8.0.5', 'flyway-test': '7.0.0', spring: '5.3.23', 'spring-boot': '2.6.13', 'zonky-postgres': 'default'],
38+
[name: '8.5.13', flyway: '8.5.13', 'flyway-test': '7.0.0', spring: '5.3.23', 'spring-boot': '2.7.5', 'zonky-postgres': 'default'],
39+
[name: '9.0.4', flyway: '9.0.4', 'flyway-test': '7.0.0', spring: '5.3.23', 'spring-boot': '2.7.5', 'zonky-postgres': 'default'],
40+
[name: '9.8.2', flyway: '9.8.2', 'flyway-test': '7.0.0', spring: '5.3.23', 'spring-boot': '2.7.5', 'zonky-postgres': 'default'],
3941
[name: 'no_sb', flyway: 'default', 'flyway-test': 'default', 'zonky-postgres': 'default']
4042
]],
4143
[name: 'liquibase', versions: [
@@ -44,10 +46,10 @@ ext {
4446
[name: '3.7.0', liquibase: '3.7.0', spring: '5.1.20.RELEASE', 'spring-boot': '2.1.18.RELEASE'],
4547
[name: '3.8.9', liquibase: '3.8.9', spring: '5.2.22.RELEASE', 'spring-boot': '2.2.13.RELEASE'],
4648
[name: '3.9.0', liquibase: '3.9.0', spring: '5.2.22.RELEASE', 'spring-boot': '2.2.13.RELEASE'],
47-
[name: '3.10.3', liquibase: '3.10.3', spring: '5.3.22', 'spring-boot': '2.4.13'],
48-
[name: '4.4.3', liquibase: '4.4.3', spring: '5.3.22', 'spring-boot': '2.5.14'],
49-
[name: '4.5.0', liquibase: '4.5.0', spring: '5.3.22', 'spring-boot': '2.6.11'],
50-
[name: '4.9.1', liquibase: '4.9.1', spring: '5.3.22', 'spring-boot': '2.7.3'],
49+
[name: '3.10.3', liquibase: '3.10.3', spring: '5.3.23', 'spring-boot': '2.4.13'],
50+
[name: '4.4.3', liquibase: '4.4.3', spring: '5.3.23', 'spring-boot': '2.5.14'],
51+
[name: '4.5.0', liquibase: '4.5.0', spring: '5.3.23', 'spring-boot': '2.6.11'],
52+
[name: '4.9.1', liquibase: '4.9.1', spring: '5.3.23', 'spring-boot': '2.7.3'],
5153
[name: 'no_sb', liquibase: 'default']
5254
]],
5355
[name: 'postgres', versions: [
@@ -211,7 +213,7 @@ project(':embedded-database-spring-test') {
211213
compile 'org.mariadb.jdbc:mariadb-java-client:2.7.6', optional
212214
compile 'com.h2database:h2:2.1.214', optional
213215

214-
compile 'org.flywaydb:flyway-core:7.15.0', optional
216+
compile 'org.flywaydb:flyway-core:9.8.2', optional
215217
compile 'org.flywaydb.flyway-test-extensions:flyway-spring-test:7.0.0', optional
216218
compile('org.springframework.boot:spring-boot-starter-test:2.0.9.RELEASE') {
217219
exclude group: 'org.mockito'

embedded-database-spring-test/src/main/java/io/zonky/test/db/flyway/FlywayClassUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private static int loadFlywayVersion() {
3434
try {
3535
ClassPathResource versionResource = new ClassPathResource("org/flywaydb/core/internal/version.txt", FlywayClassUtils.class.getClassLoader());
3636
if (versionResource.exists()) {
37-
return Integer.parseInt(StreamUtils.copyToString(versionResource.getInputStream(), UTF_8).replaceAll("^(\\d+)\\.(\\d+).*", "$1$2"));
37+
return Integer.parseInt(StreamUtils.copyToString(versionResource.getInputStream(), UTF_8).replaceAll("^(\\d+)\\.\\d{2,}", "$1.9").replaceAll("^(\\d+)\\.(\\d).*", "$1$2"));
3838
} else if (ClassUtils.hasMethod(Flyway.class, "isPlaceholderReplacement")) {
3939
return 32;
4040
} else if (ClassUtils.hasMethod(Flyway.class, "getBaselineVersion")) {

embedded-database-spring-test/src/main/java/io/zonky/test/db/flyway/FlywayDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class FlywayDescriptor {
5050
);
5151

5252
private static final Set<String> EXCLUDED_FIELDS = ImmutableSet.of(
53-
"dbConnectionInfoPrinted", "classScanner"
53+
"cleanDisabled", "dbConnectionInfoPrinted", "classScanner", "pluginRegister"
5454
);
5555

5656
private static final Set<Class<?>> EXCLUDED_TYPES = ImmutableSet.of(

embedded-database-spring-test/src/main/java/io/zonky/test/db/flyway/FlywayWrapper.java

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.flywaydb.core.api.resolver.ResolvedMigration;
2424
import org.springframework.aop.framework.ProxyFactory;
2525
import org.springframework.util.ClassUtils;
26+
import org.springframework.util.ObjectUtils;
2627

2728
import javax.sql.DataSource;
2829
import java.util.Arrays;
@@ -93,7 +94,10 @@ public Collection<ResolvedMigration> getMigrations() {
9394
Flyway flyway = getUltimateTargetObject(this.flyway);
9495
MigrationResolver resolver = createMigrationResolver(flyway);
9596

96-
if (flywayVersion >= 52) {
97+
if (flywayVersion >= 90) {
98+
Object contextInstance = invokeConstructor("org.flywaydb.core.api.resolver.MigrationResolver.Context", config, null, null, null, null);
99+
return invokeMethod(resolver, "resolveMigrations", contextInstance);
100+
} else if (flywayVersion >= 52) {
97101
Class<?> contextType = ClassUtils.forName("org.flywaydb.core.api.resolver.Context", classLoader);
98102
Object contextInstance = ProxyFactory.getProxy(contextType, (MethodInterceptor) invocation ->
99103
"getConfiguration".equals(invocation.getMethod().getName()) ? config : invocation.proceed());
@@ -107,7 +111,21 @@ public Collection<ResolvedMigration> getMigrations() {
107111
}
108112

109113
private MigrationResolver createMigrationResolver(Flyway flyway) throws ClassNotFoundException {
110-
if (flywayVersion >= 63) {
114+
if (flywayVersion >= 90) {
115+
Object executor = getField(flyway, "flywayExecutor");
116+
Object scanner = createScanner(flyway);
117+
Object sqlScriptFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptFactory");
118+
Object sqlScriptExecutorFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptExecutorFactory");
119+
Object parsingContext = invokeConstructor("org.flywaydb.core.internal.parser.ParsingContext");
120+
return invokeMethod(executor, "createMigrationResolver", scanner, scanner, sqlScriptExecutorFactory, sqlScriptFactory, parsingContext, null);
121+
} else if (flywayVersion >= 80) {
122+
Object executor = getField(flyway, "flywayExecutor");
123+
Object scanner = createScanner(flyway);
124+
Object sqlScriptFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptFactory");
125+
Object sqlScriptExecutorFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptExecutorFactory");
126+
Object parsingContext = invokeConstructor("org.flywaydb.core.internal.parser.ParsingContext");
127+
return invokeMethod(executor, "createMigrationResolver", scanner, scanner, sqlScriptExecutorFactory, sqlScriptFactory, parsingContext);
128+
} else if (flywayVersion >= 63) {
111129
Object scanner = createScanner(flyway);
112130
Object sqlScriptFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptFactory");
113131
Object sqlScriptExecutorFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptExecutorFactory");
@@ -136,6 +154,19 @@ private MigrationResolver createMigrationResolver(Flyway flyway) throws ClassNot
136154
}
137155

138156
private Object createScanner(Flyway flyway) throws ClassNotFoundException {
157+
if (flywayVersion >= 80) {
158+
Object executor = getField(flyway, "flywayExecutor");
159+
return invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
160+
ClassUtils.forName("org.flywaydb.core.api.migration.JavaMigration", classLoader),
161+
Arrays.asList((Object[]) invokeMethod(config, "getLocations")),
162+
invokeMethod(config, "getClassLoader"),
163+
invokeMethod(config, "getEncoding"),
164+
invokeMethod(config, "isDetectEncoding"),
165+
false,
166+
getField(executor, "resourceNameCache"),
167+
getField(executor, "locationScannerCache"),
168+
invokeMethod(config, "isFailOnMissingLocations"));
169+
}
139170
if (flywayVersion >= 79) {
140171
return invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
141172
ClassUtils.forName("org.flywaydb.core.api.migration.JavaMigration", classLoader),
@@ -305,31 +336,46 @@ public void setSqlMigrationSuffixes(List<String> sqlMigrationSuffixes) {
305336
}
306337

307338
public boolean isIgnoreMissingMigrations() {
308-
if (flywayVersion >= 41) {
339+
if (flywayVersion >= 90) {
340+
Object[] patterns = getArray(config, "getIgnoreMigrationPatterns");
341+
return patterns.length > 0 && "*".equals(getField(patterns[patterns.length - 1], "migrationType")) && "missing".equalsIgnoreCase(getField(patterns[patterns.length - 1], "migrationState"));
342+
} else if (flywayVersion >= 41) {
309343
return getValue(config, "isIgnoreMissingMigrations");
310344
} else {
311345
return false;
312346
}
313347
}
314348

315349
public void setIgnoreMissingMigrations(boolean ignoreMissingMigrations) {
316-
if (flywayVersion >= 41) {
350+
if (flywayVersion >= 90) {
351+
Object[] patterns = getArray(config, "getIgnoreMigrationPatterns");
352+
if (isIgnoreMissingMigrations() && !ignoreMissingMigrations) {
353+
setValue(config, "setIgnoreMigrationPatterns", Arrays.copyOf(patterns, patterns.length - 1));
354+
} else if (!isIgnoreMissingMigrations() && ignoreMissingMigrations) {
355+
try {
356+
Object ignorePattern = invokeStaticMethod("org.flywaydb.core.api.pattern.ValidatePattern", "fromPattern", "*:missing");
357+
setValue(config, "setIgnoreMigrationPatterns", ObjectUtils.addObjectToArray(patterns, ignorePattern));
358+
} catch (ClassNotFoundException e) {
359+
throw new IllegalStateException("Class not found: " + e.getMessage());
360+
}
361+
}
362+
} else if (flywayVersion >= 41) {
317363
setValue(config, "setIgnoreMissingMigrations", ignoreMissingMigrations);
318364
} else if (!Objects.equals(ignoreMissingMigrations, isIgnoreMissingMigrations())) {
319365
throw new UnsupportedOperationException("This method is not supported in current Flyway version");
320366
}
321367
}
322368

323369
public boolean isIgnoreFutureMigrations() {
324-
if (flywayVersion >= 40) {
370+
if (flywayVersion >= 40 && flywayVersion < 90) {
325371
return getValue(config, "isIgnoreFutureMigrations");
326372
} else {
327373
return true;
328374
}
329375
}
330376

331377
public void setIgnoreFutureMigrations(boolean ignoreFutureMigrations) {
332-
if (flywayVersion >= 40) {
378+
if (flywayVersion >= 40 && flywayVersion < 90) {
333379
setValue(config, "setIgnoreFutureMigrations", ignoreFutureMigrations);
334380
} else if (!Objects.equals(ignoreFutureMigrations, isIgnoreFutureMigrations())) {
335381
throw new UnsupportedOperationException("This method is not supported in current Flyway version");
@@ -344,6 +390,14 @@ public void setValidateOnMigrate(boolean validateOnMigrate) {
344390
setValue(config, "setValidateOnMigrate", validateOnMigrate);
345391
}
346392

393+
public boolean isCleanDisabled() {
394+
return getValue(config, "isCleanDisabled");
395+
}
396+
397+
public void setCleanDisabled(boolean cleanDisabled) {
398+
setValue(config, "setCleanDisabled", cleanDisabled);
399+
}
400+
347401
private static <T> T getValue(Object target, String method) {
348402
return invokeMethod(target, method);
349403
}

embedded-database-spring-test/src/main/java/io/zonky/test/db/flyway/preparer/CleanFlywayDatabasePreparer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public long estimatedDuration() {
3232

3333
@Override
3434
protected Object doOperation(FlywayWrapper wrapper) {
35+
wrapper.setCleanDisabled(false);
3536
return wrapper.clean();
3637
}
3738
}

embedded-database-spring-test/src/main/java/io/zonky/test/db/util/ReflectionUtils.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ public static <T> T invokeMethod(Object targetObject, String name, Object... arg
7979
}
8080
}
8181

82+
public static <T> T invokeStaticMethod(String className, String name, Object... args) throws ClassNotFoundException {
83+
Assert.notNull(className, "Target class must not be null");
84+
85+
Class<?> targetClass = ClassUtils.forName(className, null);
86+
return invokeStaticMethod(targetClass, name, args);
87+
}
88+
8289
@SuppressWarnings("unchecked")
8390
public static <T> T invokeStaticMethod(Class<?> targetClass, String name, Object... args) {
8491
Assert.notNull(targetClass, "Target class must not be null");

embedded-database-spring-test/src/test/java/io/zonky/test/db/flyway/FlywayDescriptorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void testBasicFields() {
3333
wrapper1.setSqlMigrationSeparator("---");
3434
wrapper1.setSqlMigrationSuffixes(ImmutableList.of(".xql"));
3535
wrapper1.setIgnoreMissingMigrations(flywayVersion >= 41);
36-
wrapper1.setIgnoreFutureMigrations(flywayVersion < 40);
36+
wrapper1.setIgnoreFutureMigrations(flywayVersion < 40 || flywayVersion >= 90);
3737
wrapper1.setValidateOnMigrate(false);
3838

3939
FlywayWrapper wrapper2 = FlywayWrapper.newInstance();
@@ -45,7 +45,7 @@ public void testBasicFields() {
4545
wrapper2.setSqlMigrationSeparator("---");
4646
wrapper2.setSqlMigrationSuffixes(ImmutableList.of(".xql"));
4747
wrapper2.setIgnoreMissingMigrations(flywayVersion >= 41);
48-
wrapper2.setIgnoreFutureMigrations(flywayVersion < 40);
48+
wrapper2.setIgnoreFutureMigrations(flywayVersion < 40 || flywayVersion >= 90);
4949
wrapper2.setValidateOnMigrate(false);
5050

5151
FlywayDescriptor descriptor1 = FlywayDescriptor.from(wrapper1);

0 commit comments

Comments
 (0)