Liquibase equivalent of beforeEachMigrate in Flyway - liquibase

I am trying to find the Flyway's beforeEachMigrate equivalent functionality in liquibase. Does liquibase have a way to execute an SQL script before each new migration script is executed?
My current liquibase structure looks like follows.
application.properties file
spring.liquibase.change-log=classpath:db/changelog/changelog-master.yaml
changelog-master.yaml file
databaseChangeLog:
- include:
file: db/changelog/1-initial-schema.sql
- include:
file: db/changelog/2-schema-update.sql

create something like db/changelog/00-init.sql
and put there something like
<changeSet id="1" author="you" runAlways="true">
<sql>...or whatever change</sql>
</changeSet>
note: use runAlways
EDIT: I'm looking into beforeEachMigrate and it executes change before each let's say changeSet. There is no equivalent for that in liquibase so far.

Adding onto what #bilak said, you can also set the parameter using runOrder in addition to runAlways.
Documentation: To always run a changeset before OR after an update - runAlways/runOrder - https://docs.liquibase.com/concepts/changelogs/changelog-formats.html

Related

Liquibase Type Mapping MySQL & SQL Server

From command line I let liquibase run in the version 4.19.0.
liquibase --changeLogFile=update.xml update
where update.xml is a bundle of changelogs:
<databaseChangeLog ...
<include file="changelog_1.xml" relativeToChangelogFile="true"/>
<include file="changelog_2.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
The first run ends with an error:
Unexpected error running Liquibase: Data type definition contains unparseable embedded information: ${dbtype.varchar}(20)
So far as I understand the ${dbtype.varchar} comes from my company and in Java code I see a replacement.
My question is for MySQL ${dbtype.varchar} should be replaced with VARCHAR and for SQL Server with nvarchar.
Is there an easy way to tell liquibase to replace this placeholder with MySQL values?
In the liquibase.properties I tell liquibase that it should be done for MySQL.
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
classpath: /home/markus/drivers/mysql-connector-java-5.1.49.jar
EDIT:
I found inside the Liquibase documentation how I can do it with properties from outside.
liquibase --changeLogFile=batch_changelogs.xml update -Ddbtype.bigint=BIGINT -Ddbtype.ubigint='BIGINT UNSIGNED'
It's not exaclty what I'm looking for but at the momement is comfortable to use.
Thanks,
Markus
Finally I found it inside the documentation
In liquibase.properties I can add with the parameter.
parameter.dbtype.bigint=BIGINT
parameter.dbtype.ubigint='BIGINT UNSIGNED'
Solved for MySql. For MSSQL I will generate a new property file and change by exeuction.

Can Liquibase Autopick new changesets files like Flyway?

