How to add parameters to flyway build.gradle file? - gradle

I have this in my build.gradle file:
flyway {
url = 'jdbc:oracle:thin:#localhost:1521:DB'
user = 'user'
password = 'pass'
driver = 'oracle.jdbc.OracleDriver'
placeholderReplacement = true
schemas = ['OWNER']
println "PRINT ARG:"
println testArg
locations = ["filesystem:soem-path/common"]
placeholders = [
'some.store.owner': flyway.schemas[0],
'some.user' : 'USER',
]
}
The build always fails after I added that part with the testArg. I wanted to get it in like this:
./gradlew flywayMigrate -PtestArg=test -Dflyway.configFiles=../flyway/flyway-dev.properties -i
The error message is:
Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'testArg' for object of type org.flywaydb.gradle.FlywayExtension.
at org.gradle.internal.metaobject.AbstractDynamicObject.getMissingProperty(AbstractDynamicObject.java:87)
at org.gradle.internal.metaobject.ConfigureDelegate.getProperty(ConfigureDelegate.java:130)
How can I get a property in there?

I believe your problem is the that when you are within the flyway configuration closure (i.e. the flyway { ... } section), your delegate object (i.e. when a property is not found in your local code, what class gradle will look in next) is the flyway extension. In other words, while you are in flyway { ... }, gradle will look for any property not found immediately in your code in the flyway plugin code.
What you are looking for is properties on the gradle project object. You could for example do something like this:
ext {
projectProperty = { name ->
project.hasProperty(name) ? project.properties[name] : null
}
}
flyway {
def testArg = projectProperty('testArg')
println "project property testArg: ${testArg}"
}
(untested, but should work in principle at least).
where the hasProperty call makes sure that the code doesn't break when the property is not set for the project.
For an explanation of delegation for groovy closures, the groovy language docs have a section specifically explaining this.

This worked:
def devEnv = System.properties.containsKey("devEnv")
flyway {
.....
if (devEnv) {
locations += "filesystem:some/path"
}
....
}
and call flyway like this:
./gradlew flywayClean -DdevEnv -Dflyway.configFiles=...

Related

Accessing Task properties in different subproject in Gradle

For the sake of asking this question, I have a trivial subproject defined as:
project("data-source-config") {
def projectName = "data-source-config"
jar {
baseName = "${projectName}_$scalaVersion"
version = "$version"
}
}
I would really like to be able to refer to the full output jar name in a separate subproject.
Something like:
project("another-subproject") {
def projectName = "another-subproject"
println(:data-source-config:jar.getProperty("archiveName")) // I don't know the correct syntax
}
I can see that the JAR task has the archiveName property in the docs here:
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveFileName
Any guidance would be much appreciated!
project("another-subproject") {
evaluationDependsOn ':data-source-config'
println project(':data-source-config').tasks['jar'].archiveName
}

ant.propertyFile updates comment everytime

In my build.gradle file I have the following variable to indicate which environment I'm building to:
buildscript {
ext {
springBootVersion = '1.5.15.RELEASE'
kotlinVersion = '1.2.70'
queryDslVersion = '4.1.4'
env = 'local'
}
// ...
}
And on my application.properties I have the following line for spring to use the correct application-{env}.properties:
spring.profiles.active=local
I have created a gradle task to update this value on my application.properties as follow:
task setEnv {
doFirst {
ant.propertyfile(file: "$projectDir/src/main/resources/application.properties") {
entry( key: "spring.profiles.active", value: "$env")
}
println "Building with env = $env"
}
}
The task works just fine except it adds one comment line with the timestamp of the update. So my application.properties now looks like:
#Fri, 14 Dec 2018 11:22:04 -0200
spring.profiles.active=local
This is a problem because everytime someone builds the project it changes this file, causing conflicts when commiting and pushing to git.
Any ideas on how I could get rid of that comment? Or even a better approach to set spring profile?
Thanks!
I don't think it's possible with ant, because it's implemented with the java.util.Properties class and it's said in the javadoc that:
...a comment line is always written, consisting of an ASCII #
character, the current date and time (as if produced by the toString
method of Date for the current time), and a line separator as
generated by the Writer.
So, to avoid it, you have to change a value in your properties file in some other way. For example, by configurion the ProcessResources Gradle task as follows:
processResources {
filesMatching('**/*.properties') {
filter {
it.replace('#ENV#', "$env")
}
}
}
And the value should be set to #ENV# inside the application.properties

How to use a parameter in gradle copy task in the destination folder?

