Skip to content

Commit d130e53

Browse files
authored
Merge pull request #256 from zonkyio/flyway-9.9-plus
Support Flyway 9.9 - 10.5
2 parents df1f12b + efa9ec0 commit d130e53

15 files changed

+468
-255
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
java: [8, 11, 15]
10+
java: [8, 11, 17]
1111
steps:
1212
- name: Checkout project
1313
uses: actions/checkout@v3

build.gradle

Lines changed: 146 additions & 99 deletions
Large diffs are not rendered by default.

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,30 @@
2626

2727
public class FlywayClassUtils {
2828

29-
private static final int flywayVersion = loadFlywayVersion();
29+
private static final FlywayVersion flywayVersion = loadFlywayVersion();
3030

3131
private FlywayClassUtils() {}
3232

33-
private static int loadFlywayVersion() {
33+
private static FlywayVersion 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{2,}", "$1.9").replaceAll("^(\\d+)\\.(\\d).*", "$1$2"));
37+
String version = StreamUtils.copyToString(versionResource.getInputStream(), UTF_8);
38+
return FlywayVersion.parseVersion(version);
3839
} else if (ClassUtils.hasMethod(Flyway.class, "isPlaceholderReplacement")) {
39-
return 32;
40+
return FlywayVersion.parseVersion("3.2");
4041
} else if (ClassUtils.hasMethod(Flyway.class, "getBaselineVersion")) {
41-
return 31;
42+
return FlywayVersion.parseVersion("3.1");
4243
} else {
43-
return 30;
44+
return FlywayVersion.parseVersion("3.0");
4445
}
4546
} catch (Exception e) {
4647
LoggerFactory.getLogger(FlywayClassUtils.class).error("Unexpected error when resolving flyway version", e);
47-
return 0;
48+
return FlywayVersion.parseVersion("0");
4849
}
4950
}
5051

