org.flywaydb.maven.AbstractFlywayMojo Maven / Gradle / Ivy
/*
* Copyright (C) Red Gate Software Ltd 2010-2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flywaydb.maven;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.building.SettingsProblem;
import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
import org.apache.maven.settings.crypto.SettingsDecrypter;
import org.apache.maven.settings.crypto.SettingsDecryptionResult;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.Location;
import org.flywaydb.core.api.logging.Log;
import org.flywaydb.core.api.logging.LogFactory;
import org.flywaydb.core.internal.configuration.ConfigUtils;
import org.flywaydb.core.internal.logging.EvolvingLog;
import org.flywaydb.core.internal.logging.buffered.BufferedLog;
import org.flywaydb.core.internal.util.ExceptionUtils;
import org.flywaydb.core.internal.util.StringUtils;
import java.io.File;
import java.util.*;
import static org.flywaydb.core.internal.configuration.ConfigUtils.FLYWAY_PLUGINS_PREFIX;
import static org.flywaydb.core.internal.configuration.ConfigUtils.putArrayIfSet;
import static org.flywaydb.core.internal.configuration.ConfigUtils.putIfSet;
/**
* Common base class for all mojos with all common attributes.
*/
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
abstract class AbstractFlywayMojo extends AbstractMojo {
private static final String CONFIG_WORKING_DIRECTORY = "flyway.workingDirectory";
private static final String CONFIG_SERVER_ID = "flyway.serverId";
private static final String CONFIG_VERSION = "flyway.version";
private static final String CONFIG_SKIP = "flyway.skip";
private static final String CONFIG_CURRENT = "flyway.current";
Log log;
/**
* Whether to skip the execution of the Maven Plugin for this module.
* Also configurable with Maven or System Property: ${flyway.skip}
*/
@Parameter(property = CONFIG_SKIP)
protected boolean skip;
/**
* The fully qualified classname of the JDBC driver to use to connect to the database.
* By default, the driver is autodetected based on the url.
* Also configurable with Maven or System Property: ${flyway.driver}
*/
@Parameter(property = ConfigUtils.DRIVER)
protected String driver;
/**
* The JDBC url to use to connect to the database.
* Also configurable with Maven or System Property: ${flyway.url}
*/
@Parameter(property = ConfigUtils.URL)
protected String url;
/**
* The user to use to connect to the database. (default: blank)
* The credentials can be specified by user/password or {@code serverId} from settings.xml
* Also configurable with Maven or System Property: ${flyway.user}
*/
@Parameter(property = ConfigUtils.USER)
protected String user;
/**
* The password to use to connect to the database. (default: blank)
* Also configurable with Maven or System Property: ${flyway.password}
*/
@Parameter(property = ConfigUtils.PASSWORD)
private String password;
/**
* 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.
* The interval between retries doubles with each subsequent attempt.
* (default: 0)
* Also configurable with Maven or System Property: ${flyway.connectRetries}
*/
@Parameter(property = ConfigUtils.CONNECT_RETRIES)
private Integer connectRetries;
/**
* The maximum time between retries when attempting to connect to the database in seconds. This will cap the interval
* between connect retry to the value provided.
* (default: 120)
* Also configurable with Maven or System Property: ${flyway.connectRetriesInterval}
*/
@Parameter(property = ConfigUtils.CONNECT_RETRIES_INTERVAL)
private Integer connectRetriesInterval;
/**
* The SQL statements to run to initialize a new database connection immediately after opening it. (default: {@code null})
* Also configurable with Maven or System Property: ${flyway.initSql}
*/
@Parameter(property = ConfigUtils.INIT_SQL)
private String initSql;
/**
* The default schema managed by Flyway. This schema name is case-sensitive. If not specified, but schemas
* is, Flyway uses the first schema in that list. If that is also not specified, Flyway uses the default schema for the
* database connection.
* Consequences:
*
* - This schema will be the one containing the schema history table.
* - This schema will be the default for the database connection (provided the database supports this concept).
*
* Also configurable with Maven or System Property: ${flyway.defaultSchema}
*/
@Parameter
private String defaultSchema;
/**
* The schemas managed by Flyway. These schema names are case-sensitive. If not specified, Flyway uses
* the default schema for the database connection. If defaultSchema is not specified, then the first of
* this list also acts as default schema.
* Consequences:
*
* - Flyway will automatically attempt to create all these schemas, unless they already exist.
* - The schemas will be cleaned in the order of this list.
* - If Flyway created them, the schemas themselves will be dropped when cleaning.
*
* Also configurable with Maven or System Property: ${flyway.schemas} (comma-separated list)
*/
@Parameter
private String[] schemas;
/**
* The name of the schema history table that will be used by Flyway. (default: flyway_schema_history)
* By default, (single-schema mode) the schema history table is placed in the default schema for the connection provided by the datasource.
* When the {@code flyway.schemas} property is set (multi-schema mode), the schema history table is placed in the first schema of the list,
* or in the schema specified to {@code flyway.defaultSchema}.
* Also configurable with Maven or System Property: ${flyway.table}
*/
@Parameter(property = ConfigUtils.TABLE)
private String table;
/**
* The tablespace where to create the schema history table that will be used by Flyway.
* If not specified, Flyway uses the default tablespace for the database connection.
* This setting is only relevant for databases that support the notion of tablespaces. Its value is simply
* ignored for all others.
* Also configurable with Maven or System Property: ${flyway.tablespace}
*/
@Parameter(property = ConfigUtils.TABLESPACE)
private String tablespace;
/**
* The version to tag an existing schema with when executing baseline. (default: 1)
* Also configurable with Maven or System Property: ${flyway.baselineVersion}
*/
@Parameter(property = ConfigUtils.BASELINE_VERSION)
private String baselineVersion;
/**
* The description to tag an existing schema with when executing baseline. (default: << Flyway Baseline >>)
* Also configurable with Maven or System Property: ${flyway.baselineDescription}
*/
@Parameter(property = ConfigUtils.BASELINE_DESCRIPTION)
private String baselineDescription;
/**
* Locations to scan recursively for migrations.
* The location type is determined by its prefix.
* Unprefixed locations or locations starting with {@code classpath:} point to a package on the classpath and may
* contain both SQL and Java-based migrations.
* Locations starting with {@code filesystem:} point to a directory on the filesystem, may only
* contain SQL migrations and are only scanned recursively down non-hidden directories.
* (default: filesystem:src/main/resources/db/migration)
* Also configurable with Maven or System Property: ${flyway.locations} (Comma-separated list)
*/
@Parameter
private String[] locations;
/**
* The fully qualified class names of the custom MigrationResolvers to be used in addition or as replacement
* (if skipDefaultResolvers is true) to the built-in ones for resolving Migrations to apply. (default: none)
* Also configurable with Maven or System Property: ${flyway.resolvers} (Comma-separated list)
*/
@Parameter
private String[] resolvers;
/**
* When set to true, default resolvers are skipped, i.e. only custom resolvers as defined by 'resolvers'
* are used. (default: false)
* Also configurable with Maven or System Property: ${flyway.skipDefaultResolvers}
*/
@Parameter(property = ConfigUtils.SKIP_DEFAULT_RESOLVERS)
private Boolean skipDefaultResolvers;
/**
* The encoding of SQL migrations. (default: UTF-8)
* Also configurable with Maven or System Property: ${flyway.encoding}
*/
@Parameter(property = ConfigUtils.ENCODING)
private String encoding;
/**
* Whether Flyway should try to automatically detect SQL migration file encoding
* Flyway Teams only
* Also configurable with Maven or System Property: ${flyway.detectEncoding}
*/
@Parameter
private Boolean detectEncoding;
/**
* The maximum number of retries when trying to obtain a lock. (default: 50)
* Also configurable with Maven or System Property: ${flyway.lockRetryCount}
*/
@Parameter(property = ConfigUtils.LOCK_RETRY_COUNT)
private Integer lockRetryCount;
/**
* The file name prefix for versioned SQL migrations (default: V)
* Versioned SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix,
* which using the defaults translates to V1_1__My_description.sql
* Also configurable with Maven or System Property: ${flyway.sqlMigrationPrefix}
*/
@Parameter(property = ConfigUtils.SQL_MIGRATION_PREFIX)
private String sqlMigrationPrefix;
/**
* The file name prefix for undo SQL migrations. (default: U)
* Undo SQL migrations are responsible for undoing the effects of the versioned migration with the same version.
* They have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix,
* which using the defaults translates to U1.1__My_description.sql
* Flyway Teams only
* Also configurable with Maven or System Property: ${flyway.undoSqlMigrationPrefix}
*/
@Parameter(property = ConfigUtils.UNDO_SQL_MIGRATION_PREFIX)
private String undoSqlMigrationPrefix;
/**
* The file name prefix for repeatable SQL migrations (default: R)
* Repeatable SQL migrations have the following file name structure: prefixSeparatorDESCRIPTIONsuffix,
* which using the defaults translates to R__My_description.sql
* Also configurable with Maven or System Property:${flyway.repeatableSqlMigrationPrefix}
*/
@Parameter(property = ConfigUtils.REPEATABLE_SQL_MIGRATION_PREFIX)
private String repeatableSqlMigrationPrefix;
/**
* The file name separator for SQL migrations (default: __)
* SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix,
* which using the defaults translates to V1_1__My_description.sql
* Also configurable with Maven or System Property: ${flyway.sqlMigrationSeparator}
*/
@Parameter(property = ConfigUtils.SQL_MIGRATION_SEPARATOR)
private String sqlMigrationSeparator;
/**
* The file name suffixes for SQL migrations. (default: .sql)
* SQL migrations have the following file name structure: prefixVERSIONseparatorDESCRIPTIONsuffix,
* which using the defaults translates to V1_1__My_description.sql
* Multiple suffixes (like .sql,.pkg,.pkb) can be specified for easier compatibility with other tools such as
* editors with specific file associations.
* Also configurable with Maven or System Property: ${flyway.sqlMigrationSuffixes}
*/
@Parameter
private String[] sqlMigrationSuffixes;
/**
* Whether to automatically call clean or not when a validation error occurs. (default: {@code false})
* This is exclusively intended as a convenience for development. even though we strongly recommend not to
* change migration scripts once they have been checked into SCM and run, this provides a way of dealing with this
* case in a smooth manner. The database will be wiped clean automatically, ensuring that the next migration will
* bring you back to the state checked into SCM.
* Warning! Do not enable in production!
* Also configurable with Maven or System Property: ${flyway.cleanOnValidationError}
*/
@Parameter(property = ConfigUtils.CLEAN_ON_VALIDATION_ERROR)
private Boolean cleanOnValidationError;
/**
* Whether to disable clean. (default: {@code false})
* This is especially useful for production environments where running clean can be a career limiting move.
* Also configurable with Maven or System Property: ${flyway.cleanDisabled}
*/
@Parameter(property = ConfigUtils.CLEAN_DISABLED)
private Boolean cleanDisabled;
/**
* The target version up to which Flyway should consider migrations.
* Migrations with a higher version number will be ignored.
* Special values:
*
* - {@code current}: Designates the current version of the schema
* - {@code latest}: The latest version of the schema, as defined by the migration with the highest version
* - {@code next}: The next version of the schema, as defined by the first pending migration
* -
* <version>? (end with a '?'): Instructs Flyway not to fail if the target version doesn't exist.
* In this case, Flyway will go up to but not beyond the specified target
* (default: fail if the target version doesn't exist) Flyway Teams only
*
*
* Defaults to {@code latest}.
* Also configurable with Maven or System Property: ${flyway.target}
*/
@Parameter(property = ConfigUtils.TARGET)
private String target;
/**
* Gets the migrations that Flyway should consider when migrating or undoing. Leave empty to consider all available migrations.
* Migrations not in this list will be ignored.
* Values should be the version for versioned migrations (e.g. 1, 2.4, 6.5.3) or the description for repeatable migrations (e.g. Insert_Data, Create_Table)
* Flyway Teams only
*/
@Parameter
private String[] cherryPick;
/**
* The loggers Flyway should use. Valid options are:
*
*
* - auto: Auto detect the logger (default behavior)
* - console: Use stdout/stderr (only available when using the CLI)
* - slf4j: Use the slf4j logger
* - log4j2: Use the log4j2 logger
* - apache-commons: Use the Apache Commons logger
*
*
* Alternatively you can provide the fully qualified class name for any other logger to use that.
*/
@Parameter
private String[] loggers;
/**
* Allows migrations to be run "out of order" (default: {@code false}).
* If you already have versions 1 and 3 applied, and now a version 2 is found,
* it will be applied too instead of being ignored.
* Also configurable with Maven or System Property: ${flyway.outOfOrder}
*/
@Parameter(property = ConfigUtils.OUT_OF_ORDER)
private Boolean outOfOrder;
/**
* Whether Flyway should skip actually executing the contents of the migrations and only update the schema history table.
* This should be used when you have applied a migration manually (via executing the sql yourself, or via an IDE), and
* just want the schema history table to reflect this.
* Use in conjunction with {@code cherryPick} to skip specific migrations instead of all pending ones.
* Flyway Teams only
*/
@Parameter(property = ConfigUtils.SKIP_EXECUTING_MIGRATIONS)
private Boolean skipExecutingMigrations;
/**
* Whether Flyway should output a table with the results of queries when executing migrations (default: true).
* Flyway Teams only
* Also configurable with Maven or System Property: ${flyway.outputQueryResults}
*/
@Parameter(property = ConfigUtils.OUTPUT_QUERY_RESULTS)
private Boolean outputQueryResults;
/**
* Ignore migrations that match this comma-separated list of patterns when validating migrations.
* Each pattern is of the form :
* See https://documentation.red-gate.com/fd/ignore-migration-patterns-184127507.html for full details
* Example: repeatable:missing,versioned:pending,*:failed
* (default: *:future)
* Flyway Teams only
*/
@Parameter
private String[] ignoreMigrationPatterns;
/**
* 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.
* Also configurable with Maven or System Property: ${flyway.validateMigrationNaming}
*/
@Parameter(property = ConfigUtils.VALIDATE_MIGRATION_NAMING)
private Boolean validateMigrationNaming;
/**
* Whether placeholders should be replaced. (default: true)
* Also configurable with Maven or System Property: ${flyway.placeholderReplacement}
*/
@Parameter(property = ConfigUtils.PLACEHOLDER_REPLACEMENT)
private Boolean placeholderReplacement;
/**
* A map of <placeholder, replacementValue> to apply to SQL migration scripts.
* Also configurable with Maven or System Properties like ${flyway.placeholders.myplaceholder} or ${flyway.placeholders.otherone}
*/
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@Parameter
private Map placeholders;
/**
* A map of <propertyName, propertyValue> to pass to the JDBC driver object
* Also configurable with Maven or System Properties like ${flyway.jdbcProperties.myProperty} or ${flyway.jdbcProperties.otherProperty}
*/
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@Parameter
private Map jdbcProperties;
/**
* The prefix of every placeholder. (default: ${ )
* Also configurable with Maven or System Property: ${flyway.placeholderPrefix}
*/
@Parameter(property = ConfigUtils.PLACEHOLDER_PREFIX)
private String placeholderPrefix;
/**
* The suffix of every placeholder. (default: } )
* Also configurable with Maven or System Property: ${flyway.placeholderSuffix}
*/
@Parameter(property = ConfigUtils.PLACEHOLDER_SUFFIX)
private String placeholderSuffix;
/**
* The separator of default placeholders. (default: : )
* Also configurable with Maven or System Property: ${flyway.placeholderSeparator}
*/
@Parameter(property = ConfigUtils.PLACEHOLDER_SEPARATOR)
private String placeholderSeparator;
/**
* The prefix of every script placeholder. (default: FP__ )
*/
@Parameter(property = ConfigUtils.SCRIPT_PLACEHOLDER_PREFIX)
private String scriptPlaceholderPrefix;
/**
* The suffix of every script placeholder. (default: __ )
*/
@Parameter(property = ConfigUtils.SCRIPT_PLACEHOLDER_SUFFIX)
private String scriptPlaceholderSuffix;
/**
* An array of FlywayCallback implementations. (default: empty )
* Also configurable with Maven or System Property: ${flyway.callbacks}
*/
@Parameter
private String[] callbacks;
/**
* When set to true, default callbacks are skipped, i.e. only custom callbacks as defined by 'resolvers'
* are used. (default: false)
* Also configurable with Maven or System Property: ${flyway.skipDefaultCallbacks}
*/
@Parameter(property = ConfigUtils.SKIP_DEFAULT_CALLBACKS)
private Boolean skipDefaultCallbacks;
/**
* Whether to automatically call baseline when migrate is executed against a non-empty schema with no schema history table.
* This schema will then be baselined with the {@code initialVersion} before executing the migrations.
* Only migrations above {@code initialVersion} will then be applied.
* This is useful for initial Flyway production deployments on projects with an existing DB.
* Be careful when enabling this as it removes the safety net that ensures Flyway does not migrate the wrong
* database in case of a configuration mistake! (default: {@code false})
* Also configurable with Maven or System Property: ${flyway.baselineOnMigrate}
*/
@Parameter(property = ConfigUtils.BASELINE_ON_MIGRATE)
private Boolean baselineOnMigrate;
/**
* Whether to automatically call validate or not when running migrate. (default: {@code true})
* Also configurable with Maven or System Property: ${flyway.validateOnMigrate}
*/
@Parameter(property = ConfigUtils.VALIDATE_ON_MIGRATE)
private Boolean validateOnMigrate;
/**
* Whether to allow mixing transactional and non-transactional statements within the same migration. Enabling this
* automatically causes the entire affected migration to be run without a transaction.
*
* Note that this is only applicable for PostgreSQL, Aurora PostgreSQL, SQL Server and SQLite which all have
* statements that do not run at all within a transaction.
*
* This is not to be confused with implicit transaction, as they occur in MySQL or Oracle, where even though a
* DDL statement was run within a transaction, the database will issue an implicit commit before and after
* its execution.
* {@code true} if mixed migrations should be allowed. {@code false} if an error should be thrown instead. (default: {@code false})
* Also configurable with Maven or System Property: ${flyway.mixed}
*/
@Parameter(property = ConfigUtils.MIXED)
private Boolean mixed;
/**
* Whether to group all pending migrations together in the same transaction when applying them (only recommended for databases with support for DDL transactions).
* {@code true} if migrations should be grouped. {@code false} if they should be applied individually instead. (default: {@code false})
* Also configurable with Maven or System Property: ${flyway.group}
*/
@Parameter(property = ConfigUtils.GROUP)
private Boolean group;
/**
* The username that will be recorded in the schema history table as having applied the migration.
* {@code null} for the current database user of the connection. (default: {@code null}).
* Also configurable with Maven or System Property: ${flyway.installedBy}
*/
@Parameter(property = ConfigUtils.INSTALLED_BY)
private String installedBy;
/**
* Rules for the built-in error handler that let you override specific SQL states and errors codes in order to force
* specific errors or warnings to be treated as debug messages, info messages, warnings or errors.
* Each error override has the following format: {@code STATE:12345:W}.
* It is a 5 character SQL state (or * to match all SQL states), a colon,
* the SQL error code (or * to match all SQL error codes), a colon and finally
* the desired behavior that should override the initial one.
* The following behaviors are accepted:
*
* - {@code D} to force a debug message
* - {@code D-} to force a debug message, but do not show the original sql state and error code
* - {@code I} to force an info message
* - {@code I-} to force an info message, but do not show the original sql state and error code
* - {@code W} to force a warning
* - {@code W-} to force a warning, but do not show the original sql state and error code
* - {@code E} to force an error
* - {@code E-} to force an error, but do not show the original sql state and error code
*
* Example 1: to force Oracle stored procedure compilation issues to produce
* errors instead of warnings, the following errorOverride can be used: {@code 99999:17110:E}
* Example 2: to force SQL Server PRINT messages to be displayed as info messages (without SQL state and error
* code details) instead of warnings, the following errorOverride can be used: {@code S0001:0:I-}
* Example 3: to force all errors with SQL error code 123 to be treated as warnings instead,
* the following errorOverride can be used: {@code *:123:W}
*
* Flyway Teams only
*
Also configurable with Maven or System Property: ${flyway.errorOverrides}
*/
@Parameter
private String[] errorOverrides;
/**
* The file where to output the SQL statements of a migration dry run. If the file specified is in a non-existent
* directory, Flyway will create all directories and parent directories as needed.
* Paths starting with s3: point to a bucket in AWS S3, which must exist. They are in the format s3:(/optionalfolder/subfolder)/filename.sql
* Paths starting with gcs: point to a bucket in Google Cloud Storage, which must exist. They are in the format gcs:(/optionalfolder/subfolder)/filename.sql
* {@code null} to execute the SQL statements directly against the database. (default: {@code null})
*
* Flyway Teams only
* Also configurable with Maven or System Property: ${flyway.dryRunOutput}
*/
@Parameter(property = ConfigUtils.DRYRUN_OUTPUT)
private String dryRunOutput;
/**
* Whether to stream SQL migrations when executing them. Streaming doesn't load the entire migration in memory at
* once. Instead each statement is loaded individually. This is particularly useful for very large SQL migrations
* composed of multiple MB or even GB of reference data, as this dramatically reduces Flyway's memory consumption.
* (default: {@code false}
*
* Flyway Teams only
* Also configurable with Maven or System Property: ${flyway.stream}
*/
@Parameter(property = ConfigUtils.STREAM)
private Boolean stream;
/**
* Whether to batch SQL statements when executing them. Batching can save up to 99 percent of network roundtrips by
* sending up to 100 statements at once over the network to the database, instead of sending each statement
* individually. This is particularly useful for very large SQL migrations composed of multiple MB or even GB of
* reference data, as this can dramatically reduce the network overhead. This is supported for INSERT, UPDATE,
* DELETE, MERGE and UPSERT statements. All other statements are automatically executed without batching.
* (default: {@code false})
*
* Flyway Teams only
* Also configurable with Maven or System Property: ${flyway.batch}
*/
@Parameter(property = ConfigUtils.BATCH)
private Boolean batch;
/**
* When connecting to a Kerberos service to authenticate, the path to the Kerberos config file.
* Flyway Teams only
*/
@Parameter(property = ConfigUtils.KERBEROS_CONFIG_FILE)
private String kerberosConfigFile;
/**
* The encoding of the external config files specified with the {@code flyway.configFiles} property. (default: UTF-8).
* Also configurable with Maven or System Property: ${flyway.configFileEncoding}
*/
@Parameter(property = ConfigUtils.CONFIG_FILE_ENCODING)
private String configFileEncoding;
/**
* Config files from which to load the Flyway configuration. The names of the individual properties match the ones
* you would use as Maven or System properties. The encoding of the files is defined by the
* flyway.configFileEncoding property, which is UTF-8 by default. Relative paths are relative to the POM or
* workingDirectory
if set.
* Also configurable with Maven or System Property: ${flyway.configFiles}
*/
@Parameter(property = ConfigUtils.CONFIG_FILES)
private String[] configFiles;
/**
* Whether Flyway should attempt to create the schemas specified in the schemas property.
* Also configurable with Maven or System Property: ${flyway.createSchemas}
*/
@Parameter(property = ConfigUtils.CREATE_SCHEMAS)
private Boolean createSchemas;
/**
* The working directory to consider when dealing with relative paths for both config files and locations.
* (default: basedir, the directory where the POM resides)
* Also configurable with Maven or System Property: ${flyway.workingDirectory}
*/
@Parameter(property = CONFIG_WORKING_DIRECTORY)
private String workingDirectory;
/**
* Whether to fail if a location specified in the flyway.locations option doesn't exist
*
* @return @{code true} to fail (default: {@code false})
*/
@Parameter(property = ConfigUtils.FAIL_ON_MISSING_LOCATIONS)
public Boolean failOnMissingLocations;
/**
* The id of the server tag in settings.xml (default: flyway-db)
* The credentials can be specified by user/password or {@code serverId} from settings.xml
* Also configurable with Maven or System Property: ${flyway.serverId}
*/
@Parameter(property = CONFIG_SERVER_ID)
private String serverId = "flyway-db";
/**
* The link to the settings.xml
*/
@Parameter(defaultValue = "${settings}", readonly = true)
protected Settings settings;
/**
* The configuration for plugins
* You will need to configure this with the key and value specific to your plugin
*/
@Parameter
private Map pluginConfiguration;
/**
* Reference to the current project that includes the Flyway Maven plugin.
*/
@Parameter(defaultValue = "${project}", readonly = true, required = true)
protected MavenProject mavenProject;
@Component
private SettingsDecrypter settingsDecrypter;
/**
* Load username and password from settings.
*
* @throws FlywayException when the credentials could not be loaded.
*/
private void loadCredentialsFromSettings() throws FlywayException {
final Server server = settings.getServer(serverId);
if (user == null) {
if (server != null) {
user = server.getUsername();
SettingsDecryptionResult result =
settingsDecrypter.decrypt(new DefaultSettingsDecryptionRequest(server));
for (SettingsProblem problem : result.getProblems()) {
if (problem.getSeverity() == SettingsProblem.Severity.ERROR
|| problem.getSeverity() == SettingsProblem.Severity.FATAL) {
throw new FlywayException("Unable to decrypt password: " + problem, problem.getException());
}
}
password = result.getServer().getPassword();
}
} else if (server != null) {
throw new FlywayException("You specified credentials both in the Flyway config and settings.xml. Use either one or the other");
}
}
/**
* Retrieves the value of this boolean property, based on the matching System property on the Maven property.
*
* @param systemPropertyName The name of the System property.
* @param mavenPropertyValue The value of the Maven property.
*/
protected boolean getBooleanProperty(String systemPropertyName, boolean mavenPropertyValue) {
String systemPropertyValue = System.getProperty(systemPropertyName);
if (systemPropertyValue != null) {
return Boolean.parseBoolean(systemPropertyValue);
}
return mavenPropertyValue;
}
public final void execute() throws MojoExecutionException {
LogFactory.setFallbackLogCreator(new MavenLogCreator(this));
log = LogFactory.getLog(getClass());
try {
if (getBooleanProperty(CONFIG_SKIP, skip)) {
log.info("Skipping Flyway execution");
return;
}
Set classpathElements = new HashSet<>();
classpathElements.addAll(mavenProject.getCompileClasspathElements());
classpathElements.addAll(mavenProject.getRuntimeClasspathElements());
ClassRealm classLoader = (ClassRealm) Thread.currentThread().getContextClassLoader();
for (String classpathElement : classpathElements) {
classLoader.addURL(new File(classpathElement).toURI().toURL());
}
File workDir = StringUtils.hasText(workingDirectory) ?
toFile(mavenProject.getBasedir(), workingDirectory) :
mavenProject.getBasedir();
if (locations != null) {
for (int i = 0; i < locations.length; i++) {
if (locations[i].startsWith(Location.FILESYSTEM_PREFIX)) {
String newLocation = locations[i].substring(Location.FILESYSTEM_PREFIX.length());
File file = toFile(workDir, newLocation);
locations[i] = Location.FILESYSTEM_PREFIX + file.getAbsolutePath();
}
}
} else {
locations = new String[] {
Location.FILESYSTEM_PREFIX + workDir.getAbsolutePath() + "/src/main/resources/db/migration"
};
}
Map envVars = ConfigUtils.environmentVariablesToPropertyMap();
Map conf = new HashMap<>(loadConfigurationFromDefaultConfigFiles(envVars));
loadCredentialsFromSettings();
putIfSet(conf, ConfigUtils.DRIVER, driver);
putIfSet(conf, ConfigUtils.URL, url);
putIfSet(conf, ConfigUtils.USER, user);
putIfSet(conf, ConfigUtils.PASSWORD, password);
putIfSet(conf, ConfigUtils.CONNECT_RETRIES, connectRetries);
putIfSet(conf, ConfigUtils.CONNECT_RETRIES_INTERVAL, connectRetriesInterval);
putIfSet(conf, ConfigUtils.INIT_SQL, initSql);
putIfSet(conf, ConfigUtils.DEFAULT_SCHEMA, defaultSchema);
putArrayIfSet(conf, ConfigUtils.SCHEMAS, schemas);
putIfSet(conf, ConfigUtils.TABLE, table);
putIfSet(conf, ConfigUtils.TABLESPACE, tablespace);
putIfSet(conf, ConfigUtils.BASELINE_VERSION, baselineVersion);
putIfSet(conf, ConfigUtils.BASELINE_DESCRIPTION, baselineDescription);
putArrayIfSet(conf, ConfigUtils.LOCATIONS, locations);
putArrayIfSet(conf, ConfigUtils.RESOLVERS, resolvers);
putIfSet(conf, ConfigUtils.SKIP_DEFAULT_RESOLVERS, skipDefaultResolvers);
putArrayIfSet(conf, ConfigUtils.CALLBACKS, callbacks);
putIfSet(conf, ConfigUtils.SKIP_DEFAULT_CALLBACKS, skipDefaultCallbacks);
putIfSet(conf, ConfigUtils.ENCODING, encoding);
putIfSet(conf, ConfigUtils.DETECT_ENCODING, detectEncoding);
putIfSet(conf, ConfigUtils.LOCK_RETRY_COUNT, lockRetryCount);
putIfSet(conf, ConfigUtils.SQL_MIGRATION_PREFIX, sqlMigrationPrefix);
putIfSet(conf, ConfigUtils.UNDO_SQL_MIGRATION_PREFIX, undoSqlMigrationPrefix);
putIfSet(conf, ConfigUtils.REPEATABLE_SQL_MIGRATION_PREFIX, repeatableSqlMigrationPrefix);
putIfSet(conf, ConfigUtils.SQL_MIGRATION_SEPARATOR, sqlMigrationSeparator);
putArrayIfSet(conf, ConfigUtils.SQL_MIGRATION_SUFFIXES, sqlMigrationSuffixes);
putIfSet(conf, ConfigUtils.MIXED, mixed);
putIfSet(conf, ConfigUtils.GROUP, group);
putIfSet(conf, ConfigUtils.INSTALLED_BY, installedBy);
putIfSet(conf, ConfigUtils.CLEAN_ON_VALIDATION_ERROR, cleanOnValidationError);
putIfSet(conf, ConfigUtils.CLEAN_DISABLED, cleanDisabled);
putIfSet(conf, ConfigUtils.OUT_OF_ORDER, outOfOrder);
putIfSet(conf, ConfigUtils.SKIP_EXECUTING_MIGRATIONS, skipExecutingMigrations);
putIfSet(conf, ConfigUtils.OUTPUT_QUERY_RESULTS, outputQueryResults);
putIfSet(conf, ConfigUtils.TARGET, target);
putArrayIfSet(conf, ConfigUtils.LOGGERS, loggers);
putArrayIfSet(conf, ConfigUtils.IGNORE_MIGRATION_PATTERNS, ignoreMigrationPatterns);
putIfSet(conf, ConfigUtils.VALIDATE_MIGRATION_NAMING, validateMigrationNaming);
putIfSet(conf, ConfigUtils.PLACEHOLDER_REPLACEMENT, placeholderReplacement);
putIfSet(conf, ConfigUtils.PLACEHOLDER_PREFIX, placeholderPrefix);
putIfSet(conf, ConfigUtils.PLACEHOLDER_SUFFIX, placeholderSuffix);
putIfSet(conf, ConfigUtils.PLACEHOLDER_SEPARATOR, placeholderSeparator);
putIfSet(conf, ConfigUtils.SCRIPT_PLACEHOLDER_PREFIX, scriptPlaceholderPrefix);
putIfSet(conf, ConfigUtils.SCRIPT_PLACEHOLDER_SUFFIX, scriptPlaceholderSuffix);
putIfSet(conf, ConfigUtils.BASELINE_ON_MIGRATE, baselineOnMigrate);
putIfSet(conf, ConfigUtils.VALIDATE_ON_MIGRATE, validateOnMigrate);
putIfSet(conf, ConfigUtils.DRIVER, driver);
putIfSet(conf, ConfigUtils.CREATE_SCHEMAS, createSchemas);
putIfSet(conf, ConfigUtils.FAIL_ON_MISSING_LOCATIONS, failOnMissingLocations);
putArrayIfSet(conf, ConfigUtils.ERROR_OVERRIDES, errorOverrides);
putIfSet(conf, ConfigUtils.DRYRUN_OUTPUT, dryRunOutput);
putIfSet(conf, ConfigUtils.STREAM, stream);
putIfSet(conf, ConfigUtils.BATCH, batch);
putIfSet(conf, ConfigUtils.KERBEROS_CONFIG_FILE, kerberosConfigFile);
if (placeholders != null) {
for (String placeholder : placeholders.keySet()) {
String value = placeholders.get(placeholder);
conf.put(ConfigUtils.PLACEHOLDERS_PROPERTY_PREFIX + placeholder, value == null ? "" : value);
}
}
if (jdbcProperties != null) {
for (String property : jdbcProperties.keySet()) {
String value = jdbcProperties.get(property);
conf.put(ConfigUtils.JDBC_PROPERTIES_PREFIX + property, value == null ? "" : value);
}
}
conf.putAll(getPluginConfiguration(pluginConfiguration));
conf.putAll(ConfigUtils.propertiesToMap(mavenProject.getProperties()));
conf.putAll(loadConfigurationFromConfigFiles(workDir, envVars));
conf.putAll(envVars);
conf.putAll(ConfigUtils.propertiesToMap(System.getProperties()));
removeMavenPluginSpecificPropertiesToAvoidWarnings(conf);
if (conf.getOrDefault(ConfigUtils.LOGGERS, "auto").equalsIgnoreCase("auto")) {
conf.put(ConfigUtils.LOGGERS, "maven");
}
Flyway flyway = Flyway.configure(classLoader).configuration(conf).load();
doExecute(flyway);
} catch (Exception e) {
throw new MojoExecutionException(e.toString(), ExceptionUtils.getRootCause(e));
} finally {
Log currentLog = ((EvolvingLog) log).getLog();
if (currentLog instanceof BufferedLog) {
((BufferedLog) currentLog).flush(new MavenLog(this.getLog()));
}
}
}
public Map getPluginConfiguration(Map pluginConfiguration) {
Map conf = new HashMap<>();
if (pluginConfiguration == null) {
return conf;
}
String camelCaseRegex = "(? determineConfigFiles(File workDir, Map envVars) {
List configFiles = new ArrayList<>();
if (envVars.containsKey(ConfigUtils.CONFIG_FILES)) {
for (String file : StringUtils.tokenizeToStringArray(envVars.get(ConfigUtils.CONFIG_FILES), ",")) {
configFiles.add(toFile(workDir, file));
}
return configFiles;
}
if (System.getProperties().containsKey(ConfigUtils.CONFIG_FILES)) {
for (String file : StringUtils.tokenizeToStringArray(System.getProperties().getProperty(ConfigUtils.CONFIG_FILES), ",")) {
configFiles.add(toFile(workDir, file));
}
return configFiles;
}
if (mavenProject.getProperties().containsKey(ConfigUtils.CONFIG_FILES)) {
for (String file : StringUtils.tokenizeToStringArray(mavenProject.getProperties().getProperty(ConfigUtils.CONFIG_FILES), ",")) {
configFiles.add(toFile(workDir, file));
}
} else if (this.configFiles != null) {
for (String configFile : this.configFiles) {
configFiles.add(toFile(workDir, configFile));
}
}
return configFiles;
}
/**
* Converts this file name into a file, adjusting relative paths if necessary to make them relative to the pom.
*
* @param workDir The working directory to use.
* @param fileName The name of the file, relative or absolute.
* @return The resulting file.
*/
private File toFile(File workDir, String fileName) {
File file = new File(fileName);
if (file.isAbsolute()) {
return file;
}
return new File(workDir, fileName);
}
/**
* Determines the encoding to use for loading the configuration files.
*
* @param envVars The environment variables converted to Flyway properties.
* @return The encoding. (default: UTF-8)
*/
private String determineConfigurationFileEncoding(Map envVars) {
if (envVars.containsKey(ConfigUtils.CONFIG_FILE_ENCODING)) {
return envVars.get(ConfigUtils.CONFIG_FILE_ENCODING);
}
if (System.getProperties().containsKey(ConfigUtils.CONFIG_FILE_ENCODING)) {
return System.getProperties().getProperty(ConfigUtils.CONFIG_FILE_ENCODING);
}
if (configFileEncoding != null) {
return configFileEncoding;
}
return "UTF-8";
}
/**
* Filters these properties to remove the Flyway Maven Plugin-specific ones to avoid warnings.
*
* @param conf The properties to filter.
*/
private static void removeMavenPluginSpecificPropertiesToAvoidWarnings(Map conf) {
conf.remove(ConfigUtils.CONFIG_FILES);
conf.remove(ConfigUtils.CONFIG_FILE_ENCODING);
conf.remove(CONFIG_CURRENT);
conf.remove(CONFIG_SKIP);
conf.remove(CONFIG_VERSION);
conf.remove(CONFIG_SERVER_ID);
conf.remove(CONFIG_WORKING_DIRECTORY);
}
/**
* Load properties from the config files (if specified).
*
* @param workDir The working directory to use.
* @param envVars The environment variables converted to Flyway properties.
* @return The properties.
*/
private Map loadConfigurationFromConfigFiles(File workDir, Map envVars) {
String encoding = determineConfigurationFileEncoding(envVars);
Map conf = new HashMap<>();
for (File configFile : determineConfigFiles(workDir, envVars)) {
conf.putAll(ConfigUtils.loadConfigurationFile(configFile, encoding, true));
}
return conf;
}
/**
* Load properties from the default config files (if available).
*
* @param envVars The environment variables converted to Flyway properties.
* @return The properties.
*/
private Map loadConfigurationFromDefaultConfigFiles(Map envVars) {
String encoding = determineConfigurationFileEncoding(envVars);
Map configMap = new HashMap<>();
configMap.putAll(ConfigUtils.loadConfigurationFile(new File(System.getProperty("user.home") + "/" + ConfigUtils.CONFIG_FILE_NAME), encoding, false));
configMap.putAll(ConfigUtils.loadConfigurationFile(new File(ConfigUtils.CONFIG_FILE_NAME), encoding, false));
return configMap;
}
/**
* Retrieves this property from either the system or the maven properties.
*
* @param name The name of the property to retrieve.
* @return The property value. {@code null} if not found.
*/
protected String getProperty(String name) {
String systemProperty = System.getProperty(name);
if (systemProperty != null) {
return systemProperty;
}
return mavenProject.getProperties().getProperty(name);
}
/**
* Executes this mojo.
*
* @param flyway The flyway instance to operate on.
* @throws Exception Any exception.
*/
protected abstract void doExecute(Flyway flyway) throws Exception;
}