Use properties in gradle liquibase - gradle

I'm trying to run liquibase scripts to create Posgresql DB + schemas.
Here're some pieces of liquibase .groovy configs and scripts and build.gradle.
build.gradle
apply plugin: 'liquibase'
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath 'org.liquibase:liquibase-gradle-plugin:1.2.0'
classpath "org.postgresql:postgresql:${postgreJdbcDriverVersion}"
}
}
sourceSets {
main {
java {
srcDir 'src/main/liquibase'
}
}
}
liquibase {
activities {
main {
File propsFile = new File("src/main/resources/database.properties")
Properties properties = new Properties()
properties.load(new FileInputStream(propsFile))
changeLogFile 'src/main/liquibase/com/freemmy/sample/spring/acl/sample/db/main-changelog.groovy'
url "${dbUrl}"
username "${dbUsername}"
password "${dbPassword}"
}
}
runList = 'main'
}
For example I have the following changeset in main-changelog.groovy:
changeSet(id: '2016-12-10-a', author: 'Dzmitry Dziokin', runInTransaction: false, runAlways: true, runOnChange: true, failOnError: false, dbms: 'postgresql') {
comment('Create the database role/login')
// Ok if the role exists
preConditions(onFail: 'CONTINUE', onFailMessage: 'Role already exists, continue') {
sqlCheck(expectedResult: '0')
{ "select count(*) from pg_roles where rolname= '${dbUsername}'" }
}
sql(stripComments: true, splitStatements: false, endDelimiter: ';') {
"CREATE ROLE ${dbUsername} LOGIN PASSWORD '${dbPassword}'"
}
}
And I have properties dbUsername and dbPassword.
But when I run, for instance, gradlew status I see the following:
Execution failed for task ':spring-acl-sample-db:status'.
liquibase.exception.LiquibaseException: Unexpected error running Liquibase: No such property: dbUsername for class: org.liquibase.groovy.delegate.PreconditionDelegate
I asked Google, but I haven't found any solution or suggestion.
Does someone know what is happening?

I assume that dbUsername and dbPassword are defined in your property file.
You'll have to define dbUsername and dbPassword in your gradle script :
def dbUsername = properties.getProperty("dbUsername")
def dbPassword = properties.getProperty("dbPassword")

You should probably use the properties prefix in the interpolation.
url "${properties.dbUrl}"
username "${properties.dbUsername}"
password "${properties.dbPassword}"

Related

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

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)
}

Liquibase module and a variable in Spring Boot Project

I use liquibase in my project, and here is one of my config files:
databaseChangeLog:
- changeSet:
id: 123
author: m.rybalkin
changes:
- update:
columns:
- column:
name: code
value: '123'
schemaName: prod
tableName: config_bundle
where: code='321'
Here is my build.gradle of the "liquibase" module:
group 'com.project.test'
version '0.1.0'
buildscript {
dependencies {
classpath "org.liquibase:liquibase-gradle-plugin:${liqubasePluginVersion}"
classpath "gradle.plugin.com.avast.gradle:gradle-docker-compose-plugin:${gradleDockerComposePluginVersion}"
}
}
apply plugin: 'java'
apply plugin: 'org.liquibase.gradle'
apply plugin: 'com.avast.gradle.docker-compose'
dependencies {
liquibaseRuntime "org.liquibase:liquibase-core:${liquibaseCoreVersion}"
liquibaseRuntime "org.postgresql:postgresql:${postgresqlVersion}"
}
liquibase {
activities {
main {
def file = new File("${projectDir}/liquibase.properties")
if (file.exists()) {
def props = new Properties()
InputStream is = new FileInputStream(file)
props.load(is)
is.close()
changeLogFile props['changeLogFile']
outputFile 'liquibase/sql-migration-bundle.sql'
url props['url']
username props['username']
password props['password']
} else {
println "Add ${projectDir}/liquibase.properties if you want use liquibase plugin"
}
}
dockerPostgres {
changeLogFile "${projectDir}/changelog/changelog-master.yml"
url 'jdbc:postgresql://localhost:5555/test'
username 'test'
password 'test'
}
runList = 'main'
}
}
task localUpdate(dependsOn: "composeUp") {
doFirst {
liquibase.setProperty("runList", "dockerPostgres")
}
finalizedBy update
}
task localDropAll(dependsOn: "composeUp") {
doFirst {
liquibase.setProperty("runList", "dockerPostgres")
}
finalizedBy dropAll
}
I have two different names of my schema, a "prod" for production and a "test" for tests.
Is it possible to set a variable in my application.yml or build.gradle for changing the name when I'm testing my app and when I'm deploying it?
P.S. I also have two different profiles of my Spring app - "prod" and "test"
You certainly can add properties at runtime of liquibase (which can be passed in from gradle, directly from commandline, etc).
So you can for example call liquibase on the CLI:
liquibase -Durl= update

