From 6cf647c7cbd3739d1309acfac9073c419669a3a5 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Wed, 29 Mar 2023 14:02:00 -0300 Subject: [PATCH] Cleanup Flyway Config --- .../flyway/FlywayCallbacksLocator.java | 2 +- .../io/quarkus/flyway/FlywayProcessor.java | 2 +- extensions/flyway/runtime/pom.xml | 5 + .../flyway/runtime/FlywayBuildTimeConfig.java | 29 +++-- .../runtime/FlywayContainerProducer.java | 4 +- .../quarkus/flyway/runtime/FlywayCreator.java | 84 ++++++------ .../FlywayDataSourceBuildTimeConfig.java | 29 ++--- .../FlywayDataSourceRuntimeConfig.java | 122 +++++++----------- .../flyway/runtime/FlywayRecorder.java | 2 +- .../flyway/runtime/FlywayRuntimeConfig.java | 32 +++-- .../devconsole/FlywayDevConsoleRecorder.java | 4 +- .../flyway/runtime/FlywayCreatorTest.java | 105 +++++++++------ 12 files changed, 206 insertions(+), 214 deletions(-) diff --git a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayCallbacksLocator.java b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayCallbacksLocator.java index 8d90513e8de45..b4e0f4fbc9cd5 100644 --- a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayCallbacksLocator.java +++ b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/FlywayCallbacksLocator.java @@ -76,7 +76,7 @@ public Map> getCallbacks() */ private Collection callbacksForDataSource(String dataSourceName) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException { - final Optional> callbackConfig = flywayBuildConfig.getConfigForDataSourceName(dataSourceName).callbacks; + final Optional> callbackConfig = flywayBuildConfig.getConfigForDataSourceName(dataSourceName).callbacks(); if (!callbackConfig.isPresent()) { return Collections.emptyList(); } 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 ce3fa9db00e21..b107b878e2b19 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 @@ -99,7 +99,7 @@ MigrationStateBuildItem build(BuildProducer featureProducer, Map> applicationMigrationsToDs = new HashMap<>(); for (var i : dataSourceNames) { Collection migrationLocations = discoverApplicationMigrations( - flywayBuildConfig.getConfigForDataSourceName(i).locations); + flywayBuildConfig.getConfigForDataSourceName(i).locations()); applicationMigrationsToDs.put(i, migrationLocations); } Set datasourcesWithMigrations = new HashSet<>(); diff --git a/extensions/flyway/runtime/pom.xml b/extensions/flyway/runtime/pom.xml index c09e75f82456d..e49a44b3d13a7 100644 --- a/extensions/flyway/runtime/pom.xml +++ b/extensions/flyway/runtime/pom.xml @@ -55,6 +55,11 @@ quarkus-junit5-internal test + + io.quarkus + quarkus-junit5-mockito + test + diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java index 47e7a4878c7f4..58ae166ac6531 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java @@ -1,35 +1,40 @@ package io.quarkus.flyway.runtime; -import java.util.Collections; import java.util.Map; import io.quarkus.datasource.common.runtime.DataSourceUtil; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithParentName; -@ConfigRoot(name = "flyway", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) -public final class FlywayBuildTimeConfig { +@ConfigMapping(prefix = "quarkus.flyway") +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +public interface FlywayBuildTimeConfig { /** * Gets the {@link FlywayDataSourceBuildTimeConfig} for the given datasource name. */ - public FlywayDataSourceBuildTimeConfig getConfigForDataSourceName(String dataSourceName) { + default FlywayDataSourceBuildTimeConfig getConfigForDataSourceName(String dataSourceName) { if (DataSourceUtil.isDefault(dataSourceName)) { - return defaultDataSource; + return defaultDataSource(); } - return namedDataSources.getOrDefault(dataSourceName, FlywayDataSourceBuildTimeConfig.defaultConfig()); + FlywayDataSourceBuildTimeConfig config = namedDataSources().get(dataSourceName); + if (config == null) { + config = defaultDataSource(); + } + return config; } /** * Flyway configuration for the default datasource. */ - @ConfigItem(name = ConfigItem.PARENT) - public FlywayDataSourceBuildTimeConfig defaultDataSource; + @WithParentName + FlywayDataSourceBuildTimeConfig defaultDataSource(); /** * Flyway configurations for named datasources. */ - @ConfigItem(name = ConfigItem.PARENT) - public Map namedDataSources = Collections.emptyMap(); -} \ No newline at end of file + @WithParentName + Map namedDataSources(); +} diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayContainerProducer.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayContainerProducer.java index d58bb692839ed..9149f5f4b22a7 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayContainerProducer.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayContainerProducer.java @@ -51,8 +51,8 @@ public FlywayContainer createFlyway(DataSource dataSource, String dataSourceName final Flyway flyway = new FlywayCreator(matchingRuntimeConfig, matchingBuildTimeConfig, matchingConfigCustomizers( configCustomizerInstances, dataSourceName)).withCallbacks(callbacks) .createFlyway(dataSource); - return new FlywayContainer(flyway, matchingRuntimeConfig.cleanAtStart, matchingRuntimeConfig.migrateAtStart, - matchingRuntimeConfig.repairAtStart, matchingRuntimeConfig.validateAtStart, + return new FlywayContainer(flyway, matchingRuntimeConfig.cleanAtStart(), matchingRuntimeConfig.migrateAtStart(), + matchingRuntimeConfig.repairAtStart(), matchingRuntimeConfig.validateAtStart(), dataSourceName, hasMigrations, createPossible); } diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java index 844be7c8fb053..863c4e895a445 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java @@ -49,63 +49,63 @@ public FlywayCreator withCallbacks(Collection callbacks) { public Flyway createFlyway(DataSource dataSource) { FluentConfiguration configure = Flyway.configure(); - if (flywayRuntimeConfig.jdbcUrl.isPresent()) { - if (flywayRuntimeConfig.username.isPresent() && flywayRuntimeConfig.password.isPresent()) { - configure.dataSource(flywayRuntimeConfig.jdbcUrl.get(), flywayRuntimeConfig.username.get(), - flywayRuntimeConfig.password.get()); + if (flywayRuntimeConfig.jdbcUrl().isPresent()) { + if (flywayRuntimeConfig.username().isPresent() && flywayRuntimeConfig.password().isPresent()) { + configure.dataSource(flywayRuntimeConfig.jdbcUrl().get(), flywayRuntimeConfig.username().get(), + flywayRuntimeConfig.password().get()); } else { throw new ConfigurationException( "Username and password must be defined when a JDBC URL is provided in the Flyway configuration"); } } else { - if (flywayRuntimeConfig.username.isPresent() && flywayRuntimeConfig.password.isPresent()) { + if (flywayRuntimeConfig.username().isPresent() && flywayRuntimeConfig.password().isPresent()) { AgroalDataSource agroalDataSource = (AgroalDataSource) dataSource; String jdbcUrl = agroalDataSource.getConfiguration().connectionPoolConfiguration() .connectionFactoryConfiguration().jdbcUrl(); - configure.dataSource(jdbcUrl, flywayRuntimeConfig.username.get(), - flywayRuntimeConfig.password.get()); + configure.dataSource(jdbcUrl, flywayRuntimeConfig.username().get(), + flywayRuntimeConfig.password().get()); } else { configure.dataSource(dataSource); } } - if (flywayRuntimeConfig.initSql.isPresent()) { - configure.initSql(flywayRuntimeConfig.initSql.get()); + if (flywayRuntimeConfig.initSql().isPresent()) { + configure.initSql(flywayRuntimeConfig.initSql().get()); } - if (flywayRuntimeConfig.connectRetries.isPresent()) { - configure.connectRetries(flywayRuntimeConfig.connectRetries.getAsInt()); + if (flywayRuntimeConfig.connectRetries().isPresent()) { + configure.connectRetries(flywayRuntimeConfig.connectRetries().getAsInt()); } - if (flywayRuntimeConfig.defaultSchema.isPresent()) { - configure.defaultSchema(flywayRuntimeConfig.defaultSchema.get()); + if (flywayRuntimeConfig.defaultSchema().isPresent()) { + configure.defaultSchema(flywayRuntimeConfig.defaultSchema().get()); } - if (flywayRuntimeConfig.schemas.isPresent()) { - configure.schemas(flywayRuntimeConfig.schemas.get().toArray(EMPTY_ARRAY)); + if (flywayRuntimeConfig.schemas().isPresent()) { + configure.schemas(flywayRuntimeConfig.schemas().get().toArray(EMPTY_ARRAY)); } - if (flywayRuntimeConfig.table.isPresent()) { - configure.table(flywayRuntimeConfig.table.get()); + if (flywayRuntimeConfig.table().isPresent()) { + configure.table(flywayRuntimeConfig.table().get()); } - configure.locations(flywayBuildTimeConfig.locations.toArray(EMPTY_ARRAY)); - if (flywayRuntimeConfig.sqlMigrationPrefix.isPresent()) { - configure.sqlMigrationPrefix(flywayRuntimeConfig.sqlMigrationPrefix.get()); + configure.locations(flywayBuildTimeConfig.locations().toArray(EMPTY_ARRAY)); + if (flywayRuntimeConfig.sqlMigrationPrefix().isPresent()) { + configure.sqlMigrationPrefix(flywayRuntimeConfig.sqlMigrationPrefix().get()); } - if (flywayRuntimeConfig.repeatableSqlMigrationPrefix.isPresent()) { - configure.repeatableSqlMigrationPrefix(flywayRuntimeConfig.repeatableSqlMigrationPrefix.get()); + if (flywayRuntimeConfig.repeatableSqlMigrationPrefix().isPresent()) { + configure.repeatableSqlMigrationPrefix(flywayRuntimeConfig.repeatableSqlMigrationPrefix().get()); } - configure.cleanDisabled(flywayRuntimeConfig.cleanDisabled); - configure.baselineOnMigrate(flywayRuntimeConfig.baselineOnMigrate); - configure.validateOnMigrate(flywayRuntimeConfig.validateOnMigrate); - configure.validateMigrationNaming(flywayRuntimeConfig.validateMigrationNaming); + configure.cleanDisabled(flywayRuntimeConfig.cleanDisabled()); + configure.baselineOnMigrate(flywayRuntimeConfig.baselineOnMigrate()); + configure.validateOnMigrate(flywayRuntimeConfig.validateOnMigrate()); + configure.validateMigrationNaming(flywayRuntimeConfig.validateMigrationNaming()); final String[] ignoreMigrationPatterns; - if (flywayRuntimeConfig.ignoreMigrationPatterns.isPresent()) { - ignoreMigrationPatterns = flywayRuntimeConfig.ignoreMigrationPatterns.get(); + if (flywayRuntimeConfig.ignoreMigrationPatterns().isPresent()) { + ignoreMigrationPatterns = flywayRuntimeConfig.ignoreMigrationPatterns().get(); } else { List patterns = new ArrayList<>(2); - if (flywayRuntimeConfig.ignoreMissingMigrations) { + if (flywayRuntimeConfig.ignoreMissingMigrations()) { patterns.add("*:Missing"); } - if (flywayRuntimeConfig.ignoreFutureMigrations) { + if (flywayRuntimeConfig.ignoreFutureMigrations()) { patterns.add("*:Future"); } // Default is *:Future @@ -113,21 +113,21 @@ public Flyway createFlyway(DataSource dataSource) { } configure.ignoreMigrationPatterns(ignoreMigrationPatterns); - configure.cleanOnValidationError(flywayRuntimeConfig.cleanOnValidationError); - configure.outOfOrder(flywayRuntimeConfig.outOfOrder); - if (flywayRuntimeConfig.baselineVersion.isPresent()) { - configure.baselineVersion(flywayRuntimeConfig.baselineVersion.get()); + configure.cleanOnValidationError(flywayRuntimeConfig.cleanOnValidationError()); + configure.outOfOrder(flywayRuntimeConfig.outOfOrder()); + if (flywayRuntimeConfig.baselineVersion().isPresent()) { + configure.baselineVersion(flywayRuntimeConfig.baselineVersion().get()); } - if (flywayRuntimeConfig.baselineDescription.isPresent()) { - configure.baselineDescription(flywayRuntimeConfig.baselineDescription.get()); + if (flywayRuntimeConfig.baselineDescription().isPresent()) { + configure.baselineDescription(flywayRuntimeConfig.baselineDescription().get()); } - configure.placeholders(flywayRuntimeConfig.placeholders); - configure.createSchemas(flywayRuntimeConfig.createSchemas); - if (flywayRuntimeConfig.placeholderPrefix.isPresent()) { - configure.placeholderPrefix(flywayRuntimeConfig.placeholderPrefix.get()); + configure.placeholders(flywayRuntimeConfig.placeholders()); + configure.createSchemas(flywayRuntimeConfig.createSchemas()); + if (flywayRuntimeConfig.placeholderPrefix().isPresent()) { + configure.placeholderPrefix(flywayRuntimeConfig.placeholderPrefix().get()); } - if (flywayRuntimeConfig.placeholderSuffix.isPresent()) { - configure.placeholderSuffix(flywayRuntimeConfig.placeholderSuffix.get()); + if (flywayRuntimeConfig.placeholderSuffix().isPresent()) { + configure.placeholderSuffix(flywayRuntimeConfig.placeholderSuffix().get()); } if (!callbacks.isEmpty()) { configure.callbacks(callbacks.toArray(new Callback[0])); diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceBuildTimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceBuildTimeConfig.java index 7668f4ca191ea..fa6382cf513aa 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceBuildTimeConfig.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceBuildTimeConfig.java @@ -1,18 +1,17 @@ package io.quarkus.flyway.runtime; -import java.util.Collections; import java.util.List; import java.util.Optional; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.annotations.ConvertWith; import io.quarkus.runtime.configuration.TrimmedStringConverter; +import io.smallrye.config.WithConverter; +import io.smallrye.config.WithDefault; @ConfigGroup -public final class FlywayDataSourceBuildTimeConfig { +public interface FlywayDataSourceBuildTimeConfig { - private static final String DEFAULT_LOCATION = "db/migration"; + String DEFAULT_LOCATION = "db/migration"; /** * Comma-separated list of locations to scan recursively for migrations. The location type is determined by its prefix. @@ -23,9 +22,9 @@ public final class FlywayDataSourceBuildTimeConfig { * Locations starting with filesystem: point to a directory on the filesystem, may only contain SQL migrations and are only * scanned recursively down non-hidden directories. */ - @ConfigItem(defaultValue = DEFAULT_LOCATION) - @ConvertWith(TrimmedStringConverter.class) - public List locations; + @WithDefault(DEFAULT_LOCATION) + @WithConverter(TrimmedStringConverter.class) + List locations(); /** * Comma-separated list of fully qualified class names of Callback implementations @@ -33,17 +32,5 @@ public final class FlywayDataSourceBuildTimeConfig { * The {@link org.flywaydb.core.api.callback.Callback} subclass must have a no-args constructor and must not be abstract. * These classes must also not have any fields that hold state (unless that state is initialized in the constructor). */ - @ConfigItem - public Optional> callbacks = Optional.empty(); - - /** - * Creates a {@link FlywayDataSourceBuildTimeConfig} with default settings. - * - * @return {@link FlywayDataSourceBuildTimeConfig} - */ - public static FlywayDataSourceBuildTimeConfig defaultConfig() { - FlywayDataSourceBuildTimeConfig defaultConfig = new FlywayDataSourceBuildTimeConfig(); - defaultConfig.locations = Collections.singletonList(DEFAULT_LOCATION); - return defaultConfig; - } + Optional> callbacks(); } diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java index 5f63532ea1e2e..625a13025ca34 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java @@ -1,32 +1,21 @@ package io.quarkus.flyway.runtime; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.OptionalInt; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; +import io.smallrye.config.WithDefault; @ConfigGroup -public final class FlywayDataSourceRuntimeConfig { - - /** - * Creates a {@link FlywayDataSourceRuntimeConfig} with default settings. - * - * @return {@link FlywayDataSourceRuntimeConfig} - */ - public static FlywayDataSourceRuntimeConfig defaultConfig() { - return new FlywayDataSourceRuntimeConfig(); - } +public interface FlywayDataSourceRuntimeConfig { /** * The maximum number of retries when attempting to connect to the database. After each failed attempt, Flyway will wait 1 * second before attempting to connect again, up to the maximum number of times specified by connectRetries. */ - @ConfigItem - public OptionalInt connectRetries = OptionalInt.empty(); + OptionalInt connectRetries(); /** * Sets the default schema managed by Flyway. This schema name is case-sensitive. If not specified, but schemas @@ -40,37 +29,32 @@ public static FlywayDataSourceRuntimeConfig defaultConfig() { *
  • This schema will be the default for the database connection (provided the database supports this concept).
  • * */ - @ConfigItem - public Optional defaultSchema = Optional.empty(); + Optional defaultSchema(); /** * The JDBC URL that Flyway uses to connect to the database. * Falls back to the datasource URL if not specified. */ - @ConfigItem - public Optional jdbcUrl = Optional.empty(); + Optional jdbcUrl(); /** * The username that Flyway uses to connect to the database. * If no specific JDBC URL is configured, falls back to the datasource username if not specified. */ - @ConfigItem - public Optional username = Optional.empty(); + Optional username(); /** * The password that Flyway uses to connect to the database. * If no specific JDBC URL is configured, falls back to the datasource password if not specified. */ - @ConfigItem - public Optional password = Optional.empty(); + Optional password(); /** * Comma-separated case-sensitive list of schemas managed by Flyway. * The first schema in the list will be automatically set as the default one during the migration. * It will also be the one containing the schema history table. */ - @ConfigItem - public Optional> schemas = Optional.empty(); + Optional> schemas(); /** * The name of Flyway's schema history table. @@ -79,149 +63,136 @@ public static FlywayDataSourceRuntimeConfig defaultConfig() { * When the flyway.schemas property is set (multi-schema mode), the schema history table is placed in the first schema of * the list. */ - @ConfigItem - public Optional table = Optional.empty(); + Optional table(); /** * The file name prefix for versioned SQL migrations. - * + *

    * Versioned SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix , which using * the defaults translates to V1.1__My_description.sql */ - @ConfigItem - public Optional sqlMigrationPrefix = Optional.empty(); + Optional sqlMigrationPrefix(); /** * The file name prefix for repeatable SQL migrations. - * + *

    * Repeatable SQL migrations have the following file name structure: prefixSeparatorDESCRIPTIONsuffix , which using the * defaults translates to R__My_description.sql */ - @ConfigItem - public Optional repeatableSqlMigrationPrefix = Optional.empty(); + Optional repeatableSqlMigrationPrefix(); /** * true to execute Flyway clean command automatically when the application starts, false otherwise. - * */ - @ConfigItem - public boolean cleanAtStart; + @WithDefault("false") + boolean cleanAtStart(); /** * true to prevent Flyway clean operations, false otherwise. */ - @ConfigItem - public boolean cleanDisabled; + @WithDefault("false") + boolean cleanDisabled(); /** * true to automatically call clean when a validation error occurs, false otherwise. */ - @ConfigItem - public boolean cleanOnValidationError; + @WithDefault("false") + boolean cleanOnValidationError(); /** * true to execute Flyway automatically when the application starts, false otherwise. - * */ - @ConfigItem - public boolean migrateAtStart; + @WithDefault("false") + boolean migrateAtStart(); /** * true to execute a Flyway repair command when the application starts, false otherwise. - * */ - @ConfigItem - public boolean repairAtStart; + @WithDefault("false") + boolean repairAtStart(); /** * true to execute a Flyway validate command when the application starts, false otherwise. - * */ - @ConfigItem - public boolean validateAtStart; + @WithDefault("false") + boolean validateAtStart(); /** * Enable the creation of the history table if it does not exist already. */ - @ConfigItem - public boolean baselineOnMigrate; + @WithDefault("false") + boolean baselineOnMigrate(); /** * The initial baseline version. */ - @ConfigItem - public Optional baselineVersion = Optional.empty(); + Optional baselineVersion(); /** * The description to tag an existing schema with when executing baseline. */ - @ConfigItem - public Optional baselineDescription = Optional.empty(); + Optional baselineDescription(); /** * Whether to automatically call validate when performing a migration. */ - @ConfigItem(defaultValue = "true") - public boolean validateOnMigrate = true; + @WithDefault("true") + boolean validateOnMigrate(); /** * Allows migrations to be run "out of order". */ - @ConfigItem - public boolean outOfOrder; + @WithDefault("false") + boolean outOfOrder(); /** * Ignore missing migrations when reading the history table. When set to true migrations from older versions present in the * history table but absent in the configured locations will be ignored (and logged as a warning), when false (the default) * the validation step will fail. */ - @ConfigItem - public boolean ignoreMissingMigrations; + @WithDefault("false") + boolean ignoreMissingMigrations(); /** * Ignore future migrations when reading the history table. When set to true migrations from newer versions present in the * history table but absent in the configured locations will be ignored (and logged as a warning), when false (the default) * the validation step will fail. */ - @ConfigItem - public boolean ignoreFutureMigrations; + @WithDefault("false") + boolean ignoreFutureMigrations(); /** * Sets the placeholders to replace in SQL migration scripts. */ - @ConfigItem - public Map placeholders = Collections.emptyMap(); + Map placeholders(); /** * Whether Flyway should attempt to create the schemas specified in the schemas property */ - @ConfigItem(defaultValue = "true") - public boolean createSchemas; + @WithDefault("true") + boolean createSchemas(); /** * Prefix of every placeholder (default: ${ ) */ - @ConfigItem - public Optional placeholderPrefix = Optional.empty(); + Optional placeholderPrefix(); /** * Suffix of every placeholder (default: } ) */ - @ConfigItem - public Optional placeholderSuffix = Optional.empty(); + Optional placeholderSuffix(); /** * The SQL statements to run to initialize a new database connection immediately after opening it. */ - @ConfigItem - public Optional initSql = Optional.empty(); + Optional initSql(); /** * Whether to validate migrations and callbacks whose scripts do not obey the correct naming convention. A failure can be * useful to check that errors such as case sensitivity in migration prefixes have been corrected. */ - @ConfigItem - public boolean validateMigrationNaming; + @WithDefault("false") + boolean validateMigrationNaming(); /** * Ignore migrations during validate and repair according to a given list of patterns (see @@ -229,6 +200,5 @@ public static FlywayDataSourceRuntimeConfig defaultConfig() { * When this configuration is set, the ignoreFutureMigrations and ignoreMissingMigrations settings are ignored. Patterns are * comma separated. */ - @ConfigItem - public Optional ignoreMigrationPatterns = Optional.empty(); + Optional ignoreMigrationPatterns(); } diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java index 94c7919fe4615..36ded39d7b507 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java @@ -76,7 +76,7 @@ public Flyway get() { } public void doStartActions() { - if (!config.getValue().enabled) { + if (!config.getValue().enabled()) { return; } for (FlywayContainer flywayContainer : FLYWAY_CONTAINERS) { diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java index 481ee6e821539..13efcd42e082a 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java @@ -1,42 +1,48 @@ package io.quarkus.flyway.runtime; -import java.util.Collections; import java.util.Map; import io.quarkus.datasource.common.runtime.DataSourceUtil; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithParentName; -@ConfigRoot(name = "flyway", phase = ConfigPhase.RUN_TIME) -public final class FlywayRuntimeConfig { +@ConfigMapping(prefix = "quarkus.flyway") +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface FlywayRuntimeConfig { /** * Gets the {@link FlywayDataSourceRuntimeConfig} for the given datasource name. */ - public FlywayDataSourceRuntimeConfig getConfigForDataSourceName(String dataSourceName) { + default FlywayDataSourceRuntimeConfig getConfigForDataSourceName(String dataSourceName) { if (DataSourceUtil.isDefault(dataSourceName)) { - return defaultDataSource; + return defaultDataSource(); } - return namedDataSources.getOrDefault(dataSourceName, FlywayDataSourceRuntimeConfig.defaultConfig()); + FlywayDataSourceRuntimeConfig config = namedDataSources().get(dataSourceName); + if (config == null) { + config = defaultDataSource(); + } + return config; } /** * Flag to enable / disable Flyway. * */ - @ConfigItem(defaultValue = "true") - public boolean enabled; + @WithDefault("true") + boolean enabled(); /** * Flyway configuration for the default datasource. */ - @ConfigItem(name = ConfigItem.PARENT) - public FlywayDataSourceRuntimeConfig defaultDataSource = FlywayDataSourceRuntimeConfig.defaultConfig(); + @WithParentName + FlywayDataSourceRuntimeConfig defaultDataSource(); /** * Flyway configurations for named datasources. */ - @ConfigItem(name = ConfigItem.PARENT) - public Map namedDataSources = Collections.emptyMap(); + @WithParentName + Map namedDataSources(); } diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/devconsole/FlywayDevConsoleRecorder.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/devconsole/FlywayDevConsoleRecorder.java index ef51023a14c12..fff138b184cd8 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/devconsole/FlywayDevConsoleRecorder.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/devconsole/FlywayDevConsoleRecorder.java @@ -76,7 +76,7 @@ protected void handlePostAsync(RoutingContext event, MultiMap form) throws Excep return; } FlywayDataSourceBuildTimeConfig config = buildTimeConfig.getConfigForDataSourceName(name); - if (config.locations.isEmpty()) { + if (config.locations().isEmpty()) { flashMessage(event, "Datasource has no locations configured"); return; } @@ -90,7 +90,7 @@ protected void handlePostAsync(RoutingContext event, MultiMap form) throws Excep // In the current project only Path path = resourcesDir.get(0); - Path migrationDir = path.resolve(config.locations.get(0)); + Path migrationDir = path.resolve(config.locations().get(0)); Files.createDirectories(migrationDir); Path file = migrationDir.resolve( "V1.0.0__" + artifactId + ".sql"); diff --git a/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java b/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java index 17764887791ed..48e818499b472 100644 --- a/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java +++ b/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java @@ -18,23 +18,41 @@ import org.flywaydb.core.api.configuration.Configuration; import org.flywaydb.core.api.pattern.ValidatePattern; import org.flywaydb.core.internal.util.ValidatePatternUtils; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; + +import io.smallrye.config.SmallRyeConfig; +import io.smallrye.config.SmallRyeConfigBuilder; class FlywayCreatorTest { - private FlywayDataSourceRuntimeConfig runtimeConfig = FlywayDataSourceRuntimeConfig.defaultConfig(); - private FlywayDataSourceBuildTimeConfig buildConfig = FlywayDataSourceBuildTimeConfig.defaultConfig(); - private Configuration defaultConfig = Flyway.configure().load().getConfiguration(); + private FlywayDataSourceRuntimeConfig runtimeConfig; + private FlywayDataSourceBuildTimeConfig buildConfig; + private final Configuration defaultConfig = Flyway.configure().load().getConfiguration(); /** * class under test. */ private FlywayCreator creator; + @BeforeEach + void mockConfig() { + SmallRyeConfig config = new SmallRyeConfigBuilder().addDiscoveredSources().addDefaultSources().addDiscoveredConverters() + .withMapping(FlywayRuntimeConfig.class, "quarkus.flyway") + .withMapping(FlywayBuildTimeConfig.class, "quarkus.flyway") + .build(); + + FlywayRuntimeConfig flywayRuntimeConfig = config.getConfigMapping(FlywayRuntimeConfig.class); + FlywayBuildTimeConfig flywayBuildTimeConfig = config.getConfigMapping(FlywayBuildTimeConfig.class); + this.runtimeConfig = Mockito.spy(flywayRuntimeConfig.defaultDataSource()); + this.buildConfig = Mockito.spy(flywayBuildTimeConfig.defaultDataSource()); + } + @Test @DisplayName("locations default matches flyway default") void testLocationsDefault() { @@ -45,9 +63,9 @@ void testLocationsDefault() { @Test @DisplayName("locations carried over from configuration") void testLocationsOverridden() { - buildConfig.locations = Arrays.asList("db/migrations", "db/something"); + Mockito.when(buildConfig.locations()).thenReturn(Arrays.asList("db/migrations", "db/something")); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(buildConfig.locations, pathList(createdFlywayConfig().getLocations())); + assertEquals(buildConfig.locations(), pathList(createdFlywayConfig().getLocations())); } @Test @@ -67,9 +85,9 @@ void testBaselineDescriptionDefault() { @Test @DisplayName("baseline description carried over from configuration") void testBaselineDescriptionOverridden() { - runtimeConfig.baselineDescription = Optional.of("baselineDescription"); + Mockito.when(runtimeConfig.baselineDescription()).thenReturn(Optional.of("baselineDescription")); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.baselineDescription.get(), createdFlywayConfig().getBaselineDescription()); + assertEquals(runtimeConfig.baselineDescription().get(), createdFlywayConfig().getBaselineDescription()); } @Test @@ -82,9 +100,9 @@ void testBaselineVersionDefault() { @Test @DisplayName("baseline version carried over from configuration") void testBaselineVersionOverridden() { - runtimeConfig.baselineVersion = Optional.of("0.1.2"); + Mockito.when(runtimeConfig.baselineVersion()).thenReturn(Optional.of("0.1.2")); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.baselineVersion.get(), createdFlywayConfig().getBaselineVersion().getVersion()); + assertEquals(runtimeConfig.baselineVersion().get(), createdFlywayConfig().getBaselineVersion().getVersion()); } @Test @@ -97,9 +115,9 @@ void testConnectionRetriesDefault() { @Test @DisplayName("connection retries carried over from configuration") void testConnectionRetriesOverridden() { - runtimeConfig.connectRetries = OptionalInt.of(12); + Mockito.when(runtimeConfig.connectRetries()).thenReturn(OptionalInt.of(12)); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.connectRetries.getAsInt(), createdFlywayConfig().getConnectRetries()); + assertEquals(runtimeConfig.connectRetries().getAsInt(), createdFlywayConfig().getConnectRetries()); } @Test @@ -112,9 +130,10 @@ void testRepeatableSqlMigrationPrefixDefault() { @Test @DisplayName("repeatable SQL migration prefix carried over from configuration") void testRepeatableSqlMigrationPrefixOverridden() { - runtimeConfig.repeatableSqlMigrationPrefix = Optional.of("A"); + Mockito.when(runtimeConfig.repeatableSqlMigrationPrefix()).thenReturn(Optional.of("A")); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.repeatableSqlMigrationPrefix.get(), createdFlywayConfig().getRepeatableSqlMigrationPrefix()); + assertEquals(runtimeConfig.repeatableSqlMigrationPrefix().get(), + createdFlywayConfig().getRepeatableSqlMigrationPrefix()); } @Test @@ -127,9 +146,9 @@ void testSchemasDefault() { @Test @DisplayName("schemas carried over from configuration") void testSchemasOverridden() { - runtimeConfig.schemas = Optional.of(Arrays.asList("TEST_SCHEMA_1", "TEST_SCHEMA_2")); + Mockito.when(runtimeConfig.schemas()).thenReturn(Optional.of(asList("TEST_SCHEMA_1", "TEST_SCHEMA_2"))); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.schemas.get(), asList(createdFlywayConfig().getSchemas())); + assertEquals(runtimeConfig.schemas().get(), asList(createdFlywayConfig().getSchemas())); } @Test @@ -142,9 +161,9 @@ void testSqlMigrationPrefixDefault() { @Test @DisplayName("SQL migration prefix carried over from configuration") void testSqlMigrationPrefixOverridden() { - runtimeConfig.sqlMigrationPrefix = Optional.of("M"); + Mockito.when(runtimeConfig.sqlMigrationPrefix()).thenReturn(Optional.of("A")); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.sqlMigrationPrefix.get(), createdFlywayConfig().getSqlMigrationPrefix()); + assertEquals(runtimeConfig.sqlMigrationPrefix().get(), createdFlywayConfig().getSqlMigrationPrefix()); } @Test @@ -157,31 +176,31 @@ void testTableDefault() { @Test @DisplayName("table carried over from configuration") void testTableOverridden() { - runtimeConfig.table = Optional.of("flyway_history_test_table"); + Mockito.when(runtimeConfig.table()).thenReturn(Optional.of("flyway_history_test_table")); creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.table.get(), createdFlywayConfig().getTable()); + assertEquals(runtimeConfig.table().get(), createdFlywayConfig().getTable()); } @Test @DisplayName("validate on migrate default matches to true") void testValidateOnMigrate() { creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.validateOnMigrate, createdFlywayConfig().isValidateOnMigrate()); - assertTrue(runtimeConfig.validateOnMigrate); + assertEquals(runtimeConfig.validateOnMigrate(), createdFlywayConfig().isValidateOnMigrate()); + assertTrue(runtimeConfig.validateOnMigrate()); } @Test @DisplayName("clean disabled default matches to false") void testCleanDisabled() { creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.cleanDisabled, createdFlywayConfig().isCleanDisabled()); - assertFalse(runtimeConfig.cleanDisabled); + assertEquals(runtimeConfig.cleanDisabled(), createdFlywayConfig().isCleanDisabled()); + assertFalse(runtimeConfig.cleanDisabled()); - runtimeConfig.cleanDisabled = false; + Mockito.when(runtimeConfig.cleanDisabled()).thenReturn(false); creator = new FlywayCreator(runtimeConfig, buildConfig); assertFalse(createdFlywayConfig().isCleanDisabled()); - runtimeConfig.cleanDisabled = true; + Mockito.when(runtimeConfig.cleanDisabled()).thenReturn(true); creator = new FlywayCreator(runtimeConfig, buildConfig); assertTrue(createdFlywayConfig().isCleanDisabled()); } @@ -189,11 +208,11 @@ void testCleanDisabled() { @Test @DisplayName("outOfOrder is correctly set") void testOutOfOrder() { - runtimeConfig.outOfOrder = false; + Mockito.when(runtimeConfig.outOfOrder()).thenReturn(false); creator = new FlywayCreator(runtimeConfig, buildConfig); assertFalse(createdFlywayConfig().isOutOfOrder()); - runtimeConfig.outOfOrder = true; + Mockito.when(runtimeConfig.outOfOrder()).thenReturn(true); creator = new FlywayCreator(runtimeConfig, buildConfig); assertTrue(createdFlywayConfig().isOutOfOrder()); } @@ -201,11 +220,11 @@ void testOutOfOrder() { @Test @DisplayName("ignoreMissingMigrations is correctly set") void testIgnoreMissingMigrations() { - runtimeConfig.ignoreMissingMigrations = false; + Mockito.when(runtimeConfig.ignoreMissingMigrations()).thenReturn(false); creator = new FlywayCreator(runtimeConfig, buildConfig); assertFalse(ValidatePatternUtils.isMissingIgnored(createdFlywayConfig().getIgnoreMigrationPatterns())); - runtimeConfig.ignoreMissingMigrations = true; + Mockito.when(runtimeConfig.ignoreMissingMigrations()).thenReturn(true); creator = new FlywayCreator(runtimeConfig, buildConfig); assertTrue(ValidatePatternUtils.isMissingIgnored(createdFlywayConfig().getIgnoreMigrationPatterns())); } @@ -213,11 +232,11 @@ void testIgnoreMissingMigrations() { @Test @DisplayName("ignoreFutureMigrations is correctly set") void testIgnoreFutureMigrations() { - runtimeConfig.ignoreFutureMigrations = false; + Mockito.when(runtimeConfig.ignoreFutureMigrations()).thenReturn(false); creator = new FlywayCreator(runtimeConfig, buildConfig); assertFalse(ValidatePatternUtils.isFutureIgnored(createdFlywayConfig().getIgnoreMigrationPatterns())); - runtimeConfig.ignoreFutureMigrations = true; + Mockito.when(runtimeConfig.ignoreFutureMigrations()).thenReturn(true); creator = new FlywayCreator(runtimeConfig, buildConfig); assertTrue(ValidatePatternUtils.isFutureIgnored(createdFlywayConfig().getIgnoreMigrationPatterns())); } @@ -226,14 +245,14 @@ void testIgnoreFutureMigrations() { @DisplayName("cleanOnValidationError defaults to false and is correctly set") void testCleanOnValidationError() { creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.cleanOnValidationError, createdFlywayConfig().isCleanOnValidationError()); - assertFalse(runtimeConfig.cleanOnValidationError); + assertEquals(runtimeConfig.cleanOnValidationError(), createdFlywayConfig().isCleanOnValidationError()); + assertFalse(runtimeConfig.cleanOnValidationError()); - runtimeConfig.cleanOnValidationError = false; + Mockito.when(runtimeConfig.cleanOnValidationError()).thenReturn(false); creator = new FlywayCreator(runtimeConfig, buildConfig); assertFalse(createdFlywayConfig().isCleanOnValidationError()); - runtimeConfig.cleanOnValidationError = true; + Mockito.when(runtimeConfig.cleanOnValidationError()).thenReturn(true); creator = new FlywayCreator(runtimeConfig, buildConfig); assertTrue(createdFlywayConfig().isCleanOnValidationError()); } @@ -242,20 +261,20 @@ void testCleanOnValidationError() { @MethodSource("validateOnMigrateOverwritten") @DisplayName("validate on migrate overwritten in configuration") void testValidateOnMigrateOverwritten(final boolean input, final boolean expected) { - runtimeConfig.validateOnMigrate = input; + Mockito.when(runtimeConfig.validateOnMigrate()).thenReturn(input); creator = new FlywayCreator(runtimeConfig, buildConfig); assertEquals(createdFlywayConfig().isValidateOnMigrate(), expected); - assertEquals(runtimeConfig.validateOnMigrate, expected); + assertEquals(runtimeConfig.validateOnMigrate(), expected); } @Test @DisplayName("validateMigrationNaming defaults to false and it is correctly set") void testValidateMigrationNaming() { creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.validateMigrationNaming, createdFlywayConfig().isValidateMigrationNaming()); - assertFalse(runtimeConfig.validateMigrationNaming); + assertEquals(runtimeConfig.validateMigrationNaming(), createdFlywayConfig().isValidateMigrationNaming()); + assertFalse(runtimeConfig.validateMigrationNaming()); - runtimeConfig.validateMigrationNaming = true; + Mockito.when(runtimeConfig.validateMigrationNaming()).thenReturn(true); creator = new FlywayCreator(runtimeConfig, buildConfig); assertTrue(createdFlywayConfig().isValidateMigrationNaming()); } @@ -265,13 +284,13 @@ void testValidateMigrationNaming() { void testIgnoreMigrationPatterns() { creator = new FlywayCreator(runtimeConfig, buildConfig); assertEquals(0, createdFlywayConfig().getIgnoreMigrationPatterns().length); - assertFalse(runtimeConfig.ignoreMigrationPatterns.isPresent()); + assertFalse(runtimeConfig.ignoreMigrationPatterns().isPresent()); - runtimeConfig.ignoreMigrationPatterns = Optional.of(new String[] { "*:missing" }); + Mockito.when(runtimeConfig.ignoreMigrationPatterns()).thenReturn(Optional.of(new String[] { "*:missing" })); creator = new FlywayCreator(runtimeConfig, buildConfig); final ValidatePattern[] existingIgnoreMigrationPatterns = createdFlywayConfig().getIgnoreMigrationPatterns(); assertEquals(1, existingIgnoreMigrationPatterns.length); - final String[] ignoreMigrationPatterns = runtimeConfig.ignoreMigrationPatterns.get(); + final String[] ignoreMigrationPatterns = runtimeConfig.ignoreMigrationPatterns().get(); final ValidatePattern[] validatePatterns = Arrays.stream(ignoreMigrationPatterns) .map(ValidatePattern::fromPattern).toArray(ValidatePattern[]::new); assertArrayEquals(validatePatterns, existingIgnoreMigrationPatterns);