2

I am modularising a monolith developed in Java, It utilizes the Micronaut framework and Gradle as a Build tool. As the title suggests, It utilizes Liquibase for database migrations.

The old structure:

It's a standard single Gradle java project with the war plugin to generate a war file. It has all the migrations in the src/main/java/resources folder (standard micronaut-liquibase stuff)

The new structure:

I am breaking down various independent domains into separate Gradle projects. And I have made a startup project which should have all the project initialization logic like Micronauts context init and Liquibase DB migrations.

project/
|
+---gradle-project-A/
|   |
|   +---build.gradle
|   |
|   +---src/main/java/
|   |
|   +---src/test/
|       |
|       +---java/TestIntegration.java
|       |
|       +---resources/application.yml (for testing)
|
+---startup/
|   |
|   +---build.gradle
|   |
|   +---src/main/java/Application.java
|   |
|   +---src/main/java/resources/
|       |
|       +---db/changelog.sql files (These files are referred by the changelog.yml)
|       +---liqiubase-changelog.yml (Liquibase looks for this file in classpath)
|       +---application.yml (Micronaut config)
|
+---settings.gradle
|
|

Of course, there will be many more Gradle projects gradle-project-B, C...

Ultimately, The startup will produce a war file that will include gradle-project-A as a jar dependency. This is the structure I thought of.

so, startup depends on every other Gradle project

a stripped-down version of startup/build.gradle

plugins {
    'io.micronaut.application'
    'war'
}

dependencies {
    implementation project(':gradle-project-A')
}

The Problem

  • As the folder structure suggests, there are Integration tests that require all the liquibase migrations to be pre-applied to the database (test container)
  • In the old structure the migrations were picked up while executing tests because they were in the same Gradle project.
  • Now, the migrations are part of startup and they are obviously not being picked up while running Integration Tests in gradle-project-A

My Research so far

  • The new project structure was inspired by this post
  • My question seems similar to this question on StackOverflow but I am not sure I understand it correctly (Not a Gradle expert)

The Question

  • How do I get gradle-project-A to detect liqiubase-changelog.yml in the classpath while running tests?
  • I can't have startup as a dependency of gradle-project-A as that will be a circular dependency. Can my module structure be improved?

Any suggestions from your side are welcome! Thanks for the help in advance...

hardik_pnp
  • 29
  • 1
  • 5

2 Answers2

1

You should create changelog file not for module, but for DB (some modules may share one DB). Then you may keep changelogs in shared configuration (see Change working directory for gradle multi-module project) and declare path to changelog module's DB in every needed module. For Spring Boot it could be looks like (in application.yaml):

spring.liquibase:
   changeLog: "file:${PROJECT_ROOT}/config/db/migration/db_a.sql"
Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
0

I would say that you need to split your migration scripts for project-A, project-B, etc.

So, inside project-A/src/main/java/resources/ you need to have migration scripts for project-A, same for project-B, etc. Then, inside your startup project you can have changelog.xml which looks like this:

<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.1.xsd">

    <include file="pathToChangeLogFromProjectA.xml" relativeToChangelogFile="true"/>
    <include file="pathToChangeLogFromProjectA.xml" relativeToChangelogFile="true"/>

</databaseChangeLog>

This way, startup will pick migration scripts for all projects and when you run tests for project-A, only scripts for that project will be run.

Spasoje Petronijević
  • 1,476
  • 3
  • 13
  • 27
  • Thanks for your input. It will be quite tedious to separate out migrations for the `project-A` and `project B`. Also, for integration tests, having the snapshot of the entire database schema would be better instead of just the schema related to project-A or project-B. what do you think? – hardik_pnp Jun 07 '21 at 03:48
  • I thought if you have tables related to the projectA and tables related to the projectB and you are running tests for projectA, it would be a little strange to run some migration script that creates tables related to the projectB. Why would you do that? If you have microservices every service should have an independent DB. Sure, you still have monolith and modules and not separate services and maybe your services are dependent in some way. In that case, maybe you can try to modify application.yaml inside projectA to reference to the liqiubase-changelog.yml inside startup? – Spasoje Petronijević Jun 07 '21 at 08:33