Gradle Artifactory deploy fails when using generated gradle.properties

I have the following build.gradle file:
plugins {
id 'java-gradle-plugin'
id 'com.gradle.plugin-publish' version '0.10.1'
id 'groovy'
id 'maven-publish'
id "com.jfrog.artifactory" version "4.9.1"
}
group = 'de.gafertp'
version = '2.0.0'
repositories {
mavenCentral()
}
dependencies {
compile 'net.sourceforge.plantuml:plantuml:1.2019.1'
testCompile 'org.junit.jupiter:junit-jupiter-api:5.4.0'
testCompile 'org.junit-pioneer:junit-pioneer:0.3.0'
testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.0'
}
gradlePlugin {
plugins {
plantUmlPlugin {
id = 'de.gafertp.plantuml'
displayName = 'Gradle PlantUML Plugin'
description = 'A very simple plugin to render PlantUML files. ' +
'Takes a set of diagram files together with desired output files / formats ' +
'and renders them with PlantUML (http://plantuml.com/).'
implementationClass = 'de.gafertp.PlantUmlPlugin'
}
}
}
pluginBundle {
website = 'https://github.com/codecholeric/gradle-plantuml-plugin'
vcsUrl = 'https://github.com/codecholeric/gradle-plantuml-plugin'
tags = ['plantuml']
}
publishing {
publications {
plantUmlPluginJar(MavenPublication) {
from components.java
}
}
}
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
repoKey = 'gradle-dev-local'
username = "${artifactory_user}"
password = "${artifactory_password}"
println "username=${artifactory_user}"
println "password=${artifactory_password}"
maven = true
}
defaults {
publications('plantUmlPluginJar')
}
}
resolve {
repository {
repoKey = 'gradle-dev'
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
}
}
test {
useJUnitPlatform()
}
And this gradle.properties file:
artifactory_user=${security.getCurrentUsername()}
artifactory_password=${security.getEncryptedPassword()!"blahblah"}
artifactory_contextUrl=http://localhost:8081/artifactory
The build fails with the following error:
Execution failed for task ':artifactoryDeploy'.
> java.io.IOException: Failed to deploy file. Status code: 401 Response message: Artifactory returned the following errors:
Unauthorized Status code: 401
If we take a look at the printed username and password, we see this:
username=${security.getCurrentUsername()}
password=${security.getEncryptedPassword()!"blahblah"}
Gradle takes the properties values as literal strings instead of evaluating them. So the issue seems to be that the security object cannot be found, because if I replace the properties in build.gradle file with their values directly, the following error occurs:
A problem occurred evaluating root project 'gradle-plantuml-plugin'.
> Could not get unknown property 'security' for object of type org.jfrog.gradle.plugin.artifactory.dsl.DoubleDelegateWrapper.
What am I doing wrong? The deploy works fine when using plaintext username and password, but I would like to use the auto-generated way of logging in (using an encrypted password).
It seems that gradle.properties should look like this:
username=your_username
password=blahblah
We suppose that blahblah is your encrypted password.

Gradle publish repository defaults or ignores

I have defined multiple repositories to publish to, but want the "gradle publish" job only to deploy to some of them.
E.g. in the following configuration I want that a "gradle publish" deploys the artifact to repo_a and repo_b but NOT repo_c.
A deploy to repo_c should only be done when the publishMavenJavaPublicationToRepo_cRepositoryjob is activated.
Is that somehow possible?
Thanks
publishing {
repositories {
maven {
url "https://repo_a/maven-releases/"
credentials {
username 'xxx'
password 'xxx'
}
name "repo_a"
}
maven {
url "https://repo_b/maven-releases/"
credentials {
username 'xxx'
password 'xxx'
}
name "repo_b"
}
maven {
url "https://repo_c/maven-releases/"
credentials {
username 'xxx'
password 'xxx'
}
name "repo_c"
}
}
publications {
mavenJava(MavenPublication) {
....
}
}
}
You can try the following code snippet to disable your publishMavenJavaPublicationToRepo_cRepository publishing task (reference):
afterEvaluate {
tasks.withType(PublishToMavenRepository) { task ->
if (task.repository.name == "repo_c") {
task.enabled = false
task.group = null
}
}
}

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