51-
public static int getFlywayVersion() {
52+
public static FlywayVersion getFlywayVersion() {
5253
return flywayVersion;
5354
}
5455
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161

6262
public class FlywayDatabaseExtension implements BeanPostProcessor {
6363

64-
private static final int flywayVersion = FlywayClassUtils.getFlywayVersion();
64+
private static final FlywayVersion flywayVersion = FlywayClassUtils.getFlywayVersion();
6565

6666
private static final ConcurrentMap<FlywayDescriptor, Collection<ResolvedMigration>> resolvedMigrationsCache = new ConcurrentHashMap<>();
6767

@@ -196,7 +196,7 @@ protected Object apply(Function<FlywayDescriptor, FlywayDatabasePreparer> creato
196196
try {
197197
return preparer.getResult().get(0, TimeUnit.MILLISECONDS);
198198
} catch (InterruptedException | ExecutionException | TimeoutException e) {
199-
if (preparer instanceof MigrateFlywayDatabasePreparer && flywayVersion < 70) {
199+
if (preparer instanceof MigrateFlywayDatabasePreparer && flywayVersion.isLessThan("7")) {
200200
return 0;
201201
}
202202
}
@@ -267,7 +267,7 @@ protected void applyTestMigrations(FlywayOperation operation) {
267267
List<String> defaultLocations = flywayWrapper.getLocations();
268268
boolean ignoreMissingMigrations = flywayWrapper.isIgnoreMissingMigrations();
269269
try {
270-
if (flywayVersion >= 41) {
270+
if (flywayVersion.isGreaterThanOrEqualTo("4.1")) {
271271
flywayWrapper.setLocations(testLocations);
272272
flywayWrapper.setIgnoreMissingMigrations(true);
273273

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

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public class FlywayDescriptor {
7878
private final boolean ignoreFutureMigrations;
7979
private final boolean validateOnMigrate;
8080
private final Map<Field, Object> otherFields;
81+
private final Map<Field, Object> envConfFields;
8182
private final Map<Class<?>, Map<Field, Object>> pluginsFields;
8283

8384
private FlywayDescriptor(FlywayWrapper wrapper) {
@@ -93,6 +94,7 @@ private FlywayDescriptor(FlywayWrapper wrapper) {
9394
this.validateOnMigrate = wrapper.isValidateOnMigrate();
9495

9596
this.otherFields = getFields(wrapper.getConfig(), OTHER_FIELDS);
97+
this.envConfFields = getFields(wrapper.getEnvConfig(), PLUGIN_FIELDS);
9698

9799
Map<Class<?>, Map<Field, Object>> pluginsFields = new HashMap<>();
98100
List<Object> plugins = wrapper.getConfigurationExtensions();
@@ -108,8 +110,6 @@ public static FlywayDescriptor from(FlywayWrapper wrapper) {
108110
}
109111

110112
public void applyTo(FlywayWrapper wrapper) {
111-
Object config = wrapper.getConfig();
112-
113113
wrapper.setLocations(locations);
114114
wrapper.setSchemas(schemas);
115115
wrapper.setTable(table);
@@ -121,7 +121,8 @@ public void applyTo(FlywayWrapper wrapper) {
121121
wrapper.setIgnoreFutureMigrations(ignoreFutureMigrations);
122122
wrapper.setValidateOnMigrate(validateOnMigrate);
123123

124-
setFields(config, otherFields);
124+
setFields(wrapper.getConfig(), otherFields);
125+
setFields(wrapper.getEnvConfig(), envConfFields);
125126

126127
List<Object> plugins = wrapper.getConfigurationExtensions();
127128
for (Object plugin : plugins) {
@@ -186,6 +187,7 @@ public boolean equals(Object o) {
186187
&& Objects.equals(sqlMigrationSeparator, that.sqlMigrationSeparator)
187188
&& Objects.equals(sqlMigrationSuffixes, that.sqlMigrationSuffixes)
188189
&& Objects.equals(otherFields, that.otherFields)
190+
&& Objects.equals(envConfFields, that.envConfFields)
189191
&& Objects.equals(pluginsFields, that.pluginsFields);
190192
}
191193

@@ -195,27 +197,31 @@ public int hashCode() {
195197
sqlMigrationPrefix, repeatableSqlMigrationPrefix,
196198
sqlMigrationSeparator, sqlMigrationSuffixes,
197199
ignoreMissingMigrations, ignoreFutureMigrations,
198-
validateOnMigrate, otherFields, pluginsFields);
200+
validateOnMigrate, otherFields, envConfFields, pluginsFields);
199201
}
200202

201203
private static void setCollection(Field field, Object target, Collection<?> value) {
202204
Collection collection = (Collection) getField(field, target);
203205
if (collection != null) {
204-
collection.clear();
205-
collection.addAll(value);
206-
} else {
207-
setField(field, target, value);
206+
try {
207+
collection.clear();
208+
collection.addAll(value);
209+
return;
210+
} catch (UnsupportedOperationException e) {}
208211
}
212+
setField(field, target, Lists.newArrayList(value));
209213
}
210214

211215
private static void setMap(Field field, Object target, Map<?, ?> value) {
212216
Map map = (Map) getField(field, target);
213217
if (map != null) {
214-
map.clear();
215-
map.putAll(value);
216-
} else {
217-
setField(field, target, value);
218+
try {
219+
map.clear();
220+
map.putAll(value);
221+
return;
222+
} catch (UnsupportedOperationException e) {}
218223
}
224+
setField(field, target, Maps.newHashMap(value));
219225
}
220226

221227
private static void setArray(Field field, Object config, List<?> value) {
@@ -227,28 +233,34 @@ private static void setArray(Field field, Object config, List<?> value) {
227233
private static Map<Field, Object> getFields(Object targetObject, FieldFilter fieldFilter) {
228234
Map<Field, Object> fieldValues = new HashMap<>();
229235

230-
Class<?> objectClass = targetObject.getClass();
231-
doWithFields(objectClass, field -> {
232-
makeAccessible(field);
233-
Object value = getField(field, targetObject);
234-
235-
if (value != null) {
236-
if (Collection.class.isAssignableFrom(field.getType())) {
237-
value = Lists.newArrayList((Collection<?>) value);
238-
} else if (Map.class.isAssignableFrom(field.getType())) {
239-
value = Maps.newHashMap((Map<?, ?>) value);
240-
} else if (field.getType().isArray()) {
241-
value = Lists.newArrayList((Object[]) value);
236+
if (targetObject != null) {
237+
Class<?> objectClass = targetObject.getClass();
238+
doWithFields(objectClass, field -> {
239+
makeAccessible(field);
240+
Object value = getField(field, targetObject);
241+
242+
if (value != null) {
243+
if (Collection.class.isAssignableFrom(field.getType())) {
244+
value = Lists.newArrayList((Collection<?>) value);
245+
} else if (Map.class.isAssignableFrom(field.getType())) {
246+
value = Maps.newHashMap((Map<?, ?>) value);
247+
} else if (field.getType().isArray()) {
248+
value = Lists.newArrayList((Object[]) value);
249+
}
242250
}
243-
}
244251

245-
fieldValues.put(field, value);
246-
}, fieldFilter);
252+
fieldValues.put(field, value);
253+
}, fieldFilter);
254+
}
247255

248256
return fieldValues;
249257
}
250258

251259
private static void setFields(Object targetObject, Map<Field, Object> fieldValues) {
260+
if (targetObject == null) {
261+
return;
262+
}
263+
252264
fieldValues.forEach((field, value) -> {
253265
makeAccessible(field);
254266

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.zonky.test.db.flyway;
18+
19+
import java.util.Arrays;
20+
import java.util.stream.Collectors;
21+
22+
public class FlywayVersion implements Comparable<FlywayVersion> {
23+
24+
private final int[] parts;
25+
26+
public static FlywayVersion parseVersion(String version) {
27+
String[] split = version.split("\\.");
28+
int[] parts = Arrays.stream(split).mapToInt(Integer::parseInt).toArray();
29+
return new FlywayVersion(parts);
30+
}
31+
32+
private FlywayVersion(int[] parts) {
33+
this.parts = parts;
34+
}
35+
36+
public boolean isGreaterThan(String version) {
37+
return compareTo(parseVersion(version)) > 0;
38+
}
39+
40+
public boolean isGreaterThanOrEqualTo(String version) {
41+
return compareTo(parseVersion(version)) >= 0;
42+
}
43+
44+
public boolean isLessThan(String version) {
45+
return compareTo(parseVersion(version)) < 0;
46+
}
47+
48+
public boolean isLessThanOrEqualTo(String version) {
49+
return compareTo(parseVersion(version)) <= 0;
50+
}
51+
52+
@Override
53+
public int compareTo(FlywayVersion other) {
54+
for (int i = 0; i < this.parts.length || i < other.parts.length; i++) {
55+
int thisPart = i < this.parts.length ? this.parts[i] : 0;
56+
int otherPart = i < other.parts.length ? other.parts[i] : 0;
57+
58+
if (thisPart > otherPart) {
59+
return 1;
60+
} else if (thisPart < otherPart) {
61+
return -1;
62+
}
63+
}
64+
return 0;
65+
}
66+
67+
@Override
68+
public boolean equals(Object o) {
69+
if (this == o) return true;
70+
if (o == null || getClass() != o.getClass()) return false;
71+
FlywayVersion that = (FlywayVersion) o;
72+
return Arrays.equals(parts, that.parts);
73+
}
74+
75+
@Override
76+
public int hashCode() {
77+
return Arrays.hashCode(parts);
78+
}
79+
80+
@Override
81+
public String toString() {
82+
return Arrays.stream(parts)
83+
.mapToObj(String::valueOf)
84+
.collect(Collectors.joining("."));
85+
}
86+
}

0 commit comments

Comments
 (0)