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

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"

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
}

Skip variable checking in gradle configuration phase

I have some gradle script where i read some properties file (differen file in different execution configurations) and assign Properties obect to "ext" property in each task.
task provisionMongoDBCopyDockerfile(type: Copy, dependsOn: 'readTestConfiguration') {
from "${projectDir}/deployment/scripts/Dockerfile.mongodb"
into "/tmp/stand/mondodb"
expand(ext.stand)
filteringCharset = 'UTF-8'
}
task readTestConfiguration () {
def props = loadStandProperties('test')
println props
tasks.each {
it.ext.stand = props
println it.ext
}
}
but when i run gradle script i get this error: "Cannot get property 'stand' on extra properties extension as it does not exist" in line with "expand(ext.stand)". How can i solve this problem. I don't want to put all configuration parameters in "gradle.properties" and change it from configuration to configuration.
Consider the following (using Gradle 2.14.1). This effectively sets up a dependency in Configuration phase. Also it uses project.ext versus tasks.ext.
def readTestConfiguration = {
def props = loadStandProperties('test')
println props
project.ext.stand = props
}
def loadStandProperties (def env) {
// use mock data
return ["foo": "bar"]
}
tasks.whenTaskAdded { Task task ->
if (task.name == "provisionMongoDBCopyDockerfile") {
readTestConfiguration()
}
}
task provisionMongoDBCopyDockerfile(type: Copy) {
from "${projectDir}/in"
into "${projectDir}/out"
expand(project.ext.stand)
}

Gradle def vs ext

What is the difference between using ext.varname and def varname. E.g. the following code seems to work the same:
task copyLicenses {
def outDir = project.buildDir.absolutePath + '/reports/license/'
doLast {
copy {
from 'licenses'
into outDir
include '*'
}
seems to work exactly the same as
task copyLicenses {
ext.outDir = project.buildDir.absolutePath + '/reports/license/'
doLast {
copy {
from 'licenses'
into outDir
include '*'
}
Keyword def comes from Groovy and means that variable has local scope.
Using ext.outDir means that you add property outDir to ExtraPropertiesExtension, think of it like project has a map of properties with name ext, and you put your property in this map for later access.

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