Polish "Add failure analyzer for Flyway's bootstrap failure"

Closes gh-16015
pull/16046/head
Stephane Nicoll 6 years ago
parent 96315372ef
commit d5448eb124

@ -16,7 +16,6 @@
package org.springframework.boot.autoconfigure.flyway;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -63,7 +62,6 @@ import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@ -163,15 +161,10 @@ public class FlywayAutoConfiguration {
private void checkLocationExists(DataSource dataSource,
FlywayProperties properties, ResourceLoader resourceLoader) {
if (properties.isCheckLocation()) {
String[] locations = new LocationResolver(dataSource)
List<String> locations = new LocationResolver(dataSource)
.resolveLocations(properties.getLocations());
Assert.state(locations.length != 0,
"Migration script locations not configured");
boolean exists = hasAtLeastOneLocation(resourceLoader, locations);
if (!exists) {
throw new FlywayMigrationScriptNotFoundException(
"Cannot find migrations in the specified location",
Arrays.asList(locations));
if (!hasAtLeastOneLocation(resourceLoader, locations)) {
throw new FlywayMigrationScriptMissingException(locations);
}
}
}
@ -180,7 +173,7 @@ public class FlywayAutoConfiguration {
FlywayProperties properties) {
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
String[] locations = new LocationResolver(configuration.getDataSource())
.resolveLocations(properties.getLocations());
.resolveLocations(properties.getLocations()).toArray(new String[0]);
map.from(locations).to(configuration::locations);
map.from(properties.getEncoding()).to(configuration::encoding);
map.from(properties.getConnectRetries()).to(configuration::connectRetries);
@ -257,7 +250,7 @@ public class FlywayAutoConfiguration {
}
private boolean hasAtLeastOneLocation(ResourceLoader resourceLoader,
String... locations) {
Collection<String> locations) {
for (String location : locations) {
if (resourceLoader.getResource(normalizePrefix(location)).exists()) {
return true;
@ -387,11 +380,7 @@ public class FlywayAutoConfiguration {
this.dataSource = dataSource;
}
public String[] resolveLocations(Collection<String> locations) {
return resolveLocations(StringUtils.toStringArray(locations));
}
public String[] resolveLocations(String[] locations) {
public List<String> resolveLocations(List<String> locations) {
if (usesVendorLocation(locations)) {
DatabaseDriver databaseDriver = getDatabaseDriver();
return replaceVendorLocations(locations, databaseDriver);
@ -399,15 +388,15 @@ public class FlywayAutoConfiguration {
return locations;
}
private String[] replaceVendorLocations(String[] locations,
private List<String> replaceVendorLocations(List<String> locations,
DatabaseDriver databaseDriver) {
if (databaseDriver == DatabaseDriver.UNKNOWN) {
return locations;
}
String vendor = databaseDriver.getId();
return Arrays.stream(locations)
return locations.stream()
.map((location) -> location.replace(VENDOR_PLACEHOLDER, vendor))
.toArray(String[]::new);
.collect(Collectors.toList());
}
private DatabaseDriver getDatabaseDriver() {
@ -421,7 +410,7 @@ public class FlywayAutoConfiguration {
}
private boolean usesVendorLocation(String... locations) {
private boolean usesVendorLocation(Collection<String> locations) {
for (String location : locations) {
if (location.contains(VENDOR_PLACEHOLDER)) {
return true;

@ -16,22 +16,25 @@
package org.springframework.boot.autoconfigure.flyway;
import java.util.ArrayList;
import java.util.List;
/**
* Exception thrown when no {@code flyway migration script} is available.
* Exception thrown when no Flyway migration script is available.
*
* @author Anand Shastri
* @author Stephane Nicoll
* @since 2.2.0
*/
public class FlywayMigrationScriptNotFoundException extends RuntimeException {
public class FlywayMigrationScriptMissingException extends RuntimeException {
private final List<String> locations;
public FlywayMigrationScriptNotFoundException(String message,
List<String> locations) {
super(message);
this.locations = locations;
FlywayMigrationScriptMissingException(List<String> locations) {
super(locations.isEmpty() ? "Migration script locations not configured"
: "Cannot find migrations location in: " + locations
+ " (please add migrations or check your Flyway configuration)");
this.locations = new ArrayList<>(locations);
}
public List<String> getLocations() {

@ -21,19 +21,32 @@ import org.springframework.boot.diagnostics.FailureAnalysis;
/**
* A {@code FailureAnalyzer} that performs analysis of failures caused by a
* {@code FlywayMigrationScriptNotFoundException}.
* {@link FlywayMigrationScriptMissingException}.
*
* @author Anand Shastri
* @author Stephane Nicoll
*/
public class FlywayMigrationScriptMissingFailureAnalyzer
extends AbstractFailureAnalyzer<FlywayMigrationScriptNotFoundException> {
class FlywayMigrationScriptMissingFailureAnalyzer
extends AbstractFailureAnalyzer<FlywayMigrationScriptMissingException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure,
FlywayMigrationScriptNotFoundException cause) {
return new FailureAnalysis(
"Cannot find migrations location in " + cause.getLocations(),
" please add migrations or check your Flyway configuration", cause);
FlywayMigrationScriptMissingException cause) {
StringBuilder description = new StringBuilder("Flyway failed to initialize: ");
if (cause.getLocations().isEmpty()) {
return new FailureAnalysis(description
.append("no migration scripts location is configured").toString(),
"Check your Flyway configuration", cause);
}
else {
description.append(String.format(
"none of the following migration scripts locations could be found:%n%n"));
cause.getLocations().forEach((location) -> description
.append(String.format("\t- %s%n", location)));
return new FailureAnalysis(description.toString(),
"Review the locations above or check your Flyway configuration",
cause);
}
}
}

@ -141,6 +141,7 @@ org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAuto
# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

@ -209,7 +209,7 @@ public class FlywayAutoConfigurationTests {
assertThat(context).getFailure()
.isInstanceOf(BeanCreationException.class);
assertThat(context).getFailure()
.hasMessageContaining("Cannot find migrations in");
.hasMessageContaining("Cannot find migrations location in");
});
}

@ -16,7 +16,7 @@
package org.springframework.boot.autoconfigure.flyway;
import java.util.Collections;
import java.util.Arrays;
import org.junit.Test;
@ -25,25 +25,35 @@ import org.springframework.boot.diagnostics.FailureAnalysis;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link FlywayMigrationScriptMissingFailureAnalyzer}
* Tests for {@link FlywayMigrationScriptMissingFailureAnalyzer}.
*
* @author Anand Shastri
*/
public class FlywayMigrationScriptMissingFailureAnalyzerTests {
private final FlywayMigrationScriptMissingFailureAnalyzer analyzer = new FlywayMigrationScriptMissingFailureAnalyzer();
@Test
public void analysisForFlywayScriptMissingFailure() {
FailureAnalysis failureAnalysis = this.analyzer
.analyze(new FlywayMigrationScriptNotFoundException(
"Migration script locations not configured",
Collections.singletonList("classpath:db/migration")));
public void analysisForMissingScriptLocation() {
FailureAnalysis failureAnalysis = performAnalysis();
assertThat(failureAnalysis.getDescription())
.endsWith("Cannot find migrations location in [classpath:db/migration]");
.contains("no migration scripts location is configured");
assertThat(failureAnalysis.getAction())
.endsWith(" please add migrations or check your Flyway configuration");
.contains("Check your Flyway configuration");
}
@Test
public void analysisForScriptLocationsNotFound() {
FailureAnalysis failureAnalysis = performAnalysis("classpath:db/migration");
assertThat(failureAnalysis.getDescription()).contains(
"none of the following migration scripts locations could be found")
.contains("classpath:db/migration");
assertThat(failureAnalysis.getAction()).contains(
"Review the locations above or check your Flyway configuration");
}
private FailureAnalysis performAnalysis(String... locations) {
FlywayMigrationScriptMissingException exception = new FlywayMigrationScriptMissingException(
Arrays.asList(locations));
return new FlywayMigrationScriptMissingFailureAnalyzer().analyze(exception);
}
}

@ -50,8 +50,7 @@ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnaly
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.FlywayMigrationScriptMissingFailureAnalyzer
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\

Loading…
Cancel
Save