Skip to content

Commit

Permalink
Make Quarkus restart when a change to Flyway scripts is made
Browse files Browse the repository at this point in the history
Adds watches to any existing Flyway migration scripts. This doesn't yet fully address #25256 (as this issue primarily is about the use case of adding new migration scripts), but at least the developer can now continue editing existing migration scripts.

Related issue: #25256

(cherry picked from commit 913308b)
  • Loading branch information
knutwannheden authored and gsmet committed May 16, 2022
1 parent 72e8481 commit 083e22b
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 9 deletions.
24 changes: 16 additions & 8 deletions docs/src/main/asciidoc/flyway.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Quarkus provides first class support for using Flyway as will be explained in th

== Setting up support for Flyway

To start using Flyway with your project, you just need to:
As shown in the <<developing-with-flyway>> section, to start using Flyway with your project, you just need to:

* add your migrations to the `{migrations-path}` folder as you usually do with Flyway
* activate the `migrate-at-start` option to migrate the schema automatically or inject the `Flyway` object and run
Expand Down Expand Up @@ -77,6 +77,7 @@ Also, you can customize the Flyway behaviour by using the following properties:

include::{generated-dir}/config/quarkus-flyway.adoc[opts=optional, leveloffset=+1]

== Developing with Flyway

The following is an example for the `{config-file}` file:

Expand All @@ -88,10 +89,10 @@ quarkus.datasource.username=sarah
quarkus.datasource.password=connor
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase
# Flyway minimal config properties
# Run Flyway migrations automatically
quarkus.flyway.migrate-at-start=true
# Flyway optional config properties
# More Flyway configuration options
# quarkus.flyway.baseline-on-migrate=true
# quarkus.flyway.baseline-version=1.0.0
# quarkus.flyway.baseline-description=Initial version
Expand All @@ -116,7 +117,12 @@ INSERT INTO quarkus(id, name)
VALUES (1, 'QUARKED');
----

Now you can start your application and Quarkus will run the Flyway's migrate method according to your config:
Now you can start your application and Quarkus will run the Flyway's
migrate method according to your config.

NOTE: With `quarkus.flyway.migrate-at-start=true`, as in the example
above, Quarkus will execute the Flyway migration as part of the
xref:lifecycle.adoc[application startup].

[source,java]
----
Expand All @@ -132,9 +138,14 @@ public class MigrationService {
}
}
----

<1> Inject the Flyway object if you want to use it directly

TIP: In dev-mode Quarkus will automatically restart the application if
any of the existing migration scripts get modified. If you want to take
advantage of this while developing and testing new migration scripts,
you will want to set `%dev.quarkus.flyway.clean-at-start=true`, so that
Flyway actually runs the modified migration.

== Multiple datasources

Flyway can be configured for multiple datasources.
Expand Down Expand Up @@ -182,9 +193,6 @@ NOTE: Without configuration, Flyway is set up for every datasource using the def

In case you are interested in using the `Flyway` object directly, you can inject it as follows:

NOTE: If you enabled the `quarkus.flyway.migrate-at-start` property, by the time you use the Flyway instance,
Quarkus will already have run the migrate operation

[source,java]
----
@ApplicationScoped
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/hibernate-orm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ link in the Flyway pane. Hit the `Create Initial Migration` button and the follo
- A `db/migration/V1.0.0__\{appname\}.sql` file will be created, containing the SQL Hibernate is running to generate the schema
- `quarkus.flyway.baseline-on-migrate` will be set, telling Flyway to automatically create its baseline tables
- `quarkus.flyway.migrate-at-start` will be set, telling Flyway to automatically apply migrations on application startup
- `%dev.quarkus.flyway.clean-at-start` and ``%test.quarkus.flyway.clean-at-start` will be set, to clean the DB after reload in dev/test mode
- `%dev.quarkus.flyway.clean-at-start` and `%test.quarkus.flyway.clean-at-start` will be set, to clean the DB after reload in dev/test mode

WARNING: This button is simply a convenience to quickly get you started with Flyway, it is up to you to determine how you want to
manage your database schemas in production. In particular the `migrate-at-start` setting may not be right for all environments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
import io.quarkus.deployment.builditem.IndexDependencyBuildItem;
import io.quarkus.deployment.builditem.ServiceStartBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
Expand Down Expand Up @@ -81,6 +82,7 @@ IndexDependencyBuildItem indexFlyway() {
MigrationStateBuildItem build(BuildProducer<FeatureBuildItem> featureProducer,
BuildProducer<NativeImageResourceBuildItem> resourceProducer,
BuildProducer<ReflectiveClassBuildItem> reflectiveClassProducer,
BuildProducer<HotDeploymentWatchedFileBuildItem> hotDeploymentProducer,
FlywayRecorder recorder,
RecorderContext context,
CombinedIndexBuildItem combinedIndexBuildItem,
Expand All @@ -107,6 +109,9 @@ MigrationStateBuildItem build(BuildProducer<FeatureBuildItem> featureProducer,

Collection<String> applicationMigrations = applicationMigrationsToDs.values().stream().collect(HashSet::new,
AbstractCollection::addAll, HashSet::addAll);
for (String applicationMigration : applicationMigrations) {
hotDeploymentProducer.produce(new HotDeploymentWatchedFileBuildItem(applicationMigration));
}
recorder.setApplicationMigrationFiles(applicationMigrations);

Set<Class<? extends JavaMigration>> javaMigrationClasses = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.quarkus.flyway.test;

import static org.hamcrest.Matchers.is;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.function.Function;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.agroal.api.AgroalDataSource;
import io.quarkus.test.QuarkusDevModeTest;
import io.restassured.RestAssured;

public class FlywayDevModeModifyMigrationTest {

@RegisterExtension
static final QuarkusDevModeTest config = new QuarkusDevModeTest()
.withApplicationRoot((jar) -> jar
.addClasses(RowCountEndpoint.class)
.addAsResource("db/migration/V1.0.0__Quarkus.sql")
.addAsResource("clean-and-migrate-at-start-config.properties", "application.properties"));

@Test
public void testModifyingExistingMigrationScriptCausesRestart() {
RestAssured.get("/row-count").then().statusCode(200).body(is("0"));
config.modifyResourceFile("db/migration/V1.0.0__Quarkus.sql", new Function<String, String>() {
@Override
public String apply(String s) {
return s + '\n' + "INSERT INTO quarked_flyway VALUES (1001, 'test')";
}
});
RestAssured.get("/row-count").then().statusCode(200).body(is("1"));
}

@Path("/row-count")
public static class RowCountEndpoint {

@Inject
AgroalDataSource dataSource;

@GET
public int rowCount() throws SQLException {
try (Connection connection = dataSource.getConnection(); Statement stat = connection.createStatement()) {
try (ResultSet countQuery = stat.executeQuery("select count(1) from quarked_flyway")) {
return countQuery.first() ? countQuery.getInt(1) : 0;
}
}
}
}
}

0 comments on commit 083e22b

Please sign in to comment.