From 554a962a130740e80e62df325b8ffef7f43d85f6 Mon Sep 17 00:00:00 2001 From: Sebastiaan Fernandez Date: Tue, 14 Jul 2020 01:01:24 +0200 Subject: [PATCH 1/2] Add failure analyzer for missing Liquibase changelog See gh-22320 --- ...uibaseChangelogMissingFailureAnalyzer.java | 52 +++++++++++ .../main/resources/META-INF/spring.factories | 3 +- ...seChangelogMissingFailureAnalyzerTest.java | 87 +++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzer.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzerTest.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzer.java new file mode 100644 index 0000000000..723bf0cc3b --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2020 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.diagnostics.analyzer; + +import java.io.FileNotFoundException; + +import liquibase.exception.ChangeLogParseException; + +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; + +/** + * An {@link AbstractFailureAnalyzer} that analyzes exceptions of type + * {@link ChangeLogParseException} caused by a Liquibase changelog not being present. + * + * @author Sebastiaan Fernandez + */ +class LiquibaseChangelogMissingFailureAnalyzer extends AbstractFailureAnalyzer { + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, ChangeLogParseException cause) { + FileNotFoundException exception = findCause(cause, FileNotFoundException.class); + if (exception != null) { + return new FailureAnalysis(getDescription(cause), + "Make sure a Liquibase changelog is present at the configured path", cause); + } + return null; + } + + private String getDescription(ChangeLogParseException cause) { + return "Liquibase failed to start because no changelog could be found at: " + extractChangelogPath(cause); + } + + private String extractChangelogPath(ChangeLogParseException cause) { + return cause.getMessage().substring("Error parsing ".length()); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index 8fb578e0f2..2506bdd9a2 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -56,7 +56,8 @@ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer org.springframework.boot.diagnostics.analyzer.IncompatibleConfigurationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\ -org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer +org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\ +org.springframework.boot.diagnostics.analyzer.LiquibaseChangelogMissingFailureAnalyzer # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzerTest.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzerTest.java new file mode 100644 index 0000000000..cfb2021465 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzerTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012-2020 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.diagnostics.analyzer; + +import javax.sql.DataSource; + +import liquibase.integration.spring.SpringLiquibase; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LiquibaseChangelogMissingFailureAnalyzer} + * + * @author Sebastiaan Fernandez + */ +class LiquibaseChangelogMissingFailureAnalyzerTest { + + @Test + void changelogParseExceptionDueToChangelogNotPresent() { + FailureAnalysis analysis = performAnalysis(); + assertThat(analysis.getDescription()) + .isEqualTo("Liquibase failed to start because no changelog could be found at: " + + "classpath:/db/changelog/db.changelog-master.yaml"); + assertThat(analysis.getAction()).isEqualTo("Make sure a Liquibase changelog is present at the configured path"); + } + + private FailureAnalysis performAnalysis() { + BeanCreationException failure = createFailure(); + assertThat(failure).isNotNull(); + return new LiquibaseChangelogMissingFailureAnalyzer().analyze(failure); + } + + private BeanCreationException createFailure() { + try { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(LiquibaseConfiguration.class); + context.refresh(); + context.close(); + return null; + } + catch (BeanCreationException ex) { + return ex; + } + } + + @Configuration(proxyBeanMethods = false) + static class LiquibaseConfiguration { + + @Bean + DataSource dataSource() { + return DataSourceBuilder.create().url("jdbc:hsqldb:mem:normal").username("sa").build(); + } + + @Bean + SpringLiquibase springLiquibase(DataSource dataSource) { + SpringLiquibase liquibase = new SpringLiquibase(); + liquibase.setChangeLog("classpath:/db/changelog/db.changelog-master.yaml"); + liquibase.setShouldRun(true); + liquibase.setDataSource(dataSource); + return liquibase; + } + + } + +} From 0ce0c3a54af67a1daba554f8aab3c261b105396d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 17 Jul 2020 14:44:16 +0100 Subject: [PATCH 2/2] Polish "Add failure analyzer for missing Liquibase changelog" See gh-22320 --- ...uibaseChangelogMissingFailureAnalyzer.java | 22 +++++++----- .../main/resources/META-INF/spring.factories | 2 +- ...ChangelogMissingFailureAnalyzerTests.java} | 36 ++++++++++++------- 3 files changed, 38 insertions(+), 22 deletions(-) rename spring-boot-project/spring-boot/src/main/java/org/springframework/boot/{diagnostics/analyzer => liquibase}/LiquibaseChangelogMissingFailureAnalyzer.java (73%) rename spring-boot-project/spring-boot/src/test/java/org/springframework/boot/{diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzerTest.java => liquibase/LiquibaseChangelogMissingFailureAnalyzerTests.java} (70%) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseChangelogMissingFailureAnalyzer.java similarity index 73% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzer.java rename to spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseChangelogMissingFailureAnalyzer.java index 723bf0cc3b..7fe2c5d830 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/LiquibaseChangelogMissingFailureAnalyzer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseChangelogMissingFailureAnalyzer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.diagnostics.analyzer; +package org.springframework.boot.liquibase; import java.io.FileNotFoundException; @@ -22,6 +22,7 @@ import liquibase.exception.ChangeLogParseException; import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.util.StringUtils; /** * An {@link AbstractFailureAnalyzer} that analyzes exceptions of type @@ -33,20 +34,23 @@ class LiquibaseChangelogMissingFailureAnalyzer extends AbstractFailureAnalyzer