Override property in build.gradle from the command line - gradle

In build.gradle we can define variables like:
def libVersion='someVersion'
We can override properties in command line with -PlibVersion=otherVersion
Unfortunately it seems this command line option does not affect local variables defined in build.gradle. Is there a way to override these from command line? Please note that for some reasons i do not want to create settings.gradle nor gradle.properties files.

Here's an example:
ext.greeting = project.hasProperty('greeting') ? project.getProperty('greeting') : 'hello'
task greet << {
println greeting
}
If you run gradle greet, it will print hello.
If you run gradle -Pgreeting=welcome greet, it will print welcome.

I was trying to override a property from command line which I had defined in build.gradle but it never worked. But when I pass the property without defining in build.gradle it's working. For example:
If I use
def myProp='foo'
println "${myProp}"
and run from the cmd
gradlew -PmyProp=Hello build
Never worked. I'm always getting foo only.
But if I remove
def myProp='foo'
It's working and taking all the inputs whatever I passed from cmd.
There is another way, just define the property in gradle.properties then you can override easily from command line.
I recently experienced this with Gradle 7.3 so thought to share.

Related

How do I remove/overwrite the outputs from a gradle task

I have dynamic defined a task in build.gradle, that inherits from another task.
In the following I'm using kotlin-DSL, but I'm happy with solutions for groovy dsl as well.
task.register<GenerateTask>("generateCode") {
// stuff
outputDir.set("$rootDir")
}
As you can see I had to define the output as rootDir.
However I'm setting options to only create part of the output.
All the generated code is in a specificPackage meaning it will all end up in:
$rootDir/src/main/my/generated/package/name
$rootDir/src/test/my/generated/package/name
However due to outputDir being set it assumes the whole rootdir is an output and warns me accordingly.
Now I would like to tell gradle, that this task only produces those two packages.
I tried overwriting outputs but it is readonly.
I tried overwriting outputs.files but it is readonly.
I tried using outputs.files.setFrom() as described here, but this seems no longer to be valid.
Is there a way to set outputDir, but not add the value it to outputs or a way to clear the outputs list?

Why are optional inputs on my Gradle custom task not working?

