How to generate jOOQ classes from Testcontainers database migrated with Flyway during Gradle build? - gradle

I am trying to generate jOOQ classes from a database running in docker container(Testcontainers) which will be migrated with flyway during gradle build. I am new to gradle and I created working proof of concept which does not feel right, because I have to start the container in configuration phase, so the database url, password and username are available to configuration extensions(flyway and jooq). Then I have to register container stop using deprecated method buildFinished
I would like for the container to start only when generateJooq task needs to be run. Ideally there would be three tasks, first would start the container with database, second would migrate the started database with flyway and third would generate jooq classes, and after that, stop the running container. Any advice how to do that?
import org.testcontainers.containers.PostgreSQLContainer
plugins {
id("org.flywaydb.flyway") version "8.5.13"
id("nu.studer.jooq") version "7.1.1"
}
repositories {
mavenCentral()
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.testcontainers:postgresql:1.17.3")
classpath("org.postgresql:postgresql:42.2.14")
}
}
val flywayMigration: Configuration by configurations.creating
dependencies {
flywayMigration("org.postgresql:postgresql:42.3.3")
jooqGenerator("org.postgresql:postgresql:42.3.3")
jooqGenerator("jakarta.xml.bind:jakarta.xml.bind-api:4.0.0")
}
var instance: PostgreSQLContainer<Nothing>? = null
task("postgreSQLContainer") {
instance = PostgreSQLContainer<Nothing>("postgres:11.6")
instance?.start()
gradle.buildFinished {
if (instance?.isRunning == true) {
instance?.stop()
}
}
}
flyway {
configurations = arrayOf("flywayMigration")
url = instance?.jdbcUrl
user = instance?.username
password = instance?.password
}
jooq {
configurations {
create("main") {
jooqConfiguration.apply {
logging = org.jooq.meta.jaxb.Logging.WARN
jdbc.apply {
driver = "org.postgresql.Driver"
url = flyway.url
user = flyway.user
password = flyway.password
}
generator.apply {
name = "org.jooq.codegen.DefaultGenerator"
database.apply {
inputSchema = "public"
}
target.apply {
packageName = "com.cleevio.jooq"
}
}
}
}
}
}
tasks.named<nu.studer.gradle.jooq.JooqGenerate>("generateJooq") {
dependsOn(tasks.named("postgreSQLContainer"))
dependsOn(tasks.named("flywayMigrate"))
inputs.files(fileTree("src/main/resources/db/migration"))
.withPropertyName("migrations")
.withPathSensitivity(PathSensitivity.RELATIVE)
allInputsDeclared.set(true)
}

Related

Is there a way to generate jooq code from flyway migrations?

