Merge pull request #16015 from anandshastri1990

* pr/16015:
  Polish "Add failure analyzer for Flyway's bootstrap failure"
  Add failure analyzer for Flyway's bootstrap failure
pull/16046/head
Stephane Nicoll 6 years ago
commit 6d286b9be7

@ -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,14 +161,11 @@ 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);
Assert.state(exists, () -> "Cannot find migrations location in: "
+ Arrays.asList(locations)
+ " (please add migrations or check your Flyway configuration)");
if (!hasAtLeastOneLocation(resourceLoader, locations)) {
throw new FlywayMigrationScriptMissingException(locations);
}
}
}
@ -178,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);
@ -255,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;
@ -385,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);
@ -397,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() {
@ -419,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;

@ -0,0 +1,44 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* 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.springframework.boot.autoconfigure.flyway;
import java.util.ArrayList;
import java.util.List;
/**
* Exception thrown when no Flyway migration script is available.
*
* @author Anand Shastri
* @author Stephane Nicoll
* @since 2.2.0
*/
public class FlywayMigrationScriptMissingException extends RuntimeException {
private final List<String> 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() {
return this.locations;
}
}

@ -0,0 +1,52 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* 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.springframework.boot.autoconfigure.flyway;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
/**
* A {@code FailureAnalyzer} that performs analysis of failures caused by a
* {@link FlywayMigrationScriptMissingException}.
*
* @author Anand Shastri
* @author Stephane Nicoll
*/
class FlywayMigrationScriptMissingFailureAnalyzer
extends AbstractFailureAnalyzer<FlywayMigrationScriptMissingException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure,
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

@ -0,0 +1,59 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* 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.springframework.boot.autoconfigure.flyway;
import java.util.Arrays;
import org.junit.Test;
import org.springframework.boot.diagnostics.FailureAnalysis;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link FlywayMigrationScriptMissingFailureAnalyzer}.
*
* @author Anand Shastri
*/
public class FlywayMigrationScriptMissingFailureAnalyzerTests {
@Test
public void analysisForMissingScriptLocation() {
FailureAnalysis failureAnalysis = performAnalysis();
assertThat(failureAnalysis.getDescription())
.contains("no migration scripts location is configured");
assertThat(failureAnalysis.getAction())
.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);
}
}
Loading…
Cancel
Save