10

My package structure is looks like:

enter image description here

In /db.changelog/db.changelod-master.xml i include /db.changelog/v1/db.changelog-1.0.xml where i also include all changelogs from /db.changelog/v1/changeset package.

In my application, I have two profiles: dev and prod, and I need to divide the structure of packages according to "Best Practises" of Liquibase. Some changelogs can be in prod and dev environment.

Also, I can use context attribute in changeset tag and explicitly set dev or prod value, but this workaround is not preferable.

Simple usage looks like: i switch to prod profile and some tables will not be created or some inserts to Database will be skipped.

Can you please help me refactor structure of packages according to Liquibase "Best Practices??

Abzelhan
  • 510
  • 1
  • 7
  • 26
  • 1- How did you defined dev and prod profile in your application? 2- Which build tools did you used? (Maven, Gradle ,...) 3- What is the difference between change-log of dev and prod profile? Are there in separated path? – M-Razavi Oct 04 '18 at 12:25
  • 1
    @M-Razavi, 1. We define profile in maven inside tag, and also in resource module we have separated packages named: dev, prod, test. In each package we have different application.properties file. 2. Maven 3. For prod we have reference values such as list of city and etc. For dev we also have reference values but also some predefined data that required for development environment and this data must not be loaded after we switch profile to prod in maven. 3. All changelogs located in package that i show in screenshot, and i need to separate changelogs according to environment. – Abzelhan Oct 04 '18 at 12:46

2 Answers2

9

Solution1:
You need to define 'liquibase.contexts' property into your yaml file. Something like below.

spring:
  profiles: dev
  datasource:
    url: jdbc:postgresql://localhost:5432/dev
    username: postgres
    password: password
    driver-class-name: org.postgresql.Driver
liquibase:
   contexts: dev

After adding this the below change set will only execute when your local profile is 'dev' (i.e. spring-boot:run -Dspring.profiles.active=dev)

<changeSet id="20161016_my_first_change2" author="krudland" context="dev">
    <sql>
        insert into customer (firstname, lastname) values ('Franklin','Ike');
    </sql>
    <rollback>
        delete from customer where firstname = 'Franklin' and lastname = 'Ike';
    </rollback>
</changeSet>

Solution2:
If you don't want to use liquibase.context, You might can use maven to filter recourses : The key was to use the maven filter element in conjunction with the resource element as explained in Liquibase Documentation.

Also it's important to include the resources goal in the maven command:

mvn resources:resources liquibase:update -Plocal

This is the file hierarchy I used:

|-- pom.xml
`-- src
    `-- main
       |-- resources
       |   `-- liquibase.properties
       |   |-- changelog
       |       `-- db-changelog-master.xml
       |       `-- db-changelog-1.0.xml
       |-- filters
           |-- local
           |   `-- db.properties
           |-- dev
           |   `-- db.properties

The db.properties file would look like the following:

database.driver = oracle.jdbc.driver.OracleDriver
database.url = jdbc:oracle:thin:@<host_name>:<port_number>/instance
database.username = user
database.password = password123
database.changelogfile = db.changelog-master.xml

The liquibase.properties file would look like the following:

changeLogFile: changelog/${database.changelogfile}
driver: ${database.driver}
url: ${database.url}
username: ${database.username}
password: ${database.password}
verbose: true

The POM file would look like the following:

<build>
      <pluginManagement>
         <plugins>
            <plugin>
               <groupId>org.liquibase</groupId>
               <artifactId>liquibase-maven-plugin</artifactId>
               <version>3.1.0</version>
               <configuration>
                  <propertyFile>target/classes/liquibase.properties</propertyFile>
               </configuration>
            </plugin>
         </plugins>
      </pluginManagement>
   </build>


<profiles>
    <profile>
        <id>local</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <filters>
                <filter>src/main/filters/local/db.properties</filter>
            </filters>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
        </build>
    </profile>
    <profile>
        <id>dev</id>
        <build>
            <filters>
                <filter>src/main/filters/dev/db.properties</filter>
            </filters>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
        </build>
    </profile>
</profiles>
M-Razavi
  • 3,327
  • 2
  • 34
  • 46
  • the question is: How to divide Liquibase package structure for dev and prod environment. In my question i specify that i can use contexts. I need to know how to divide changesets to separated xml files for prod and dev environments. – Abzelhan Oct 04 '18 at 13:28
  • @MisterMagic use resource filtering . I've updated my answer – M-Razavi Oct 05 '18 at 12:00
  • `spring: profiles: dev datasource: url: jdbc:postgresql://localhost:5432/dev username: postgres password: password driver-class-name: org.postgresql.Driver liquibase: contexts: dev` How about if I want to define multiple profiles/contexts? – SoT Jun 17 '20 at 11:06
  • @SoT which solution? – M-Razavi Jun 17 '20 at 17:49
  • Beside that, when I apply solution 2, I got error: Error setting up or running Liquibase: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: Connection could not be created to ${database.url} with driver org.postgresql.Driver. Seem that it cannot ịnêct the value from dev/db.properties to liquibase.properties – SoT Jun 18 '20 at 06:31
  • the link to Liquibase Documentation is broken – Ali Behzadian Nejad Jun 25 '22 at 21:57
  • Hi @M-Razavi, it looks like you just copied this content from others people answers. [Here](https://stackoverflow.com/a/44896267/2672193) is a link to the answer in Solution 1 and [here](https://stackoverflow.com/a/22376004) is link to the answer in solution 2. Can you edit your post and give attribution to the author? Plagiarism isn't really welcomed on Stack Overflow, and it's always nice to give credit where credit is due. Good luck! – frenky Aug 02 '22 at 20:47
  • Thanks, @frenky, I added links. I didn't know that links are required. – M-Razavi Aug 03 '22 at 15:09
2

As for me, I put dev, prod into different change set with different context.

There are stayed in the same file.

<changeSet author="test" id="API-111" context="dev">
    <sql>
        insert into api_key(id, value) values (1, 'dev_value');                   
    </sql>
</changeSet>

<changeSet author="test" id="API-111" context="uat">
    <sql>
        insert into api_key(id, value) values (1, 'uat_value');                   
    </sql>
</changeSet>    

<changeSet author="test" id="API-111" context="prod">
    <sql>
        insert into api_key(id, value) values (1, 'prod_value');                   
    </sql>
</changeSet>  
sendon1982
  • 9,982
  • 61
  • 44