I have a kotlin spring boot application which is using Jooq.
My database is postresql and I have flyway migrations configured for it.
The problem is that when I am in my dev environment there is no problem generating code for jooq, but when I try to deploy my app to my server (with github actions and docker compose) I cant build the project, because Jooq is trying to connect to database (which is not started yet) to generate necessary code.
My gradle build looks like this:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jooq.meta.jaxb.ForcedType
import org.jooq.meta.jaxb.Logging
import org.jooq.meta.jaxb.Property
val environment = System.getenv()
plugins {
id("org.springframework.boot") version "2.7.5"
id("io.spring.dependency-management") version "1.0.15.RELEASE"
kotlin("jvm") version "1.8.0"
kotlin("plugin.spring") version "1.8.0"
id("nu.studer.jooq") version "7.0"
}
group = "osu.salat23"
version = "ALPHA"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.flywaydb:flyway-core")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.github.yvasyliev:java-vk-bots-longpoll-api:3.5.3")
implementation("org.telegram:telegrambots-spring-boot-starter:6.3.0")
implementation("com.microsoft.playwright:driver-bundle:1.28.1")
implementation("com.microsoft.playwright:playwright:1.28.1")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
testImplementation("com.squareup.okhttp3:mockwebserver:4.10.0")
testImplementation("junit:junit:4.13.2")
jooqGenerator("org.postgresql:postgresql:42.5.1")
jooqGenerator("jakarta.xml.bind:jakarta.xml.bind-api:3.0.1")
}
configurations {
all {
exclude("org.apache.logging.log4j", "log4j-slf4j-impl")
}
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
jooq {
version.set("3.16.0") // default (can be omitted)
edition.set(nu.studer.gradle.jooq.JooqEdition.OSS) // default (can be omitted)
configurations {
create("main") { // name of the jOOQ configuration
generateSchemaSourceOnCompilation.set(false) // default (can be omitted)
jooqConfiguration.apply {
logging = Logging.WARN
jdbc.apply {
driver = "org.postgresql.Driver"
url = environment["DATABASE_URL"] ?: "jdbc:postgresql://localhost:5432/postgres"
user = environment["DATABASE_USER"] ?: "postgres"
password = environment["DATABASE_PASSWORD"] ?: "postgres"
properties.add(Property().apply {
key = "ssl"
value = "false"
})
}
generator.apply {
name = "org.jooq.codegen.DefaultGenerator"
database.apply {
name = "org.jooq.meta.postgres.PostgresDatabase"
inputSchema = "public"
forcedTypes.addAll(listOf(
ForcedType().apply {
name = "varchar"
includeExpression = ".*"
includeTypes = "JSONB?"
},
ForcedType().apply {
name = "varchar"
includeExpression = ".*"
includeTypes = "INET"
}
))
}
generate.apply {
isDeprecated = false
isRecords = true
isImmutablePojos = true
isFluentSetters = true
}
target.apply {
packageName = "osu.salat23.circler"
directory = "src/generated-src/jooq/main" // default (can be omitted)
}
strategy.name = "org.jooq.codegen.DefaultGeneratorStrategy"
}
}
}
}
}
Is there a way to generate code not from database but rather from my flyway migrations? I have tried to follow official documentation but there is so little information and also no gladle kotlin dsl code examples, so I am asking it here.
You could consider intentionally committing the jOOQ generated code to your repo instead of re-generating it every time as part your build process.
Basic idea is, when you intend to make a DB change, presumably you'll be in your dev environment: run the DB migrations, then generate the jooq code, change your project to compile with the new code, commit.
There are 2 ways to do this:
If you think you're not using anything RDBMS vendor specific, then jOOQ can emulate (simple) Flyway migrations (much like any SQL script based migrations and database setups, including dumps) using the DDLDatabase
If you're using RDBMS vendor specific things, or more advanced Flyway features, which can't be emulated simply (e.g. repeatable migrations), then ideally, you just set up a build that runs an actual Flyway migration prior to code generation, e.g. in testcontainers
The article above uses Maven, but it should work the same way with Gradle, in principle.
I solved my problem the following way:
Because I am using github actions for my CI CD pipelines, I added a postgres service (because I am using vendor specific features) to my gh actions config:
jobs:
  Deploy:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:14.0
        env:
          POSTGRES_DB: postgres
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout#v3
      - uses: actions/setup-java#v3
        with:
          distribution: adopt
          java-version: 18
      - name: Setup gradle
        uses: gradle/gradle-build-action#v2
      - name: Execute gradle build
        run: ./gradlew clean && ./gradlew build && ./gradlew bootJar
The CI database credentials are also written in my gradle jooq config. By doing this, I can build my jar inside actions runner and then send it by using SCP to my server through ssh. Flyway generates database and jooq then generates code. Pretty simple yet good setup (at least for me)
Before that, I wanted to setup test containers, but decided that is was too big of a hustle for me.
If anybody will run into the same issue - I can send my gradle config if needed for better clarity.
Here is my gradle file for jooq compatibility:
import nu.studer.gradle.jooq.JooqExtension
import nu.studer.gradle.jooq.JooqGenerate
import org.flywaydb.gradle.task.FlywayMigrateTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jooq.meta.jaxb.ForcedType
import org.jooq.meta.jaxb.Logging
import org.jooq.meta.jaxb.Property
val environment = System.getenv()
plugins {
id("org.springframework.boot") version "2.7.5"
id("io.spring.dependency-management") version "1.0.15.RELEASE"
kotlin("jvm") version "1.8.0"
kotlin("plugin.spring") version "1.8.0"
id("org.flywaydb.flyway") version "9.8.1"
id("nu.studer.jooq") version "7.0"
}
group = "osu.salat23"
version = "ALPHA"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
maven(url="https://jitpack.io")
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("io.micrometer:micrometer-registry-prometheus")
implementation("com.github.cvb941:kotlin-parallel-operations:1.5.0")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.flywaydb:flyway-core")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.github.yvasyliev:java-vk-bots-longpoll-api:3.5.3")
implementation("org.telegram:telegrambots-spring-boot-starter:6.3.0")
implementation("com.microsoft.playwright:driver-bundle:1.28.1")
implementation("com.microsoft.playwright:playwright:1.28.1")
runtimeOnly("org.postgresql:postgresql")
implementation("com.github.holgerbrandl:jsonbuilder:-SNAPSHOT")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
testImplementation("com.squareup.okhttp3:mockwebserver:4.10.0")
testImplementation("junit:junit:4.13.2")
jooqGenerator("org.postgresql:postgresql:42.5.1")
jooqGenerator("jakarta.xml.bind:jakarta.xml.bind-api:3.0.1")
}
configurations {
all {
exclude("org.apache.logging.log4j", "log4j-slf4j-impl")
}
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.withType<JooqGenerate> {
dependsOn("flywayMigrate")
}
flyway {
url = "jdbc:postgresql://localhost:5432/postgres"
user = "postgres"
password = "postgres"
schemas = arrayOf("public")
locations = arrayOf("filesystem:${project.projectDir}/src/main/resources/db/migration")
}
jooq {
version.set("3.16.0") // default (can be omitted)
edition.set(nu.studer.gradle.jooq.JooqEdition.OSS) // default (can be omitted)
configurations {
create("main") { // name of the jOOQ configuration
generateSchemaSourceOnCompilation.set(true) // default (can be omitted)
jooqConfiguration.apply {
logging = Logging.WARN
jdbc.apply {
driver = "org.postgresql.Driver"
url = "jdbc:postgresql://localhost:5432/postgres"
user = "postgres"
password = "postgres"
properties.add(Property().apply {
key = "ssl"
value = "false"
})
}
generator.apply {
name = "org.jooq.codegen.DefaultGenerator"
database.apply {
name = "org.jooq.meta.postgres.PostgresDatabase"
inputSchema = "public"
forcedTypes.addAll(listOf(
ForcedType().apply {
name = "varchar"
includeExpression = ".*"
includeTypes = "JSONB?"
},
ForcedType().apply {
name = "varchar"
includeExpression = ".*"
includeTypes = "INET"
}
))
}
generate.apply {
isDeprecated = false
isRecords = true
isImmutablePojos = true
isFluentSetters = true
}
target.apply {
packageName = "osu.salat23.circler"
directory = "generated/generated-src/jooq/main" // default (can be omitted)
}
strategy.name = "org.jooq.codegen.DefaultGeneratorStrategy"
}
}
}
}
}

Gradle common repositories for multi module project

I have below project setup for gradle scripts, but I would like to keep one single common repository file for both main and subprojects.
apply from : "$rootDir/gradle/repositories.gradle" does not work inside build.gradle for this purpose. It would work only if I declare repositories again inside build.gradle
**build.gradle**
--------------------------
{
repositories {
maven {
url "https://myprivate.repo.com/artifactory"
credentials {
username = "user1"
password = "psswd"
}
}
}
dependencies {
# some list of dependencies
}
}
**gradle/repositories.gradle**
-------------------------
repositories {
maven {
url "https://myprivate.repo.com/artifactory"
credentials {
username = "user1"
password = "psswd"
}
}
}
**subprojects.gradle**
--------------------------
subprojects {
apply from : "$rootDir/gradle/repositories.gradle"
}

How to access PlaginManager repositories from custom gradle plugin

My problem is that I develop a custom Gradle plugin and I need to get access to repositories which belongs to Settings object, particular PluginManagement object.
settings.gradle file of project which I connect my custom plugin looks like this:
pluginManagement {
resolutionStrategy {
}
repositories {
maven {
credentials {
username = System.getenv("USERNAME")
password = System.getenv("PASSWORD")
}
url = uri("${System.getenv("nexusUrl")}/repository/***")
}
}
}
There is my code I want to just list url of all repositories:
project.afterEvaluate {
val gradle = project.rootProject.gradle as org.gradle.invocation.DefaultGradle
val settings = gradle.settings as org.gradle.initialization.DefaultSettings
settings.pluginManagement.repositories.forEach { repo ->
run {
repo as MavenArtifactRepository
println(repo.url)
}
}
}
I expect the following output result:
https://nexus_url/repository/***
But instead I get 'null' in output.
But when I run this code from custom task I get expected result:
tasks.create("abc") {
project.afterEvaluate {
val gradle = project.rootProject.gradle as org.gradle.invocation.DefaultGradle
val settings = gradle.settings as org.gradle.initialization.DefaultSettings
settings.pluginManagement.repositories.forEach { repo ->
run {
repo as MavenArtifactRepository
println(repo.url)
}
}
}
}
Why are in execution time this repositories not empty and what is the best way to access them from Project object?

How to consolidate imported plugins to custom plugin in Gradle using Kotlin

I have microservices that will share some of the same configuration between all of them, mainly Jib, publish, and release. Not sure if it's possible to do the same for dependencies but it would be beneficial to include actuator and log4j2 in each. Here is the build.gradle.kts for one of my projects.
import net.researchgate.release.BaseScmAdapter
import net.researchgate.release.GitAdapter
import net.researchgate.release.ReleaseExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("com.gorylenko.gradle-git-properties") version "1.5.1"
id("com.google.cloud.tools.jib") version "1.6.1"
id("io.spring.dependency-management") version "1.0.7.RELEASE"
id("net.researchgate.release") version "2.8.1"
id("org.sonarqube") version "2.7.1"
id("org.springframework.boot") version "2.1.6.RELEASE"
kotlin("jvm") version "1.2.71"
kotlin("plugin.spring") version "1.2.71"
jacoco
`maven-publish`
}
java.sourceCompatibility = JavaVersion.VERSION_1_8
springBoot {
buildInfo {
group = project.properties["group"].toString()
version = project.properties["version"].toString()
description = project.properties["description"].toString()
}
}
repositories {
maven(url = uri(project.properties["nexus.url.gateway"].toString()))
mavenCentral()
}
dependencies {
// Kotlin
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// Spring
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-log4j2")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.cloud:spring-cloud-config-server")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Greenwich.SR3")
}
}
configurations.all {
exclude(group = "ch.qos.logback", module = "logback-classic")
exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging")
}
tasks {
withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "1.8"
}
}
build { dependsOn(clean) }
afterReleaseBuild { dependsOn(publish) }
publish { dependsOn(build) }
jibDockerBuild { dependsOn(build) }
jacocoTestReport {
reports {
html.isEnabled = false
xml.isEnabled = true
}
}
}
publishing {
publications {
create<MavenPublication>(project.name) {
from(components["java"])
pom {
scm {
connection.set("scm:git:git#github.com:company/${project.name}.git")
developerConnection.set("scm:git:git#github.com:company/${project.name}.git")
url.set("https://github.com/company/${project.name}/")
}
}
versionMapping {
usage("java-api") {
fromResolutionOf("runtimeClasspath")
}
usage("java-runtime") {
fromResolutionResult()
}
}
}
}
repositories {
maven {
val releasesRepoUrl = "${project.properties["nexus.url.publish"].toString()}/releases"
val snapshotsRepoUrl = "${project.properties["nexus.url.publish"].toString()}/snapshots"
url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
credentials {
username = project.properties["nexus.user"].toString()
password = project.properties["nexus.password"].toString()
}
}
}
}
fun ReleaseExtension.git(configureFn : GitAdapter.GitConfig.() -> Unit) {
(propertyMissing("git") as GitAdapter.GitConfig).configureFn()
}
release {
scmAdapters = mutableListOf<Class<out BaseScmAdapter>> ( GitAdapter::class.java )
git {
requireBranch = "develop"
pushToRemote = project.properties["release.git.remote"].toString()
pushReleaseVersionBranch = "master"
tagTemplate = "${project.name}.${project.version}"
}
}
jib {
from {
image = "openjdk:8-jdk-alpine"
}
to {
image = "host:port/${project.name}:${project.version}"
auth {
username = project.properties["nexus.user"].toString()
password = project.properties["nexus.password"].toString()
}
}
container {
workingDirectory = "/"
ports = listOf("8080")
environment = mapOf(
"SPRING_OUTPUT_ANSI_ENABLED" to "ALWAYS",
"SPRING_CLOUD_BOOTSTRAP_LOCATION" to "/path/to/bootstrap.yml"
)
useCurrentTimestamp = true
}
setAllowInsecureRegistries(true)
}
I was able to get a custom plugin created and added to this project using git#github.com:klg71/kotlintestplugin.git and git#github.com:klg71/kotlintestpluginproject.git but I have no idea how to implement these existing plugins and their configurations. In the main Plugin class in the apply function I am able to call the project.pluginManager.apply(PublishingPlugin::class.java) which causes the task to show in the project referencing the custom plugin but I can't figure out how to configure it and it does not successfully publish to the nexus server. I can publish the plugin itself to the nexus server and reference it in the microservice but it skips running the task, which I assume is caused by the configuration not being included. Also, when trying to apply/configure the Jib plugin, all of the classes are not visible when attempting to import.
So the above answer isn't super long and to preserve the issues I ran into I am posting a new answer.
PLUGIN
This portion of the answer is going to discuss the actual custom plugin project.
Because the plugins wrapper in the build.gradle.kts is runtime, the CustomPlugin.kt does not have access to it at compile time. My boss who is much smarter than me was kind enough to point this out to me even though he has never worked with gradle. Although I looked pretty dumb in front of him he still got me up and running by basically following the 'legacy' way of applying plugins in gradle.
plugins { // This is a runtime script preventing plugins declared here to be accessible in CustomPlugin.kt but is used to actually publish/release this plugin itself
id("net.researchgate.release") version "2.8.1"
kotlin("jvm") version "1.3.0"
`maven-publish`
}
repositories {
maven { url = uri("https://plugins.gradle.org/m2/") } // This is required to be able to import plugins below in the dependencies
jcenter()
}
dependencies {
compile(kotlin("stdlib"))
compile(kotlin("reflect"))
// These must be declared here (at compile-time) in order to access in CustomPlugin.kt
compile(group = "gradle.plugin.com.gorylenko.gradle-git-properties", name = "gradle-git-properties", version = "2.2.0")
compile(group = "gradle.plugin.com.google.cloud.tools", name = "jib-gradle-plugin", version = "1.7.0")
compile(group = "net.researchgate", name = "gradle-release", version = "2.8.1")
compile(group = "org.asciidoctor", name = "asciidoctor-gradle-plugin", version = "1.5.9.2")
compile(group = "org.jetbrains.dokka", name = "dokka-gradle-plugin", version = "0.9.18")
compile(group = "org.sonarsource.scanner.gradle", name = "sonarqube-gradle-plugin", version = "2.8")
implementation(gradleApi()) // This exposes the gradle API to CustomPlugin.kt
}
This allowed me to have access to jib and everything else in the CustomPlugin.kt.
The plugins jacoco and maven-publish are automatically accessible in the plugin project but still need to be added in the microservice project referencing the plugin. I was unable to find a workaround for this unfortunately.
I included the typical maven-publish plugin in the build.gradle.kts to push to nexus with the publishing task configurations in the build.gradle.kts as well so I could pull this from nexus in the microservice that wanted to use the plugin.
publishing {
publications {
create<MavenPublication>(project.name) {
from(components["java"])
pom {
scm {
connection.set("scm:git:git#github.com:diendanyoi54/${project.name}.git")
developerConnection .set("scm:git:git#github.com:diendanyoi54/${project.name}.git")
url.set("https://github.com/diendanyoi54/${project.name}/")
}
}
}
}
repositories {
maven {
val baseUrl = "https://${project.properties["nexus.host"].toString()}:${project.properties["nexus.port.jar"].toString()}/repository"
url = uri(if (version.toString().endsWith("SNAPSHOT")) "$baseUrl/maven-snapshots" else "$baseUrl/maven-releases")
credentials {
username = project.properties["nexus.user"].toString()
password = project.properties["nexus.password"].toString()
}
}
}
}
Lastly, you want to make sure you include the properties file that will tell the microservices where the plugin class is. In Intellij's IDEA, when typing the path to the implementation-class it auto completed for me.
The name of this file should reflect apply(plugin = "string") in the microservice's build.gradle.kts.
IMPLEMENTATION
This portion of the answer is going to reflect the microservice project that will be referencing the plugin. As stated above, jacoco and maven-publish still need to be added to the plugin block in the build.gradle.kts for some reason (I think because they are official gradle plugins).
To reference the plugin from the nexus server it was published to, the microservice must reference it in the buildscript.
buildscript { // Custom plugin must be accessed by this buildscript
repositories {
maven {
url = uri("https://${project.properties["nexus.host"].toString()}:${project.properties["nexus.port.jar"].toString()}/repository/maven-public")
credentials {
username = project.properties["nexus.user"].toString()
password = project.properties["nexus.password"].toString()
}
}
}
dependencies { classpath("com.company:kotlin-consolidated-plugin:1.0.0-SNAPSHOT") }
}
Lastly, the plugin must be applied using the properties file name referenced above.
apply(plugin = "com.company.kotlinconsolidatedplugin") // Custom plugin cannot reside in plugin declaration above
I created sample projects of these and posted them to Github so feel free to clone or take a look:
git#github.com:diendanyoi54/kotlin-consolidated-plugin.git
git#github.com:diendanyoi54/kotlin-consolidated-plugin-implementation.git
I was able to successfully able to use the github repo examples referenced above to accomplish what I needed with the publish task. Here is my custom plugin's build.gradle.kts.
plugins {
id("com.google.cloud.tools.jib") version "1.6.1"
id("org.sonarqube") version "2.7.1"
kotlin("jvm") version "1.3.0"
`maven-publish`
}
dependencies {
compile(kotlin("stdlib"))
compile(kotlin("reflect"))
implementation(gradleApi())
}
repositories {
jcenter()
}
publishing {
publications {
create<MavenPublication>(project.name) {
from(components["java"])
pom {
scm {
connection.set("scm:git:git#github.com:company/${project.name}.git")
developerConnection.set("scm:git:git#github.com:company/${project.name}.git")
url.set("https://github.com/company/${project.name}/")
}
}
}
}
repositories {
maven {
val baseUrl = "https://${project.properties["nexus.host"].toString()}:${project.properties["nexus.port.jar"].toString()}/repository"
url = uri(if (version.toString().endsWith("SNAPSHOT")) "$baseUrl/maven-snapshots" else "$baseUrl/maven-releases")
credentials {
username = project.properties["nexus.user"].toString()
password = project.properties["nexus.password"].toString()
}
}
}
}
Here is the CustomPlugin.kt class.
package com.company.gradlemicroserviceplugin
//import com.google.cloud.tools.jib.gradle.JibExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.plugins.PublishingPlugin
import org.gradle.testing.jacoco.tasks.JacocoReport
import java.net.URI
open class CustomPlugin : Plugin<Project> {
override fun apply(project: Project) {
// applySonar(project)
applyPublish(project)
// applyJib(project)
}
// private fun applySonar(project: Project) {
// project.pluginManager.apply("sonarqube")
// val task = project.task("jacocoTestReport") as JacocoReport
// task.reports = JacocoReport()
// jacocoTestReport { This was nested in the tasks declaration in build.gradle.kts so the fields below are the fields I'm trying to set in task.reports
// reports {
// html.isEnabled = false
// xml.isEnabled = true
// }
// }
// }
private fun applyPublish(project: Project) {
project.pluginManager.apply(PublishingPlugin::class.java)
val publishingExtension = project.extensions.findByType(PublishingExtension::class.java)
val mavenPublication = publishingExtension?.publications?.create(project.name, MavenPublication::class.java)
publishingExtension?.repositories?.maven {
val baseUrl = "https://${project.properties["nexus.host"].toString()}:${project.properties["nexus.port.jar"].toString()}/repository"
it.url = URI(if (project.version.toString().endsWith("SNAPSHOT")) "$baseUrl/maven-snapshots" else "$baseUrl/maven-releases")
it.credentials { cred ->
cred.username = project.properties["nexus.user"].toString()
cred.password = project.properties["nexus.password"].toString()
}
}
mavenPublication?.from(project.components.findByName("java"))
mavenPublication?.pom?.scm {
it.connection.set("scm:git:git#github.com:company/${project.name}.git")
it.developerConnection.set("scm:git:git#github.com:company/${project.name}.git")
it.url.set("https://github.com/company/${project.name}/")
}
}
// private fun applyJib(project: Project) {
// project.pluginManager.apply(JibPlugin::class.java)
//
// }
}
There are definitely areas of improvement on this but at least I got something working here. There is maven-publish logic in both build.gradle.kts because I push to the custom plugin to nexus and the maven-publish logic is in the CustomPlugin.kt class so the microservice that references this plugin can use it. However, I am unable to successfully setup Jib and Sonar. Jib doesn't give me access to anything in com.google.cloud.tools.jib.gradle preventing me from using the same approach as I used in maven-publish.
For Sonar I think I'm on the right track with retrieving the task by its name but I'm unable to set any fields that belong to task.reports because they are all final and this is necessary for Sonar to properly analyze Kotlin.
Applying built-in plugins
plugins {
java
id("jacoco")
}
You can also use the older apply syntax:
apply(plugin = "checkstyle")
Applying external plugins
plugins {
id("org.springframework.boot") version "2.0.1.RELEASE"
}
i am not good in kotlin but here is link to better understanding missing migration guide to the Gradle Kotlin DSL

