diff --git a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayProcessor.java b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayProcessor.java index 85576bebc80f36..68e4106a97feac 100644 --- a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayProcessor.java +++ b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayProcessor.java @@ -195,14 +195,8 @@ private Collection discoverApplicationMigrations(Collection loca LinkedHashSet applicationMigrationResources = new LinkedHashSet<>(); // Locations can be a comma separated list for (String location : locations) { - // Strip any 'classpath:' protocol prefixes because they are assumed - // but not recognized by ClassLoader.getResources() - if (location != null && location.startsWith(CLASSPATH_APPLICATION_MIGRATIONS_PROTOCOL + ':')) { - location = location.substring(CLASSPATH_APPLICATION_MIGRATIONS_PROTOCOL.length() + 1); - if (location.startsWith("/")) { - location = location.substring(1); - } - } + location = normalizeLocation(location); + Enumeration migrations = Thread.currentThread().getContextClassLoader().getResources(location); while (migrations.hasMoreElements()) { URL path = migrations.nextElement(); @@ -232,11 +226,33 @@ private Collection discoverApplicationMigrations(Collection loca } } + private String normalizeLocation(String location) { + if (location == null) { + throw new IllegalStateException("Flyway migration location may not be null."); + } + + // Strip any 'classpath:' protocol prefixes because they are assumed + // but not recognized by ClassLoader.getResources() + if (location.startsWith(CLASSPATH_APPLICATION_MIGRATIONS_PROTOCOL + ':')) { + location = location.substring(CLASSPATH_APPLICATION_MIGRATIONS_PROTOCOL.length() + 1); + if (location.startsWith("/")) { + location = location.substring(1); + } + } + if (!location.endsWith("/")) { + location += "/"; + } + + return location; + } + private Set getApplicationMigrationsFromPath(final String location, final URL path) throws IOException, URISyntaxException { + Path rootPath = Paths.get(path.toURI()); + try (final Stream pathStream = Files.walk(Paths.get(path.toURI()))) { return pathStream.filter(Files::isRegularFile) - .map(it -> Paths.get(location, it.getFileName().toString()).toString()) + .map(it -> Paths.get(location, rootPath.relativize(it).toString()).toString()) // we don't want windows paths here since the paths are going to be used as classpath paths anyway .map(it -> it.replace('\\', '/')) .peek(it -> LOGGER.debugf("Discovered path: %s", it)) diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartSubfolderTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartSubfolderTest.java new file mode 100644 index 00000000000000..fa3d8e04c9c638 --- /dev/null +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartSubfolderTest.java @@ -0,0 +1,41 @@ +package io.quarkus.flyway.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import javax.inject.Inject; + +import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.MigrationInfo; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class FlywayExtensionMigrateAtStartSubfolderTest { + // Quarkus built object + @Inject + Flyway flyway; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addAsResource("db/migration-subfolder/subfolder/V1.0.0__Quarkus.sql") + .addAsResource("migrate-at-start-subfolder-config.properties", "application.properties")); + + @Test + @DisplayName("Migrates at start correctly") + public void testFlywayConfigInjection() { + MigrationInfo migrationInfo = flyway.info().current(); + assertNotNull(migrationInfo, "No Flyway migration was executed"); + + String currentVersion = migrationInfo + .getVersion() + .toString(); + // Expected to be 1.0.0 as migration runs at start + assertEquals("1.0.0", currentVersion); + } +} diff --git a/extensions/flyway/deployment/src/test/resources/db/migration-subfolder/subfolder/V1.0.0__Quarkus.sql b/extensions/flyway/deployment/src/test/resources/db/migration-subfolder/subfolder/V1.0.0__Quarkus.sql new file mode 100644 index 00000000000000..241cad5122ccb0 --- /dev/null +++ b/extensions/flyway/deployment/src/test/resources/db/migration-subfolder/subfolder/V1.0.0__Quarkus.sql @@ -0,0 +1,5 @@ +CREATE TABLE quarked_flyway +( + id INT, + name VARCHAR(20) +); \ No newline at end of file diff --git a/extensions/flyway/deployment/src/test/resources/migrate-at-start-subfolder-config.properties b/extensions/flyway/deployment/src/test/resources/migrate-at-start-subfolder-config.properties new file mode 100644 index 00000000000000..c57bf8416f737f --- /dev/null +++ b/extensions/flyway/deployment/src/test/resources/migrate-at-start-subfolder-config.properties @@ -0,0 +1,8 @@ +quarkus.datasource.db-kind=h2 +quarkus.datasource.username=sa +quarkus.datasource.password=sa +quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start-subfolder;DB_CLOSE_DELAY=-1 + +# Flyway config properties +quarkus.flyway.locations=db/migration-subfolder +quarkus.flyway.migrate-at-start=true