I am new to both Liquibase and Flyway. Was trying to do some Hello Worlds. I successfully ran basic SQL ( create insert etc ) using both Liquibase and Flyway. Was interested in running them from command line.
Flyway :
was kind of easy to start with
I had to just Put sql file in correct naming format 'V1_xxxx.sql' in correct folder 'flyway/sql' & Run 'flyway migrate'
the best part was it automatically picked up any new sql file given the correct file name.
LiquiBase :
had to spend some time to understand and use it
Need to give correct file name each time
liquibase --driver=com.mysql.jdbc.Driver --classpath=/path/to/classes --changeLogFile=com/example/db.changelog1.xml --url="jdbc:mysql://localhost/example" --username=dev migrate
liquibase --driver=com.mysql.jdbc.Driver --classpath=/path/to/classes --changeLogFile=com/example/db.changelog2.xml --url="jdbc:mysql://localhost/example" --username=dev migrate
Is there a way in liquibase to automatically pick the new xml files ? like Flyway i could just give folder name and Liquibase could use its table DATABASECHANGELOG to find the deltas and execute same.
Second Question for Liquibase only
In windows in order to run command successfully i had to change the changeLogFile parameter ... from ...
liquibase --driver=com.mysql.jdbc.Driver --classpath=/path/to/classes --changeLogFile=com/example/db.changelog1.xml --url="jdbc:mysql://localhost/example" --username=dev migrate
to
liquibase --driver=com.mysql.jdbc.Driver --classpath=/path/to/classes --changeLogFile=./db.changelog1.xml --url="jdbc:mysql://localhost/example" --username=dev migrate
i.e. i changed my present working directory to com/example and then modified the changeLogFile param to point to a file in current folder and execute command.
Is there a way i can point to changeLogFile in another folder (apart from current folder)
One thing you can do to make liquibase a bit easier to use from the commandline is to create a file named liquibase.properties and save that in the directory where you are running the command. If I remember correctly, the command line will look for files with that name and use the properties in that file rather than requiring all the options on the command line. See http://www.liquibase.org/documentation/liquibase.properties.html and http://www.liquibase.org/documentation/command_line.html#using_a_liquibase.properties_file for more details. The docs there have this:
If you do not want to always specify options on the command line, you
can create a properties file that contains default values. By default,
Liquibase will look for a file called “liquibase.properties” in the
current working directory, but you can specify an alternate location
with the --defaultsFile flag. If you have specified an option in a
properties file and specify the same option on the command line, the
value on the command line will override the properties file value.
Yes, you can have liquibase automatically load files from a directory. You have to have a simple changelog.xml that is referenced from the command line or your properties file, but then that changelog can just reference another directory that contains more changelog files. The <includeAll> tag is used for this purpose (see http://www.liquibase.org/documentation/includeall.html) for more details.
Also, yes, you can put the changelog file wherever you like.

can't get liquibase executeCommand changeset to do anything

From the liquibase docs, it looks like an executeCommand changeset should just shell out and execute the given command (e.g., mysqldump). But if I specify some changeset like
<changeSet author="me" id="test">
<executeCommand executable="date" />
</changeSet>
then all I get is this error message
2016-07-20 10:02:43,675 ERROR [main] liquibase
even though the changeset gets marked as EXECUTED in the db.
Even if I specify some different executable like a tiny test shell script, it doesn't look like it actually gets executed.
Is there anything else that I need to specify in the changeset, or do I have some incorrect expectation about how an executeCommand changeset should work?

Using Liquibase contexts to conditionally activate/deactivate a change set

We have changeset one:
--changeset change_one runOnChange:true
And changeset two:
--changeset change_two runOnChange:true context:kansas
change_one applies to all our installations but change_two only applies to our "kansas" installation. We want to ensure that change_two is executed whenever change_one is changed - how can we do this?
change_one has runOnChange:true so it will run whenever changed. But how can we ensure change_two runs when change_one executes - but only when we pass context:kansas?
When you run Liquibase without specifying any contexts, you might expect that no contexts should be activated, but in fact it works as documented in that ALL contexts will be activated. If you use contexts in your change logs to disable change sets, you will have to set a contexts parameter whenever you execute Liquibase. e.g.
mvn process-resources liquibase:update -Dliquibase.contexts=production
You should also check into the labels feature added in Liquibase 3.3. The difference is that the caller can specify some sophisticated expressions. e.g.
mvn process-resources liquibase:update -Dliquibase.labels=!kansas
Note, however, that the behavior is the same as contexts when no label expression is specified.
Example Change Sets:
<changeSet id="tag-v1" author="a">
<tagDatabase tag="v1"/>
</changeSet>
<changeSet id="tag-v1a" author="a" context="kansas">
<tagDatabase tag="v1a"/>
</changeSet>
<changeSet id="tag-v1b" author="a" labels="kansas">
<tagDatabase tag="v1b"/>
</changeSet>

How to configure liquibase not to include file path or name for calculating checksum?

I found that liquibase uses the full path of the change log file to calculate the checksum.
This behavior restricts to modify change log file names and tries to reapply the change sets again once renamed the file.
Is there a way to configure liquibase to use only the changelog id to
calculate cuecksum?
Please provide your valuable thoughts.
Use the attribute logicalFilePath of the databaseChangeLog tag.
Upstream developers recommend to use logicalFilePath and suggest to perform direct update on DATABASECHANGELOG.FILENAME column:
https://forum.liquibase.org/t/why-does-the-change-log-contain-the-file-name/481
to fix broken entries with full paths.
If you set hashes DATABASECHANGELOG.MD5SUM to null that triggers hashes recalculation on next LiquiBase run. It is necessary as hash algorithm includes moving parts too into the result.
One really similar issue- you may just want to ignore the portion of the path before the changelog-master.xml file. In my scenario, I've checked out a project in C:\DEV\workspace and my colleague has the project checked out in C:\another_folder\TheWorkspace.
I'd recommend reading through http://forum.liquibase.org/topic/changeset-uniqueness-causing-issues-with-branched-releases-overlapped-changes-not-allowed-in-different-files first.
Like others have suggested, you'll want the logicalFilePath property set on the <databaseChangeLog> element.
You'll also need to specify the changeLogFile property in a certain way when calling liquibase. I'm calling it from the command line. If you specify an absolute or relative path to the changeLogFile without the classpath, like this, it will include the whole path in the DATABASECHANGELOG table:
liquibase.bat ^
--changeLogFile=C:\DEV\more\folders\schema\changelog-master.xml ^
...
then liquibase will break if you move your migrations to any folder other than that one listed above. To fix it (and ensure that other developers can use whatever workspace location they want), you need to reference the changelogFile from the classpath:
liquibase.bat ^
--classpath=C:\DEV\more\folders ^
--changeLogFile=schema/changelog-master.xml ^
...
The first way, my DATABASECHANGELOG table had FILENAME values (I might have the slash backwards) like
C:\DEV\more\folders\schema\subfolder\script.sql
The second way, my DATABASECHANGELOG table has FILENAME values like
subfolder/script.sql
I'm content to go with filenames like that. Each developer can run liquibase from whatever folder they want. If we decide we want to rename or move an individual SQL file later on, then we can specify the old value in the logicalFilePath property of the <changeSet> element.
For reference, my changelog-master.xml just consists of elements like
<include file="subfolder/script.sql" relativeToChangelogFile="true"/>
I have faced the same problem and found solution below.
If you are using liquibase sql format then simply put below in your sql file:
--liquibase formatted sql logicalFilePath:<relative SQL file path like(liquibase/changes.sql)>
If you are using liquibase xml format then simply put below in your xml file:
<databaseChangeLog logicalFilePath=relative XML file path like(liquibase/changes.xml)" ...>
...
</databaseChangeLog>
After adding above logicalFilePath attribute, run the liquibase update command.
It will put relative file path whatever you put in logicalFilePath in FILENAME column of table DATABASECHANGELOG