Given the following task in gradle, the dev would start a new module by:
gradle initModule -PmoduleName=derp
task initModule(type: Copy) {
description "Initialize an empty module based on the template. Usage: gradle initModule -P moduleName=derp"
onlyIf { project.hasProperty("moduleName") }
from "$rootDir/modules/template"
into "$rootDir/modules/$moduleName"
}
I am unable to run gradle since moduleName is not defined during evaluation, although I was hoping that "onlyIf" would do so.
To solve this I assign it to a locally defined variable in a guard block:
def modName = ""
if (!project.hasProperty("moduleName")) {
logger.error("Invalid moduleName : It can't be")
} else {
modName = moduleName
}
and finally use the new variable to survive the configuration phase.
Is this the right way to do this? It just doesn't feel right.
Additionally if I was using a rule to make this a tad more elegant:
tasks.addRule("Pattern: initModule_<mod name>") { String taskName ->
if (taskName.startsWith("initModule_")) {
def params = taskName.split('_');
task(taskName) {
doLast {
project.ext.moduleName = params.tail().head()
tasks.initModule.execute()
}
}
}
}
The moduleName is not passed around (even if I change it to finalizedBy).
Any help is appreciated.
As you already figured out the property is not available during the configuration phase.
But can postpone the look-up to the execution phase by using
into "$rootDir/modules/" + project.property("moduleName")
instead of
into "$rootDir/modules/$moduleName"

Gradle - publish artifacts

I want to publish artifacts to ivy repository but it doesn't work. I read this article and after read created this sample build:
task ivyPublishTest << {
def buildDir = new File("build")
buildDir.mkdirs()
def fileToPublish = new File("build/file.abc")
fileToPublish.write("asdasdasd")
}
artifacts {
archives(ivyPublishTest.fileToPublish) {
name 'gradle-test-artifact'
builtBy ivyPublishTest
}
}
uploadArchives {
repositories {
ivy {
url "http://my.ivy.repo/ivyrep/shared"
}
}
}
Of course the problem is that it doesn't work. I get this error Could not find property 'fileToPublish' on task ':ivyPublishTest'
In Groovy, def creates a local variable, which is lexically scoped. Therefore, fileToPublish is not visible outside the task action. Additionally, configuration has to be done in the configuration phase (i.e. the declaration and assignment of fileToPublish in your task action would come too late). Here is a correct solution:
task ivyPublishTest {
// configuration (always evaluated)
def buildDir = new File("build")
ext.fileToPublish = new File("build/file.abc")
doLast {
// execution (only evaluated if and when the task executes)
buildDir.mkdirs()
fileToPublish.write("asdasdasd")
}
}
artifacts {
// configuration (always evaluated)
archives(ivyPublishTest.fileToPublish) {
name 'gradle-test-artifact'
builtBy ivyPublishTest
}
}
ext.fileToPublish = ... declares an extra property, a new property attached to an existing object that's visible everywhere the object (task in this case) is visible. You can read more about extra properties here in the Gradle User Guide.

How can I override a property defined in build.gradle?

How can I set a property in the build.gradle file and allow each developer to override it locally? I tried:
gradle.properties:
MY_NAME = "Jonathon"
MY_COLOR = "blue"
build.gradle:
ext.MY_NAME = "John Doe"
task showit <<{
println "MY_NAME[" + MY_NAME + "]";
println "MY_COLOR[" + MY_COLOR + "]";
}
gradle showit gives:
:showit
MY_NAME[John Doe]
MY_COLOR["blue"]
I thought that a property defined in a gradle.properties file at the project root would override a property with the same name defined in build.gradle, but this does not appear to be the case. It only fills in for a missing property.
Check whether the project has a property, and if not, set it to the default value:
ext {
if (!project.hasProperty('MY_NAME')) {
MY_NAME = 'John Doe'
}
}
See: https://docs.gradle.org/current/userguide/build_environment.html#sub:checking_for_project_properties
If you need to do this for multiple properties, you can define a function:
def setPropertyDefaultValueIfNotCustomized(propertyName, defaultValue) {
if (!project.hasProperty(propertyName)) {
ext[propertyName] = defaultValue
}
}
ext {
setPropertyDefaultValueIfNotCustomized('MY_NAME', 'John Doe')
}
Similar to Johan Stuyts' answer, but as a one-liner:
ext.MY_NAME = project.properties['MY_NAME'] ?: 'John Doe'
Running gradle -PMY_NAME="Jeff F." showit gives MY_NAME[Jeff F.].
Running gradle showit gives MY_NAME[John Doe].
i think you can define a local variable and then override it like this
def dest = "name"
task copy(type: Copy) {
from "source"
into name
}
see this doc
I just ran into this myself. My use case is that I fork project repos and my coworkers don't. I needed to set the repository remote for axion-release to upstream instead of origin.
I didn't want to have to pass args (or create aliases/shell functions) so I ended up creating a gradle.properties in my GRADLE_USER_HOME (~/.gradle) and adding a property (name doesn't matter) for this there as well as in the project's gradle.properties. In gradle.build I always use that property since it always exists.
Example
~/.gradle/gradle.properties
scmVersionRepositoryRemote=upstream
[project-root]/gradle.properties
scmVersionRepositoryRemote=origin
[project-root]/build.gradle
scmVersion {
repository {
remote = scmVersionRepositoryRemote
}
}

Resources