I have a build.gradle with the following contents:
task myTask {
inputs.file("input.txt").optional()
doLast { println "input.txt exists = " + file("input.txt").exists() }
}
If input.txt doesn't exist, it fails with:
File '/Users/skissane/testgradle/input.txt' specified for property '$1' does not exist.
What I am trying to do, is run a custom script–which is written in Groovy, and runs inside the Gradle build under doLast, not as an external process–which takes the input.txt file as input, and the script's behaviour and output will change based on what is in that input file. But it is an optional input file – the script will still generate output (albeit different output) even if the input file doesn't exist.
Things I have tried so far:
Remove .optional(), change it to .optional(true): no difference in results
Instead of .optional(), wrap it in if (file("input.txt").exists()) {: this works, but seems ugly. Why doesn't .optional() work?
Have I misunderstood what .optional() is meant to do? Because another answer suggests it is the right way to solve my problem, but it isn't working.
(I am using Gradle 6.8.3. I tried upgrading to the latest Gradle 7.2, the same problem occurs, although 7.2 has more detailed error messages.)
optional() can't be used to mark the file itself as optional. optional() just means that the input property is optional, and the task is still valid if no files at all are specified; but if a file is specified, it must exist.
As such, optional() isn't really useful in this kind of custom task declared directly in build.gradle. It is really intended for defining new task types in plugins, when one defines a new task input property other than inputs, and wants to make it optional to declare files for that property. It is the property itself which is made optional, not the files in it. On a custom task, declaring inputs as optional is pointless because it is already optional to begin with.
Right now (as of version 7.2), Gradle doesn't have any way to mark a file as an optional input, other than through if (file("input.txt").exists()) {. Hopefully they might add that feature in some future Gradle version.
(Thanks to James Justinic who answered my post about this on Gradle forums.)

Passing property to custom gradle task from command prompt

I wrote a custom gradle task class (say PrintNameTask) that accepts some input parameter (say name).
Then if I define a printName task of type PrintNameTask like below:
task printName(type: PrintNameTask) {
name = project.name
}
and invoke it from command prompt like below I can see the passed name printed out
$gradle printName -Pname=myName
myName
However if I invoke any other task like clean or build the build fails because there is no property called name passed. This is fair enough as my printName is a configure closure and is evaluated all the times.
To address this I tried to change the configure closure into a task action closure like below:
task printName(type: PrintNameTask) << {
// What should I put on here?
name = ???
// or
name ???
}
But it was no way to make it work. I tried project.name, getProperty("name") and a few more other combinations but nothing worked. All I get back is:
* What went wrong:
A problem was found with the configuration of task ':printName'.
No value has been specified for property 'name'.
This kind of requirement looks to me quite basic and it is a bit frustrating that tons of books and documentation are published but they only shows trivial examples. Maybe is just me but at the point of asking this question my initial gradle enthusiasm is more than half gone. Anyway thank you in advance for your inputs.
Configure the task in the following way:
task printName(type: PrintNameTask) {
name = project.hasProperty('name') ? project.name : '' // or null
}
Since this closure is evaluated at configuration phase it's executed every time the script is processed. You just need to check if the property is present.

How can I get $ not escaped in application default jvm args for gradle?

Using the application task I am specifying:
applicationDefaultJvmArgs = ['$DEBUG_OPTS',
'-Djava.library.path=${ZMQ_LIB_PATH}']
In the generated start scripts I see:
DEFAULT_JVM_OPTS='"\$DEBUG_OPTS" "-Djava.library.path=\${ZMQ_LIB_PATH}"'
I don't want the \$ in there. I tried using '$$DEBUG_OPTS' and also '\$DEBUG_OPTS' but got the same result. What is the right way to escape the $ so it ends up in the script without a backslash in front of it?
I had a similar issue, trying to add a commandline parameter $1 in there. With some googling came up with this solution, fixing the script after the fact.
applicationDefaultJvmArgs=['-Dmy.property=DOLLARONE']
...
startScripts{
doLast{
def bashFile = new File(getOutputDir(),applicationName)
String bashContent = bashFile.text
bashFile.text = bashContent.replaceFirst('DOLLARONE', Matcher.quoteReplacement('$1'))
}
}
The StartScriptGenerator code implies that '$' will be unconditionally replaced by the '\$'.
I assume that your intention is to use '$' character for shell parameters extension but I would like to point out that such usage (if permitted by the gradle task that generates the scripts) is not interoperable between bash and bat scripts - in the bash it will be used for shell parameters extension but in the bat it will have no meaning.
For Kotlin build script the solution could look like:
tasks.named<CreateStartScripts>("startScripts") {
doLast {
unixScript.writeText(unixScript.readText().replace("{{APP_HOME}}", "\${APP_HOME}"))
windowsScript.writeText(windowsScript.readText().replace("{{APP_HOME}}", "%APP_HOME%"))
}
}

How do I set test.testLogging.showStandardStreams to true from the command line?

It is convenient to debug some of external libraries and even internal code while writing unit tests by reviewing the logging on stdout.
While I can add test.testLogging.showStandardStreams = true to the build.graddle file, I'd rather do something less permanent, such as setting this flag from the command line execution of gradle.
I've tried several approaches, none seem to work:
gradle test -Dtest.testLogging.showStandardStreams=true
gradle test -Ptest.testLogging.showStandardStreams=true
And other variations of those options by changing the property string. Nothing seems to do the trick.
How do I set test.testLogging.showStandardStreams=true from the command line?
There is no built-in way to set build model properties from the command line. You'll have to make the build script query a system or project property that gets passed in via -D or -P, respectively.
Just use environment variables:
test {
testLogging.showStandardStreams = (System.getenv('PRINTF_DEBUG') != null)
}
Now run your test case like this:
PRINTF_DEBUG=1 ./gradlew test --tests=com.yourspace.yourtest
This will run enable console output and just run one single test case. You often not want to enable console output for the entire test suite because of the noise generated.
You can override it like this
gradle -Doverride.test.testLogging.info.showStandardStreams=true test
or you can add this to your gradle.properties either in the project or in ~/.gradle/gradle.properties
systemProp.override.test.testLogging.info.showStandardStreams=true

Resources