Don't store classpath: prefix in databasechangelog

Description

From http://forum.liquibase.org/topic/semantics-of-ignoreclasspathprefix#49382000001495008

I am using Liquibase through the Spring integration to run any changesets on application start-up. Since the changelog is part of a jar, I specify the location in one of my property files as:
liquibase.change-log = classpath:db/changelog/current.xml

Liquibase gets set up by Spring Boot's auto-configuration mechanism. When a changeset us run, the file name is recorded in DATABASECHANGELOG as classpath:db/changelog/current.xml.

I am also using the Gradle plugin to provide a way to update the database without running the application. When I run with the same changelog file, the recorded file name doesn't have the prefix (I am still loading it from the class path, by specifying it in the respective activity).

Liquibase provides the ignoreClasspathPrefix property (which is true by default) to deal with this discrepancy and it does work to some extent. If I apply the changesets through Gradle first, the Spring app will recognize that they have been run and skips them. However, if the changesets get executed by the Spring app first, gradle update will attempt to apply the changesets again and use the file name without the classpath: prefix.

It would seem that the ignoreClasspathPrefix property should remove the prefix from the file name before being recorded in DATABASECHANGELOG, to provide consistent behavior. Or am I missing something in my setup? Using Spring Boot 1.3.3.RELEASE and the Liquibase version it pulls by default (3.4.2). Any insights would be appreciated.

Environment

Spring

Activity

Show:

Pierrick Rouxel January 26, 2021 at 1:00 PM
Edited

I experience the same issue.

It works with this config of gradle plugin:

liquibase { activities { main { changeLogFile '/db/changelog/db.changelog-master.yaml' classpath "$projectDir/src/main/resources/" } } }

Spring writes filename with the classpath: prefix but it’s ignored by spring integration and cli.

Ruslan Stelmachenko January 27, 2020 at 4:24 AM

@Nathan I can try to create a PR to implement this behavior. But please tell me if you agree with the approach. What do you think about setting a filename with already stripped classpath: prefix right into filePath field of ChangeSet class (if logical file name is not set, of course)?

Ruslan Stelmachenko January 27, 2020 at 4:12 AM

@Dennis SpringLiquibase class is part of liquibase-core, so, I think no, it hasn’t to be a Spring issue.

@Nathan I agree this would be best to fix it when it saved. Even earlier: when filename of changeset is calculated. Because, if classpath: prefix will be removed just before save into DB, it is still possible to catch a filename mismatch when spring runs liquibase update and liquibase tries to match changesets (filename will not match).

There are many bugs related to ignoreClasspathPrefix flag now. E.e. it doesn’t taken into account when md5sum is recalculated (after clearCheckSums). Changesets with classpath: prefix in their filename are ignored by maven plugin, and changesets without classpath: prefix are ignored by spring (leaving md5sum column as null).

I see this pattern in the code of Liquibase class at several places (implementations of rollback method):

DatabaseChangeLog changeLog = getDatabaseChangeLog(); checkLiquibaseTables(false, changeLog, contexts, labelExpression); changeLog.validate(database, contexts, labelExpression); changeLog.setIgnoreClasspathPrefix(ignoreClasspathPrefix);

As you can see, the ignoreClasspathPrefix flag is set to DatabaseChangeLog only in 4th line. But this DatabaseChangeLog is passed into checkLiquibaseTables method earlier. And checkLiquibaseTables method uses DatabaseChangeLog.getChangeSet method, which uses normalizePath method, which checks ignoreClasspathPrefix flag, which is always false at this stage, because it is the default value in DatabaseChangeLog class and because it isn’t updated from Liquibase class as soon as DatabaseChangeLog instance is created. Other methods of Liquibase class doesn’t set ignoreClasspathPrefix flag on DatabaseChangeLog at all (update, changeLogSync etc).

Maybe changeLog.setIgnoreClasspathPrefix(ignoreClasspathPrefix); should be run from inside getDatabaseChangeLog() method? This way it will always return properly initialized DatabaseChangeLog instance.

 

So, this classpath: prefix creates many problems. To get rid of the most of them, I think, the filePath field of ChangeSet class should be normalized as soon as possible, e.g. when it calculated for changeset, so the ChangeSet object will contain already normalized filePath (if it will not break other functionality, of course). I see now the javadoc of this field as “File changeSet is defined in. May be a logical/non-physical string. It is included in the unique identifier to allow duplicate id+author combinations in different files”. If it can contain a logical name, then it can contain a name without classpath: prefix also, I think?

P.S. Take care that in Spring, any classpath can have a leading slash (e.g. classpath:/db/changelog.xml). While it is ignored by spring itself (classpath:/db/changelog.xml is virtually the same as classpath:db/changelog.xml) it is not ignored when Liquibase compares ChangeSets. Even after stripping classpath: prefix the filename can be still different because of this leading slash. So, it would be best to strip this also, if it exist right after classpath: prefix.

Dennis Effing April 18, 2019 at 8:43 AM

Shouldn't this be a Spring issue? The ignoreClasspathPrefix property is implemented by Spring itself (and, as far as I can tell, not Liquibase).

I tested running Liquibase using the Liquibase Gradle Plugin and it inserted the database changelog just fine without a classpath: prefix. However, Spring inserts any database changelog using the prefix. The issue is that while Spring strips the prefix when checking which changes have been run already, the Liquibase CLI does not.

There are two ways to fix this issue:
1. Provide a way to strip the prefix when using the CLI
2. Create a PR for Spring to not use the prefix when saving the filename of the change log

Details

Reporter

Fix versions

Affects versions

Priority

Created May 19, 2016 at 4:16 PM
Updated January 26, 2021 at 1:01 PM

Flag notifications