Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.core;
import lombok.CustomLog;
import lombok.Setter;
import lombok.SneakyThrows;
import org.flywaydb.core.api.ErrorCode;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationInfoService;
import org.flywaydb.core.api.callback.Event;
import org.flywaydb.core.api.configuration.ClassicConfiguration;
import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.api.configuration.FluentConfiguration;
import org.flywaydb.core.api.exception.FlywayValidateException;
import org.flywaydb.core.api.logging.LogFactory;
import org.flywaydb.core.api.output.*;
import org.flywaydb.core.api.pattern.ValidatePattern;
import org.flywaydb.core.extensibility.ConfigurationExtension;
import org.flywaydb.core.extensibility.EventTelemetryModel;
import org.flywaydb.core.extensibility.LicenseGuard;
import org.flywaydb.core.internal.callback.CallbackExecutor;
import org.flywaydb.core.internal.command.*;
import org.flywaydb.core.internal.command.clean.DbClean;
import org.flywaydb.core.internal.database.base.Database;
import org.flywaydb.core.internal.database.base.Schema;
import org.flywaydb.core.internal.resolver.CompositeMigrationResolver;
import org.flywaydb.core.internal.schemahistory.SchemaHistory;
import org.flywaydb.core.internal.util.CommandExtensionUtils;
import org.flywaydb.core.internal.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* This is the centre point of Flyway, and for most users, the only class they will ever have to deal with.
*
* It is THE public API from which all important Flyway functions such as clean, validate and migrate can be called.
*
* To get started all you need to do is create a configured Flyway object and then invoke its principal methods.
*
* Note that a configured Flyway object is immutable. If you change the configuration you will end up creating a new Flyway object.
*/
@CustomLog
public class Flyway {
private final ClassicConfiguration configuration;
private final FlywayExecutor flywayExecutor;
@Deprecated
@Setter
private FlywayTelemetryManager flywayTelemetryManager;
/**
* This is your starting point. This creates a configuration which can be customized to your needs before being
* loaded into a new Flyway instance using the load() method.
*
* In its simplest form, this is how you configure Flyway with all defaults to get started:
*
*
* After that you have a fully-configured Flyway instance at your disposal which can be used to invoke Flyway
* functionality such as migrate() or clean().
*
* @return A new configuration from which Flyway can be loaded.
*/
public static FluentConfiguration configure() {
return new FluentConfiguration();
}
/**
* This is your starting point. This creates a configuration which can be customized to your needs before being
* loaded into a new Flyway instance using the load() method.
*
* In its simplest form, this is how you configure Flyway with all defaults to get started:
*
*
* After that you have a fully-configured Flyway instance at your disposal which can be used to invoke Flyway
* functionality such as migrate() or clean().
*
* @param classLoader The class loader to use when loading classes and resources.
*
* @return A new configuration from which Flyway can be loaded.
*/
public static FluentConfiguration configure(ClassLoader classLoader) {
return new FluentConfiguration(classLoader);
}
/**
* Creates a new instance of Flyway with this configuration. In general the Flyway.configure() factory method should
* be preferred over this constructor, unless you need to create or reuse separate Configuration objects.
*
* @param configuration The configuration to use.
*/
public Flyway(Configuration configuration) {
this.configuration = new ClassicConfiguration(configuration);
// Load callbacks from default package
this.configuration.loadCallbackLocation("db/callback", false);
this.flywayExecutor = new FlywayExecutor(this.configuration);
LogFactory.setConfiguration(this.configuration);
}
/**
* @return The configuration that Flyway is using.
*/
public Configuration getConfiguration() {
return configuration;
}
/**
* @return The configuration extension type requested from the plugin register.
*/
public T getConfigurationExtension(Class configClass) {
return getConfiguration().getPluginRegister().getPlugin(configClass);
}
/**
* Starts the database migration. All pending migrations will be applied in order.
* Calling migrate on an up-to-date database has no effect.
*
*
* @return An object summarising the successfully applied migrations.
*
* @throws FlywayException when the migration failed.
*/
@SneakyThrows
public MigrateResult migrate() throws FlywayException {
try (EventTelemetryModel telemetryModel = new EventTelemetryModel("migrate", flywayTelemetryManager)) {
try {
return flywayExecutor.execute((migrationResolver, schemaHistory, database, defaultSchema, schemas, callbackExecutor, statementInterceptor) -> {
if (configuration.isValidateOnMigrate()) {
List ignorePatterns = new ArrayList<>(Arrays.asList(configuration.getIgnoreMigrationPatterns()));
ignorePatterns.add(ValidatePattern.fromPattern("*:pending"));
ValidateResult validateResult = doValidate(database, migrationResolver, schemaHistory, defaultSchema, schemas, callbackExecutor, ignorePatterns.toArray(new ValidatePattern[0]));
if (!validateResult.validationSuccessful && !configuration.isCleanOnValidationError()) {
throw new FlywayValidateException(validateResult.errorDetails, validateResult.getAllErrorMessages());
}
}
if (configuration.isCreateSchemas()) {
new DbSchemas(database, schemas, schemaHistory, callbackExecutor).create(false);
} else if (!defaultSchema.exists()) {
LOG.warn("The configuration option 'createSchemas' is false.\n" +
"However, the schema history table still needs a schema to reside in.\n" +
"You must manually create a schema for the schema history table to reside in.\n" +
"See https://documentation.red-gate.com/fd/migrations-184127470.html");
}
if (!schemaHistory.exists()) {
List nonEmptySchemas = new ArrayList<>();
for (Schema schema : schemas) {
if (schema.exists() && !schema.empty()) {
nonEmptySchemas.add(schema);
}
}
if (!nonEmptySchemas.isEmpty()
) {
if (configuration.isBaselineOnMigrate()) {
doBaseline(schemaHistory, callbackExecutor, database);
} else {
// Second check for MySQL which is sometimes flaky otherwise
if (!schemaHistory.exists()) {
throw new FlywayException("Found non-empty schema(s) "
+ StringUtils.collectionToCommaDelimitedString(nonEmptySchemas)
+ " but no schema history table. Use baseline()"
+ " or set baselineOnMigrate to true to initialize the schema history table.", ErrorCode.NON_EMPTY_SCHEMA_WITHOUT_SCHEMA_HISTORY_TABLE);
}
}
}
schemaHistory.create(false);
}
MigrateResult result = new DbMigrate(database, schemaHistory, defaultSchema, migrationResolver, configuration, callbackExecutor).migrate();
callbackExecutor.onOperationFinishEvent(Event.AFTER_MIGRATE_OPERATION_FINISH, result);
return result;
}, true, flywayTelemetryManager);
} catch (Exception e) {
telemetryModel.setException(e);
throw e;
}
}
}
/**
* Retrieves the complete information about all the migrations including applied, pending and current migrations with
* details and status.
*
*
* @return All migrations sorted by version, oldest first.
*
* @throws FlywayException when the info retrieval failed.
*/
public MigrationInfoService info() {
return flywayExecutor.execute((migrationResolver, schemaHistory, database, defaultSchema, schemas, callbackExecutor, statementInterceptor) -> {
MigrationInfoService migrationInfoService = new DbInfo(migrationResolver, schemaHistory, configuration, database, callbackExecutor, schemas).info();
callbackExecutor.onOperationFinishEvent(Event.AFTER_INFO_OPERATION_FINISH, migrationInfoService.getInfoResult());
return migrationInfoService;
}, true, flywayTelemetryManager);
}
/**
* Drops all objects (tables, views, procedures, triggers, ...) in the configured schemas.
* The schemas are cleaned in the order specified by the {@code schemas} property.
*
*
* @return An object summarising the actions taken
*
* @throws FlywayException when the clean fails.
*/
@SneakyThrows
public CleanResult clean() {
try (EventTelemetryModel telemetryModel = new EventTelemetryModel("clean", flywayTelemetryManager)) {
try {
return flywayExecutor.execute((migrationResolver, schemaHistory, database, defaultSchema, schemas, callbackExecutor, statementInterceptor) -> {
CleanResult cleanResult = doClean(database, schemaHistory, defaultSchema, schemas, callbackExecutor);
callbackExecutor.onOperationFinishEvent(Event.AFTER_CLEAN_OPERATION_FINISH, cleanResult);
return cleanResult;
}, false, flywayTelemetryManager);
} catch (Exception e) {
telemetryModel.setException(e);
throw e;
}
}
}
/**
* Validate applied migrations against resolved ones (on the filesystem or classpath)
* to detect accidental changes that may prevent the schema(s) from being recreated exactly.
* Validation fails if:
*
*
differences in migration names, types or checksums are found
*
versions have been applied that aren't resolved locally anymore
*
versions have been resolved that haven't been applied yet
*
*
*
*
* @throws FlywayException when the validation failed.
*/
public void validate() throws FlywayException {
flywayExecutor.execute((FlywayExecutor.Command) (migrationResolver, schemaHistory, database, defaultSchema, schemas, callbackExecutor, statementInterceptor) -> {
ValidateResult validateResult = doValidate(database, migrationResolver, schemaHistory, defaultSchema, schemas, callbackExecutor, configuration.getIgnoreMigrationPatterns());
callbackExecutor.onOperationFinishEvent(Event.AFTER_VALIDATE_OPERATION_FINISH, validateResult);
if (!validateResult.validationSuccessful && !configuration.isCleanOnValidationError()) {
throw new FlywayValidateException(validateResult.errorDetails, validateResult.getAllErrorMessages());
}
return null;
}, true, flywayTelemetryManager);
}
/**
* Validate applied migrations against resolved ones (on the filesystem or classpath)
* to detect accidental changes that may prevent the schema(s) from being recreated exactly.
* Validation fails if:
*
*
differences in migration names, types or checksums are found
*
versions have been applied that aren't resolved locally anymore
*
versions have been resolved that haven't been applied yet
*
*
*
*
* @return An object summarising the validation results
*
* @throws FlywayException when the validation failed.
*/
public ValidateResult validateWithResult() throws FlywayException {
return flywayExecutor.execute((migrationResolver, schemaHistory, database, defaultSchema, schemas, callbackExecutor, statementInterceptor) -> {
ValidateResult validateResult = doValidate(database, migrationResolver, schemaHistory, defaultSchema, schemas, callbackExecutor, configuration.getIgnoreMigrationPatterns());
callbackExecutor.onOperationFinishEvent(Event.AFTER_VALIDATE_OPERATION_FINISH, validateResult);
return validateResult;
}, true, flywayTelemetryManager);
}
/**
* Baselines an existing database, excluding all migrations up to and including baselineVersion.
*
*
*
* @return An object summarising the actions taken
*
* @throws FlywayException when the schema baseline failed.
*/
@SneakyThrows
public BaselineResult baseline() throws FlywayException {
try (EventTelemetryModel telemetryModel = new EventTelemetryModel("baseline", flywayTelemetryManager)) {
try {
return flywayExecutor.execute((migrationResolver, schemaHistory, database, defaultSchema, schemas, callbackExecutor, statementInterceptor) -> {
if (configuration.isCreateSchemas()) {
new DbSchemas(database, schemas, schemaHistory, callbackExecutor).create(true);
} else {
LOG.warn("The configuration option 'createSchemas' is false.\n" +
"Even though Flyway is configured not to create any schemas, the schema history table still needs a schema to reside in.\n" +
"You must manually create a schema for the schema history table to reside in.\n" +
"See https://documentation.red-gate.com/fd/migrations-184127470.html");
}
BaselineResult baselineResult = doBaseline(schemaHistory, callbackExecutor, database);
callbackExecutor.onOperationFinishEvent(Event.AFTER_BASELINE_OPERATION_FINISH, baselineResult);
return baselineResult;
}, false, flywayTelemetryManager);
} catch (Exception e) {
telemetryModel.setException(e);
throw e;
}
}
}
/**
* Repairs the Flyway schema history table. This will perform the following actions:
*
*
Remove any failed migrations on databases without DDL transactions (User objects left behind must still be cleaned up manually)
*
Realign the checksums, descriptions and types of the applied migrations with the ones of the available migrations
*
*
*
* @return An object summarising the actions taken
*
* @throws FlywayException when the schema history table repair failed.
*/
@SneakyThrows
public RepairResult repair() throws FlywayException {
try (EventTelemetryModel telemetryModel = new EventTelemetryModel("repair", flywayTelemetryManager)) {
try {
return flywayExecutor.execute((migrationResolver, schemaHistory, database, defaultSchema, schemas, callbackExecutor, statementInterceptor) -> {
RepairResult repairResult = new DbRepair(database, migrationResolver, schemaHistory, callbackExecutor, configuration).repair();
callbackExecutor.onOperationFinishEvent(Event.AFTER_REPAIR_OPERATION_FINISH, repairResult);
return repairResult;
}, true, flywayTelemetryManager);
} catch (Exception e) {
telemetryModel.setException(e);
throw e;
}
}
}
/**
* Undoes the most recently applied versioned migration. If target is specified, Flyway will attempt to undo
* versioned migrations in the order they were applied until it hits one with a version below the target. If there
* is no versioned migration to undo, calling undo has no effect.
* Flyway Teams only
*
*
* @return An object summarising the successfully undone migrations.
*
* @throws FlywayException when undo failed.
*/
public OperationResult undo() throws FlywayException {
try {
return runCommand("undo", Collections.emptyList());
} catch (FlywayException e) {
if (e.getMessage().startsWith("No command extension found")) {
throw new FlywayException("The command 'undo' was not recognized. Make sure you have added 'flyway-proprietary' as a dependency.", e);
}
throw e;
}
}
private OperationResult runCommand(String command, List flags) {
return CommandExtensionUtils.runCommandExtension(configuration, command, flags, null);
}
private CleanResult doClean(Database database, SchemaHistory schemaHistory, Schema defaultSchema, Schema[] schemas, CallbackExecutor callbackExecutor) {
return new DbClean(database, schemaHistory, defaultSchema, schemas, callbackExecutor, configuration).clean();
}
private ValidateResult doValidate(Database database, CompositeMigrationResolver migrationResolver, SchemaHistory schemaHistory,
Schema defaultSchema, Schema[] schemas, CallbackExecutor callbackExecutor, ValidatePattern[] ignorePatterns) {
ValidateResult validateResult = new DbValidate(database, schemaHistory, defaultSchema, migrationResolver, configuration, callbackExecutor, ignorePatterns).validate();
if (!validateResult.validationSuccessful && configuration.isCleanOnValidationError()) {
doClean(database, schemaHistory, defaultSchema, schemas, callbackExecutor);
}
return validateResult;
}
private BaselineResult doBaseline(SchemaHistory schemaHistory, CallbackExecutor callbackExecutor, Database database) {
return new DbBaseline(schemaHistory, configuration.getBaselineVersion(), configuration.getBaselineDescription(), callbackExecutor, database).baseline();
}
}