Last active
October 14, 2025 19:26
-
-
Save stackunderflow111/8b90e77d688ae64186bb4d23dfeb41ac to your computer and use it in GitHub Desktop.
Integrate Jooq with Testcontainers and Flyway
This file contains hidden or 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 nu.studer.gradle.jooq.JooqGenerate | |
| import org.flywaydb.core.Flyway | |
| import org.flywaydb.core.api.configuration.FluentConfiguration | |
| import org.jooq.meta.jaxb.Configuration | |
| import org.testcontainers.containers.JdbcDatabaseContainer | |
| import org.testcontainers.containers.PostgreSQLContainer | |
| import org.testcontainers.utility.DockerImageName | |
| plugins { | |
| id("nu.studer.jooq") version "7.1.1" | |
| } | |
| fun startContainer(imageName: String): JdbcDatabaseContainer<*> { | |
| // for why we need the <Nothing> here, see | |
| // https://kotlinlang.org/docs/whatsnew1530.html#improvements-to-type-inference-for-recursive-generic-types | |
| // note that our current Gradle version uses an older version of Kotlin, and we have to use the "older" way | |
| val container = PostgreSQLContainer<Nothing>(DockerImageName.parse(imageName)) | |
| container.start() | |
| // register a buildFinished hook so that the container will be stopped when build finishes | |
| // otherwise the container will only stop when the Gradle daemon stops | |
| gradle.buildFinished { | |
| container.stop() | |
| } | |
| return container | |
| } | |
| fun flywayMigrate(container: JdbcDatabaseContainer<*>, migrationFilesLocation: String) { | |
| val configuration: FluentConfiguration = Flyway.configure() | |
| .dataSource(container.jdbcUrl, container.username, container.password) | |
| // the "filesystem:" prefix is required, otherwise flyway will treat "migrationFilesLocation" as classpath | |
| .locations("filesystem:$migrationFilesLocation") | |
| val flyway: Flyway = configuration.load() | |
| flyway.migrate() | |
| } | |
| fun modifyJooqConfiguration(jooqGenerate: JooqGenerate, container: JdbcDatabaseContainer<*>) { | |
| // this is the same as val jooqConfiguration = jooqGenerate.jooqConfiguration, | |
| // but it's a private field, so I have to bypass the access restriction using reflection | |
| val jooqConfigurationField = JooqGenerate::class.java.getDeclaredField("jooqConfiguration") | |
| jooqConfigurationField.isAccessible = true | |
| val jooqConfiguration = jooqConfigurationField.get(jooqGenerate) as Configuration | |
| jooqConfiguration.jdbc.apply { | |
| url = container.jdbcUrl | |
| user = container.username | |
| password = container.password | |
| } | |
| } | |
| tasks.named<JooqGenerate>("generateJooq") { | |
| val migrationFilesLocation = "location" | |
| // Make the generateJooq task dependent on the migration scripts so we get proper build caching | |
| // (trigger a clean rebuild only when the files change) | |
| inputs.files(fileTree(migrationFilesLocation)) | |
| .withPropertyName("migrations") | |
| .withPathSensitivity(PathSensitivity.RELATIVE) | |
| // Let the task participate in incremental builds and build caching | |
| allInputsDeclared.set(true) | |
| outputs.cacheIf { | |
| true | |
| } | |
| // starts the postgres container and runs the migration before generating Jooq files | |
| doFirst { | |
| val container = startContainer("postgres:13-alpine") | |
| flywayMigrate(container, migrationFilesLocation) | |
| modifyJooqConfiguration(this as JooqGenerate, container) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Don't suppose you've ever managed this with liquibase?