Merge pull request #6613 from eddumelendez:gh-6610
* pr/6613: Polish contribution Add support for multiple beans in the Flyway and Liquibase endpoints
This commit is contained in:
commit
4b23528eb4
|
@ -55,7 +55,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionEvaluationRepor
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||||
|
@ -188,27 +187,28 @@ public class EndpointAutoConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnSingleCandidate(Flyway.class)
|
@ConditionalOnBean(Flyway.class)
|
||||||
@ConditionalOnClass(Flyway.class)
|
@ConditionalOnClass(Flyway.class)
|
||||||
static class FlywayEndpointConfiguration {
|
static class FlywayEndpointConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public FlywayEndpoint flywayEndpoint(Flyway flyway) {
|
public FlywayEndpoint flywayEndpoint(Map<String, Flyway> flyways) {
|
||||||
return new FlywayEndpoint(flyway);
|
return new FlywayEndpoint(flyways);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnSingleCandidate(SpringLiquibase.class)
|
@ConditionalOnBean(SpringLiquibase.class)
|
||||||
@ConditionalOnClass(SpringLiquibase.class)
|
@ConditionalOnClass(SpringLiquibase.class)
|
||||||
static class LiquibaseEndpointConfiguration {
|
static class LiquibaseEndpointConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public LiquibaseEndpoint liquibaseEndpoint(SpringLiquibase liquibase) {
|
public LiquibaseEndpoint liquibaseEndpoint(
|
||||||
return new LiquibaseEndpoint(liquibase);
|
Map<String, SpringLiquibase> liquibases) {
|
||||||
|
return new LiquibaseEndpoint(liquibases);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,17 @@
|
||||||
package org.springframework.boot.actuate.endpoint;
|
package org.springframework.boot.actuate.endpoint;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.flywaydb.core.Flyway;
|
import org.flywaydb.core.Flyway;
|
||||||
import org.flywaydb.core.api.MigrationInfo;
|
import org.flywaydb.core.api.MigrationInfo;
|
||||||
import org.flywaydb.core.api.MigrationState;
|
import org.flywaydb.core.api.MigrationState;
|
||||||
import org.flywaydb.core.api.MigrationType;
|
import org.flywaydb.core.api.MigrationType;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.endpoint.FlywayEndpoint.FlywayMigration;
|
import org.springframework.boot.actuate.endpoint.FlywayEndpoint.FlywayReport;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@ -38,23 +40,54 @@ import org.springframework.util.Assert;
|
||||||
* @since 1.3.0
|
* @since 1.3.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties(prefix = "endpoints.flyway")
|
@ConfigurationProperties(prefix = "endpoints.flyway")
|
||||||
public class FlywayEndpoint extends AbstractEndpoint<List<FlywayMigration>> {
|
public class FlywayEndpoint extends AbstractEndpoint<List<FlywayReport>> {
|
||||||
|
|
||||||
private final Flyway flyway;
|
private final Map<String, Flyway> flyways;
|
||||||
|
|
||||||
public FlywayEndpoint(Flyway flyway) {
|
public FlywayEndpoint(Flyway flyway) {
|
||||||
|
this(Collections.singletonMap("default", flyway));
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlywayEndpoint(Map<String, Flyway> flyways) {
|
||||||
super("flyway");
|
super("flyway");
|
||||||
Assert.notNull(flyway, "Flyway must not be null");
|
Assert.notEmpty(flyways, "Flyways must be specified");
|
||||||
this.flyway = flyway;
|
this.flyways = flyways;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<FlywayMigration> invoke() {
|
public List<FlywayReport> invoke() {
|
||||||
|
List<FlywayReport> reports = new ArrayList<FlywayReport>();
|
||||||
|
for (Map.Entry<String, Flyway> entry : this.flyways.entrySet()) {
|
||||||
List<FlywayMigration> migrations = new ArrayList<FlywayMigration>();
|
List<FlywayMigration> migrations = new ArrayList<FlywayMigration>();
|
||||||
for (MigrationInfo info : this.flyway.info().all()) {
|
for (MigrationInfo info : entry.getValue().info().all()) {
|
||||||
migrations.add(new FlywayMigration(info));
|
migrations.add(new FlywayMigration(info));
|
||||||
}
|
}
|
||||||
return migrations;
|
reports.add(new FlywayReport(entry.getKey(), migrations));
|
||||||
|
}
|
||||||
|
return reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flyway report for one datasource.
|
||||||
|
*/
|
||||||
|
public static class FlywayReport {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final List<FlywayMigration> migrations;
|
||||||
|
|
||||||
|
public FlywayReport(String name, List<FlywayMigration> migrations) {
|
||||||
|
this.name = name;
|
||||||
|
this.migrations = migrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FlywayMigration> getMigrations() {
|
||||||
|
return this.migrations;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.endpoint;
|
package org.springframework.boot.actuate.endpoint;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@ import liquibase.database.DatabaseFactory;
|
||||||
import liquibase.database.jvm.JdbcConnection;
|
import liquibase.database.jvm.JdbcConnection;
|
||||||
import liquibase.integration.spring.SpringLiquibase;
|
import liquibase.integration.spring.SpringLiquibase;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint.LiquibaseReport;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@ -37,26 +40,33 @@ import org.springframework.util.Assert;
|
||||||
* @since 1.3.0
|
* @since 1.3.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties(prefix = "endpoints.liquibase")
|
@ConfigurationProperties(prefix = "endpoints.liquibase")
|
||||||
public class LiquibaseEndpoint extends AbstractEndpoint<List<Map<String, ?>>> {
|
public class LiquibaseEndpoint extends AbstractEndpoint<List<LiquibaseReport>> {
|
||||||
|
|
||||||
private final SpringLiquibase liquibase;
|
private final Map<String, SpringLiquibase> liquibases;
|
||||||
|
|
||||||
public LiquibaseEndpoint(SpringLiquibase liquibase) {
|
public LiquibaseEndpoint(SpringLiquibase liquibase) {
|
||||||
|
this(Collections.singletonMap("default", liquibase));
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiquibaseEndpoint(Map<String, SpringLiquibase> liquibase) {
|
||||||
super("liquibase");
|
super("liquibase");
|
||||||
Assert.notNull(liquibase, "Liquibase must not be null");
|
Assert.notEmpty(liquibase, "Liquibase must be specified");
|
||||||
this.liquibase = liquibase;
|
this.liquibases = liquibase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Map<String, ?>> invoke() {
|
public List<LiquibaseReport> invoke() {
|
||||||
StandardChangeLogHistoryService service = new StandardChangeLogHistoryService();
|
List<LiquibaseReport> reports = new ArrayList<LiquibaseReport>();
|
||||||
try {
|
|
||||||
DatabaseFactory factory = DatabaseFactory.getInstance();
|
DatabaseFactory factory = DatabaseFactory.getInstance();
|
||||||
DataSource dataSource = this.liquibase.getDataSource();
|
StandardChangeLogHistoryService service = new StandardChangeLogHistoryService();
|
||||||
|
for (Map.Entry<String, SpringLiquibase> entry : this.liquibases.entrySet()) {
|
||||||
|
try {
|
||||||
|
DataSource dataSource = entry.getValue().getDataSource();
|
||||||
JdbcConnection connection = new JdbcConnection(dataSource.getConnection());
|
JdbcConnection connection = new JdbcConnection(dataSource.getConnection());
|
||||||
try {
|
try {
|
||||||
Database database = factory.findCorrectDatabaseImplementation(connection);
|
Database database = factory.findCorrectDatabaseImplementation(connection);
|
||||||
return service.queryDatabaseChangeLogTable(database);
|
reports.add(new LiquibaseReport(entry.getKey(),
|
||||||
|
service.queryDatabaseChangeLogTable(database)));
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
connection.close();
|
connection.close();
|
||||||
|
@ -67,4 +77,31 @@ public class LiquibaseEndpoint extends AbstractEndpoint<List<Map<String, ?>>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liquibase report for one datasource.
|
||||||
|
*/
|
||||||
|
public static class LiquibaseReport {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final List<Map<String, ?>> changeLogs;
|
||||||
|
|
||||||
|
public LiquibaseReport(String name, List<Map<String, ?>> changeLogs) {
|
||||||
|
this.name = name;
|
||||||
|
this.changeLogs = changeLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, ?>> getChangeLogs() {
|
||||||
|
return this.changeLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import liquibase.integration.spring.SpringLiquibase;
|
import liquibase.integration.spring.SpringLiquibase;
|
||||||
import org.flywaydb.core.Flyway;
|
import org.flywaydb.core.Flyway;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -50,6 +52,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionEvaluationRepor
|
||||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;
|
import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.info.ProjectInfoProperties;
|
import org.springframework.boot.autoconfigure.info.ProjectInfoProperties;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||||
import org.springframework.boot.bind.PropertySourcesBinder;
|
import org.springframework.boot.bind.PropertySourcesBinder;
|
||||||
|
@ -65,7 +68,6 @@ import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link EndpointAutoConfiguration}.
|
* Tests for {@link EndpointAutoConfiguration}.
|
||||||
|
@ -222,12 +224,13 @@ public class EndpointAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void flywayEndpointIsDisabledWhenThereAreMultipleFlywayBeans() {
|
public void testFlywayEndpointWithMultipleFlywayBeans() {
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
this.context.register(MultipleFlywayBeansConfig.class,
|
this.context.register(MultipleFlywayBeansConfig.class,
|
||||||
EndpointAutoConfiguration.class);
|
FlywayAutoConfiguration.class, EndpointAutoConfiguration.class);
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
assertThat(this.context.getBeansOfType(FlywayEndpoint.class)).hasSize(0);
|
assertThat(this.context.getBeansOfType(Flyway.class)).hasSize(2);
|
||||||
|
assertThat(this.context.getBeansOfType(FlywayEndpoint.class)).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -242,12 +245,13 @@ public class EndpointAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void liquibaseEndpointIsDisabledWhenThereAreMultipleSpringLiquibaseBeans() {
|
public void testLiquibaseEndpointWithMultipleSpringLiquibaseBeans() {
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
this.context.register(MultipleLiquibaseBeansConfig.class,
|
this.context.register(MultipleLiquibaseBeansConfig.class,
|
||||||
EndpointAutoConfiguration.class);
|
LiquibaseAutoConfiguration.class, EndpointAutoConfiguration.class);
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
assertThat(this.context.getBeansOfType(LiquibaseEndpoint.class)).hasSize(0);
|
assertThat(this.context.getBeansOfType(SpringLiquibase.class)).hasSize(2);
|
||||||
|
assertThat(this.context.getBeansOfType(LiquibaseEndpoint.class)).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load(Class<?>... config) {
|
private void load(Class<?>... config) {
|
||||||
|
@ -330,32 +334,58 @@ public class EndpointAutoConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
static class DataSourceConfig {
|
||||||
static class MultipleFlywayBeansConfig {
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
Flyway flywayOne() {
|
public DataSource dataSourceOne() {
|
||||||
return mock(Flyway.class);
|
return DataSourceBuilder.create().url("jdbc:hsqldb:mem:changelogdbtest")
|
||||||
|
.username("sa").build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
Flyway flywayTwo() {
|
public DataSource dataSourceTwo() {
|
||||||
return mock(Flyway.class);
|
return DataSourceBuilder.create().url("jdbc:hsqldb:mem:changelogdbtest2")
|
||||||
|
.username("sa").build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class MultipleLiquibaseBeansConfig {
|
static class MultipleFlywayBeansConfig extends DataSourceConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SpringLiquibase liquibaseOne() {
|
public Flyway flywayOne() {
|
||||||
return mock(SpringLiquibase.class);
|
Flyway flyway = new Flyway();
|
||||||
|
flyway.setDataSource(dataSourceOne());
|
||||||
|
return flyway;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SpringLiquibase liquibaseTwo() {
|
public Flyway flywayTwo() {
|
||||||
return mock(SpringLiquibase.class);
|
Flyway flyway = new Flyway();
|
||||||
|
flyway.setDataSource(dataSourceTwo());
|
||||||
|
return flyway;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class MultipleLiquibaseBeansConfig extends DataSourceConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringLiquibase liquibaseOne() {
|
||||||
|
SpringLiquibase liquibase = new SpringLiquibase();
|
||||||
|
liquibase.setChangeLog("classpath:/db/changelog/db.changelog-master.yaml");
|
||||||
|
liquibase.setDataSource(dataSourceOne());
|
||||||
|
return liquibase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringLiquibase liquibaseTwo() {
|
||||||
|
SpringLiquibase liquibase = new SpringLiquibase();
|
||||||
|
liquibase.setChangeLog("classpath:/db/changelog/db.changelog-master.yaml");
|
||||||
|
liquibase.setDataSource(dataSourceTwo());
|
||||||
|
return liquibase;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue