Liquibase module and a variable in Spring Boot Project - spring-boot

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

Related

How do I load a .yml property in a Gradle build script?

I have .yml file with the following properties:
spring:
application:
name: auth module
profiles:
active: prod
My gradle.build script has these settings for the jar task:
jar {
baseName = 'auth-module-dev' // `dev` should come from `spring.profiles.active`
version = '0.1.2'
}
I want to build jar files with the naming convention auth-module-%profile_name%.jar where %profile_name% is the value of spring.profiles.active. How can I do this?
assume your yaml file has name cfg.yaml
don't forget to add --- at the beginning of yaml
---
spring:
application:
name: auth module
profiles:
active: prod
build.gradle:
defaultTasks "testMe"
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'org.yaml', name: 'snakeyaml', version: '1.19'
}
}
def cfg = new org.yaml.snakeyaml.Yaml().load( new File("cfg.yaml").newInputStream() )
task testMe( ){
doLast {
println "make "
println "profile = ${cfg.spring.profiles.active}"
assert cfg.spring.profiles.active == "prod"
}
}

Use properties in gradle liquibase

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

Gradle Liquibase plugin not using specified contexts

We have a Gradle project which uses Liquibase, and our build file has:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.liquibase:liquibase-gradle-plugin:1.1.1'
classpath 'org.liquibase:liquibase-core'
}
}
apply plugin: 'liquibase'
Yet when we try to update our project via:
gradle update -Dliquibase.contexts=foobar
(tried with --contexts too)
it seems to ignore the specified contexts and runs all the changesets instead.
Example:
changeSet(author: 'me', id: 'someId1', context: 'somethingElse') { // This runs, but shouldn't
// ...
changeSet(author: 'me', id: 'someId2', context: 'foobar') { // Should only run this
The project was forked at one point, so maybe we're misinterpreting the documentation (original, new) but it seems like this should work.
Do we need a different plugin/version? Are we calling it wrong?
Derp, looks like you need to grab the contexts manually in your build file:
main {
if (project.hasProperty('contexts')) {
contexts contexts
}
url 'someurl'
username 'username'
password 'pass'
}
Then pass it in via:
gradle update -Pcontexts=schema
You should define your contexts inside task
task('liquibase_dev') << {
liquibase {
activities {
main {
changeLogFile changeLog
url 'jdbc:postgresql://localhost:5432/test'
username 'postgres'
password 'admin'
contexts 'DEV'
}
}
}
}
Liquibase changelog:
<changeSet author="xxx" context="DEV" id="1591257804177-1" ...>
<changeSet author="xxx" context="PROD" id="1591257804177-2" ...>
Then you can run like:
./gradlew :liquibase_dev update
Only the first changeset will be executed
Newer plugin (2.0.3), same problem and slightly different solution, 'cause I'm keeping a default context.
liquibase.gradle (snippet):
if (!project.hasProperty("contexts")) {
project.ext.contexts = "dev"
}
liquibase {
activities {
main {
driver "${datasource_driver}"
url "${datasource_url}"
username "${datasource_username}"
password "${datasource_password}"
changeLogFile "src/main/resources/db/changelog/master.xml"
defaultSchemaName ""
logLevel "info"
contexts contexts
}
}
}
tasks.liquibaseUpdate.dependsOn(tasks.classes)
gradle.properties (snippet):
liquibaseTaskPrefix=liquibase
So, now it's safe to call:
./gradlew liquibaseUpdate # to apply contexts=dev
And:
./gradlew liquibaseUpdate -Pcontexts=test # to apply contexts=test

Upload only war/jar files in gradle(restrict zip/tar generation and upload)

My build script is like as follows. I use gradle build command to build and gradle upload command to upload the artifact. My problem is a tar,zip file is also generated with this command and get uploaded. I dont want it. Only things I would like to get uploaded is 'jar' and 'war' files.
I have also a related question posted by me yesterday here.
More details(I have excluded some unwanted code)
build file in root
allprojects {
apply plugin: 'maven'
group = 'groupid'
version = '1.0-SNAPSHOT'
}
subprojects {
apply plugin: 'java'
sourceCompatibility = 1.7
targetCompatibility = 1.7
repositories {
maven {
credentials {
username "$nexusUser"
password "$nexusPass"
}
url "$nexusUrl"
}
}
uploadArchives {
repositories {
mavenDeployer {
repository(url: "$nexusSnapshotUrl") {
authentication(userName: "$nexusUser", password: "$nexusPass")
}
}
}
}
}
ext.comlib = [ // Groovy map literal
junit3: "junit:junit:3.8",
junit4: "junit:junit:4.9",
spring_core: "org.springframework:spring-core:3.1",
hibernate_validator : "org.hibernate:hibernate-validator:5.1.3.Final",
spring_core : "org.springframework.security:spring-security-core:4.0.2.RELEASE",
spring_security_web: "org.springframework.security:spring-security-web:4.0.2.RELEASE",
spring_security_config: "org.springframework.security:spring-security-config:4.0.2.RELEASE",
spring_boot_starter_test: "org.springframework.boot:spring-boot-starter-test:1.2.5.RELEASE",
spring_boot_starter_actuator: "org.springframework.boot:spring-boot-starter-actuator:1.2.5.RELEASE",
spring_boot_plugin_gradle: "org.springframework.boot:spring-boot-gradle-plugin:1.2.6.RELEASE",
asciidoctor_gradle_plugin: "org.asciidoctor:asciidoctor-gradle-plugin:1.5.1",
asciidoctor_pdf_plugin: "org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.9"/*,
sl4j_api: "org.slf4j:slf4j-api:1.7.12",
sl4j_log4j: "org.slf4j:slf4j-log4j12:1.7.12",
logback_classic: "ch.qos.logback:logback-classic:1.1.3",
logback_core: "ch.qos.logback:logback-core:1.1.3"*/
]
build file in sub module
apply plugin: 'spring-boot'
group = 'com.group.id'
apply from: "../build.gradle"
apply plugin: 'org.asciidoctor.gradle.asciidoctor'
apply plugin: 'war'
description = 'module name'
dependencies {
compile "someothermodule:commonapi:1.0.0-SNAPSHOT"
compile "io.springfox:springfox-swagger2:2.0.1"
compile project(':dependingproject1:dependingproject2')
compile comlib.spring_boot_starter_actuator
compile comlib.spring_core
compile comlib.spring_security_web
compile comlib.spring_security_config
testCompile(comlib.spring_boot_starter_test) {
exclude(module: 'commons-logging')
}
testCompile comlib.junit4
providedCompile comlib_app.spring_boot_plugin_tomcat
testCompile "io.springfox:springfox-staticdocs:2.0.3"
testCompile "org.springframework:spring-test:4.1.7.RELEASE"
}
ext {
swaggerOutputDir = file("src/docs/asciidoc/generated")
asciiDocOutputDir = file("${buildDir}/asciidoc")
}
test {
systemProperty 'org.springframework.restdocs.outputDir', asciiDocOutputDir
systemProperty 'io.springfox.staticdocs.outputDir', swaggerOutputDir
}
//spring boot plugin
buildscript {
repositories {
maven {
credentials {
username "$nexusUser"
password "$nexusPass"
}
url "$nexusCentral"
}
maven {
credentials {
username "$nexusUser"
password "$nexusPass"
}
url "$nexusThirdParty"
}
}
dependencies {
classpath(comlib.spring_boot_plugin_gradle)
}
}
Included the following code snippet in my gradle file
[distZip, distTar].each { task -> configurations.archives.artifacts.removeAll
{ it.class.simpleName == "ArchivePublishArtifact" && it.archiveTask == task }
task.enabled = false
}
For more details refer this link. Its issue with spring boot plugin.
arjuncc's solution doesn't seem to work on Gradle 4.10.2, so here's one that works and uses public APIs, hopefully it will continue to work.
configurations.archives.artifacts.removeAll {
// exclude from the archives configuration all artifacts that were generated by distZip & distTar
def depTasks = it.getBuildDependencies().getDependencies()
depTasks.contains(distZip) || depTasks.contains(distTar)
}
More or less the same as ajuncc's solution, but perhaps a bit more simple. Remove all .tar artifacts from the archives configuration:
configurations.archives.artifacts.removeAll {PublishArtifact publishArtifact -> publishArtifact.type == 'tar'}

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