Gradle load properties from file and use it in liquibase task

I am trying to load properties and use it in liquibase task. I am able to load the properties and able to print it out. But when I use it in liquibase task, gradle complains that properties are not found.
I am using:
classpath 'org.liquibase:liquibase-gradle-plugin:1.1.0'
Loading properties:
def springApplicationProperties = "src/main/resources/application-${System.env.SPRING_PROFILES_ACTIVE}.properties"
def springProps = new Properties()
InputStream is = new FileInputStream("${springApplicationProperties}")
springProps.load(is)
println "${springProps['spring.datasource.url']}"
Liquibase block:
liquibase{
activities {
main {
changeLogFile 'src/main/database/changelog.groovy'
url ${springProps['spring.datasource.url']}
username ${springProps['spring.datasource.user']}
password ${springProps['spring.datasource.password']}
}
}
runList = 'main'
}
And I am getting
No such property: $springProps for class:
org.liquibase.gradle.Activity
Looks like springProps is not visible in the liquibase activity. I tried to use ext and project scope, both not visible in liquibase block.
It will work this way:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.liquibase:liquibase-gradle-plugin:1.1.0'
}
}
apply plugin: 'java'
apply plugin: 'org.liquibase.gradle'
ext.springProps = new Properties()
InputStream is = new FileInputStream("src/main/resources/lol.properties")
springProps.load(is)
liquibase {
activities {
main {
url springProps['spring.datasource.url']
username springProps['spring.datasource.user']
password springProps['spring.datasource.password']
}
}
runList = 'main'
}
You unnecessarily added ${}. I've changed script a bit while trying out myself - but it has no side effects.

Resources