Last active
September 17, 2022 11:35
-
-
Save mhewedy/39094729975d9d73d11afad82af55788 to your computer and use it in GitHub Desktop.
SkipMissingChangelogsSpringLiquibase
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import liquibase.changelog.IncludeAllFilter; | |
import liquibase.integration.spring.SpringLiquibase; | |
import liquibase.integration.spring.SpringResourceAccessor; | |
import lombok.extern.slf4j.Slf4j; | |
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; | |
import org.springframework.boot.context.properties.EnableConfigurationProperties; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.core.io.ResourceLoader; | |
import javax.sql.DataSource; | |
import java.io.ByteArrayInputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.nio.charset.StandardCharsets; | |
/** | |
* The point here is, liquibase loads either <br /> | |
* <ol> | |
* <li>"files" <a href="https://docs.liquibase.com/concepts/advanced/include.html">include</a> </li> | |
* <li>or "complete directories" <a href="https://docs.liquibase.com/concepts/advanced/includeall.html">includeAll</a> </li> | |
* </ol> | |
* | |
* <p> | |
* | |
* <p> | |
* The issue is, if you mention a list of files, and liquibase doesn't find one of the on the classpath | |
* (that will be affected by optionally load modules based on the selected profile, then it will fail. | |
* <p> | |
* And apparently there's no way to workaround this but to go with option #2 above | |
* and then write a couple of sorters {@link java.util.Comparator<String> } and filters {@link IncludeAllFilter} classes | |
* and ask liquibase to behave accordingly. | |
* <p> | |
* which I find not so clear if we compare with the first option where we list explicitly the files we need to load as part of liquibase. | |
* <br /><br /> | |
* So, the solution here is to override liquibase bean and instead on throwing exception if file not found, we log warn and continue. | |
*/ | |
@Slf4j | |
class SkipMissingChangelogsSpringLiquibase extends SpringLiquibase { | |
private static final String DUMMY_PATH = "A String"; | |
private static final String EMPTY_FILE = """ | |
<?xml version="1.1" encoding="UTF-8" standalone="no"?> | |
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog | |
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.10.xsd"> | |
</databaseChangeLog> | |
"""; | |
@Override | |
protected SpringResourceAccessor createResourceOpener() { | |
return new SkipMissingFilesResourceAccessor(getResourceLoader()); | |
} | |
private static class SkipMissingFilesResourceAccessor extends SpringResourceAccessor { | |
public SkipMissingFilesResourceAccessor(ResourceLoader resourceLoader) { | |
super(resourceLoader); | |
} | |
@Override | |
public InputStream openStream(String relativeTo, String streamPath) throws IOException { | |
InputStream inputStream = super.openStream(relativeTo, streamPath); | |
if (inputStream == null && !DUMMY_PATH.equals(streamPath)) { | |
log.warn("missing liquibase file: \"{}\" => skipping", streamPath); | |
return new ByteArrayInputStream(EMPTY_FILE.getBytes(StandardCharsets.UTF_8)); | |
} | |
return inputStream; | |
} | |
} | |
@Configuration | |
@EnableConfigurationProperties({LiquibaseProperties.class}) | |
static class LiquibaseWebConfig { | |
// source: LiquibaseAutoConfiguration | |
@Bean | |
public SpringLiquibase liquibase(LiquibaseProperties properties, DataSource dataSource) { | |
SpringLiquibase liquibase = createSpringLiquibase(dataSource); | |
liquibase.setChangeLog(properties.getChangeLog()); | |
liquibase.setClearCheckSums(properties.isClearChecksums()); | |
liquibase.setContexts(properties.getContexts()); | |
liquibase.setDefaultSchema(properties.getDefaultSchema()); | |
liquibase.setLiquibaseSchema(properties.getLiquibaseSchema()); | |
liquibase.setLiquibaseTablespace(properties.getLiquibaseTablespace()); | |
liquibase.setDatabaseChangeLogTable(properties.getDatabaseChangeLogTable()); | |
liquibase.setDatabaseChangeLogLockTable(properties.getDatabaseChangeLogLockTable()); | |
liquibase.setDropFirst(properties.isDropFirst()); | |
liquibase.setShouldRun(properties.isEnabled()); | |
liquibase.setLabels(properties.getLabels()); | |
liquibase.setChangeLogParameters(properties.getParameters()); | |
liquibase.setRollbackFile(properties.getRollbackFile()); | |
liquibase.setTestRollbackOnUpdate(properties.isTestRollbackOnUpdate()); | |
liquibase.setTag(properties.getTag()); | |
return liquibase; | |
} | |
private SpringLiquibase createSpringLiquibase(DataSource dataSource) { | |
SpringLiquibase liquibase = new SkipMissingChangelogsSpringLiquibase(); | |
liquibase.setDataSource(dataSource); | |
return liquibase; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
tested with with spring 2.7.3