Polish "Auto-configure Flyway and Liquibase when there's a URL but no DataSource"
See gh-16850
This commit is contained in:
parent
3ca73bf00d
commit
880721557b
|
|
@ -36,11 +36,13 @@ import org.flywaydb.core.api.configuration.FluentConfiguration;
|
|||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayDataSourceCondition;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcOperationsDependsOnPostProcessor;
|
||||
|
|
@ -52,6 +54,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
|||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.jdbc.DatabaseDriver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
|
@ -82,8 +85,8 @@ import org.springframework.util.StringUtils;
|
|||
@SuppressWarnings("deprecation")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Flyway.class)
|
||||
@ConditionalOnProperty(prefix = FlywayProperties.PROPERTIES_PREFIX, name = "enabled",
|
||||
matchIfMissing = true)
|
||||
@Conditional(FlywayDataSourceCondition.class)
|
||||
@ConditionalOnProperty(prefix = "spring.flyway", name = "enabled", matchIfMissing = true)
|
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
|
||||
JdbcTemplateAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
|
||||
public class FlywayAutoConfiguration {
|
||||
|
|
@ -152,11 +155,8 @@ public class FlywayAutoConfiguration {
|
|||
else if (flywayDataSource != null) {
|
||||
configuration.dataSource(flywayDataSource);
|
||||
}
|
||||
else if (dataSource != null) {
|
||||
configuration.dataSource(dataSource);
|
||||
}
|
||||
else {
|
||||
throw new FlywayDataSourceMissingException();
|
||||
configuration.dataSource(dataSource);
|
||||
}
|
||||
return configuration.getDataSource();
|
||||
}
|
||||
|
|
@ -465,4 +465,23 @@ public class FlywayAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
static final class FlywayDataSourceCondition extends AnyNestedCondition {
|
||||
|
||||
FlywayDataSourceCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
private static final class DataSourceBeanCondition {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.flyway", name = "url",
|
||||
matchIfMissing = false)
|
||||
private static final class FlywayUrlCondition {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* Exception thrown when no Flyway is enabled and present in classpath but no datasource
|
||||
* was available or configured for it.
|
||||
*
|
||||
* @author Ilya Lukyanovich
|
||||
*/
|
||||
public class FlywayDataSourceMissingException extends RuntimeException {
|
||||
|
||||
FlywayDataSourceMissingException() {
|
||||
super("Flyway is present in classpath and enabled but "
|
||||
+ "no DataSource bean neither " + FlywayProperties.PROPERTIES_PREFIX
|
||||
+ ".url and " + FlywayProperties.PROPERTIES_PREFIX
|
||||
+ ".user configuration was provided");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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 FlywayDataSourceMissingException}.
|
||||
*
|
||||
* @author Ilya Lukyanovich
|
||||
*/
|
||||
class FlywayDataSourceMissingFailureAnalyzer
|
||||
extends AbstractFailureAnalyzer<FlywayDataSourceMissingException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure,
|
||||
FlywayDataSourceMissingException cause) {
|
||||
return new FailureAnalysis("No DataSource found for flyway",
|
||||
"Please provide a javax.sql.DataSource bean or flyway datasource configuration",
|
||||
cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -35,11 +35,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||
* @author Stephane Nicoll
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = FlywayProperties.PROPERTIES_PREFIX)
|
||||
@ConfigurationProperties(prefix = "spring.flyway")
|
||||
public class FlywayProperties {
|
||||
|
||||
public static final String PROPERTIES_PREFIX = "spring.flyway";
|
||||
|
||||
/**
|
||||
* Whether to enable flyway.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import liquibase.integration.spring.SpringLiquibase;
|
|||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
|
@ -37,10 +38,12 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcOperationsDependsOnPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.jdbc.NamedParameterJdbcOperationsDependsOnPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseDataSourceCondition;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
|
@ -65,8 +68,9 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ SpringLiquibase.class, DatabaseChange.class })
|
||||
@ConditionalOnProperty(prefix = LiquibaseProperties.PROPERTIES_PREFIX, name = "enabled",
|
||||
@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled",
|
||||
matchIfMissing = true)
|
||||
@Conditional(LiquibaseDataSourceCondition.class)
|
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
|
||||
HibernateJpaAutoConfiguration.class })
|
||||
public class LiquibaseAutoConfiguration {
|
||||
|
|
@ -140,12 +144,9 @@ public class LiquibaseAutoConfiguration {
|
|||
liquibase.setDataSource(liquibaseDataSource);
|
||||
return liquibase;
|
||||
}
|
||||
else if (this.properties.isCreateDataSource()) {
|
||||
SpringLiquibase liquibase = new DataSourceClosingSpringLiquibase();
|
||||
liquibase.setDataSource(createNewDataSource(dataSourceProperties));
|
||||
return liquibase;
|
||||
}
|
||||
throw new LiquibaseDataSourceMissingException();
|
||||
SpringLiquibase liquibase = new DataSourceClosingSpringLiquibase();
|
||||
liquibase.setDataSource(createNewDataSource(dataSourceProperties));
|
||||
return liquibase;
|
||||
}
|
||||
|
||||
private DataSource getDataSource(DataSource liquibaseDataSource,
|
||||
|
|
@ -153,7 +154,7 @@ public class LiquibaseAutoConfiguration {
|
|||
if (liquibaseDataSource != null) {
|
||||
return liquibaseDataSource;
|
||||
}
|
||||
if (!this.properties.isCreateDataSource()) {
|
||||
if (this.properties.getUrl() == null && this.properties.getUser() == null) {
|
||||
return dataSource;
|
||||
}
|
||||
return null;
|
||||
|
|
@ -227,4 +228,23 @@ public class LiquibaseAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
static final class LiquibaseDataSourceCondition extends AnyNestedCondition {
|
||||
|
||||
LiquibaseDataSourceCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
private static final class DataSourceBeanCondition {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.liquibase", name = "url",
|
||||
matchIfMissing = false)
|
||||
private static final class LiquibaseUrlCondition {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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.liquibase;
|
||||
|
||||
/**
|
||||
* Exception thrown when Liquibase is enabled and present in classpath but no datasource
|
||||
* was available or configured for it.
|
||||
*
|
||||
* @author Ilya Lukyanovich
|
||||
*/
|
||||
public class LiquibaseDataSourceMissingException extends RuntimeException {
|
||||
|
||||
LiquibaseDataSourceMissingException() {
|
||||
super("Liquibase is present in classpath and enabled but "
|
||||
+ "no DataSource bean neither " + LiquibaseProperties.PROPERTIES_PREFIX
|
||||
+ ".url and " + LiquibaseProperties.PROPERTIES_PREFIX
|
||||
+ ".user configuration was provided");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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.liquibase;
|
||||
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
|
||||
/**
|
||||
* A {@code FailureAnalyzer} that performs analysis of failures caused by a
|
||||
* {@link LiquibaseDataSourceMissingException}.
|
||||
*
|
||||
* @author Ilya Lukyanovich
|
||||
*/
|
||||
class LiquibaseDataSourceMissingFailureAnalyzer
|
||||
extends AbstractFailureAnalyzer<LiquibaseDataSourceMissingException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure,
|
||||
LiquibaseDataSourceMissingException cause) {
|
||||
return new FailureAnalysis("No DataSource found for liquibsae",
|
||||
"Please provide a javax.sql.DataSource bean or liquibase datasource configuration",
|
||||
cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,12 +30,9 @@ import org.springframework.util.Assert;
|
|||
* @author Marcel Overdijk
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = LiquibaseProperties.PROPERTIES_PREFIX,
|
||||
ignoreUnknownFields = false)
|
||||
@ConfigurationProperties(prefix = "spring.liquibase", ignoreUnknownFields = false)
|
||||
public class LiquibaseProperties {
|
||||
|
||||
public static final String PROPERTIES_PREFIX = "spring.liquibase";
|
||||
|
||||
/**
|
||||
* Change log configuration path.
|
||||
*/
|
||||
|
|
@ -219,10 +216,6 @@ public class LiquibaseProperties {
|
|||
this.password = password;
|
||||
}
|
||||
|
||||
public boolean isCreateDataSource() {
|
||||
return this.url != null || this.user != null;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,8 +146,6 @@ org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAuto
|
|||
org.springframework.boot.diagnostics.FailureAnalyzer=\
|
||||
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.flyway.FlywayDataSourceMissingFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.liquibase.LiquibaseDataSourceMissingFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer
|
||||
|
|
|
|||
|
|
@ -79,19 +79,13 @@ public class FlywayAutoConfigurationTests {
|
|||
.withPropertyValues("spring.datasource.generate-unique-name=true");
|
||||
|
||||
@Test
|
||||
public void noDataSource() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().isInstanceOf(BeanCreationException.class);
|
||||
assertThat(context).getFailure()
|
||||
.hasRootCauseInstanceOf(FlywayDataSourceMissingException.class);
|
||||
assertThat(context).getFailure()
|
||||
.hasMessageContaining("Flyway is present in classpath and enabled");
|
||||
});
|
||||
public void backsOffWithNoDataSourceBeanAndNoFlywayUrl() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(Flyway.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noDataSourceCreateOneWithUrl() {
|
||||
public void createsDataSourceWithNoDataSourceBeanAndFlywayUrl() {
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.flyway.url:jdbc:hsqldb:mem:" + UUID.randomUUID())
|
||||
|
|
|
|||
|
|
@ -78,19 +78,13 @@ public class LiquibaseAutoConfigurationTests {
|
|||
.withPropertyValues("spring.datasource.generate-unique-name=true");
|
||||
|
||||
@Test
|
||||
public void noDataSource() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().isInstanceOf(BeanCreationException.class);
|
||||
assertThat(context).getFailure()
|
||||
.hasRootCauseInstanceOf(LiquibaseDataSourceMissingException.class);
|
||||
assertThat(context).getFailure().hasMessageContaining(
|
||||
"Liquibase is present in classpath and enabled");
|
||||
});
|
||||
public void backsOffWithNoDataSourceBeanAndNoLiquibaseUrl() {
|
||||
this.contextRunner.run(
|
||||
(context) -> assertThat(context).doesNotHaveBean(SpringLiquibase.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noDataSourceCreateOneWithUrl() {
|
||||
public void createsDataSourceWithNoDataSourceBeanAndLiquibaseUrl() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.liquibase.url:jdbc:hsqldb:mem:liquibase")
|
||||
.run(assertLiquibase((liquibase) -> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import org.springframework.boot.autoconfigure.flyway.FlywayProperties
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties
|
||||
import org.springframework.boot.configurationdocs.ConfigurationMetadataDocumentWriter
|
||||
import org.springframework.boot.configurationdocs.DocumentOptions
|
||||
import org.springframework.core.io.UrlResource
|
||||
|
|
@ -50,7 +48,7 @@ def generateConfigMetadataDocumentation() {
|
|||
.addSection("security")
|
||||
.withKeyPrefixes("spring.security", "spring.ldap", "spring.session")
|
||||
.addSection("data-migration")
|
||||
.withKeyPrefixes(FlywayProperties.PROPERTIES_PREFIX, LiquibaseProperties.PROPERTIES_PREFIX)
|
||||
.withKeyPrefixes("spring.flyway", "spring.liquibase")
|
||||
.addSection("data")
|
||||
.withKeyPrefixes("spring.couchbase", "spring.elasticsearch", "spring.h2",
|
||||
"spring.influx", "spring.mongodb", "spring.redis",
|
||||
|
|
|
|||
Loading…
Reference in New Issue