Optional Gradle properties - gradle

I have a Gradle build file where one of the the tasks is to login into docker. In this task I want that the user/CI provides the parameter docker_username, docker_password and docker_email.
task loginDockerHub(group: "Docker", type:Exec) {
executable "docker"
args "login","-u", docker_username, "-p", docker_password, "-e", docker_email
}
Executing gradle loginDockerHub -Pdocker_username=vad1mo ... all is working as expected.
But when I execute for example gradle build I get the error:
Could not find property 'docker_username' on task ':loginDockerHub'.
I would expect this error on executing gradle loginDockerHub without providing the -P parameter, but not on other tasks that don't access docker_username/password parameters.
How can I have optional parameters for my loginDockerHub task in Gradle that don't make the parameter mandatory for any other task.

You can check if the property exists and if not return a default.
args "login", "-u", project.hasProperty("docker_username") ? docker_username : ""
Update: Starting with Gradle 2.13 you can simplify this somewhat.
args "login", "-u", project.findProperty("docker_username") ?: ""

I was not able to find a solution to the problem. This description had a hint about about declaring actions within a task. Putting the shell exec into the action task has the behavior I was expecting, because actions are evaluated when the task executes.
task loginDockerHub(group: "Docker", type:Exec) {
doFirst{
executable "docker"
args "login","-u", docker_username, "-p", docker_password, "-e", docker_email
}
}
Executing the loginDockerHub without providing the docker_* parameters will yelled an error. Executing any other task will work as expected.

I had to do this and didn't want my build to fail with an error. I solved it by doing this:
ext.shouldLoginDockerHub = project.hasProperty("docker_username");
task loginDockerHub(group: "Docker") {
doLast{
if(shouldLoginDockerHub) {
exec {
executable "docker"
args "login","-u", docker_username, "-p", docker_password, "-e", docker_email
}
} else {
println "Not logging in to docker hub because docker_username was not provided.";
}
}
}
You could expand the first line to look for docker_password, docker_email, etc.

Related

Gradle task lines always getting executed

I have the following Gradle task:
task deploy(type: Exec) {
doFirst {
println 'Performing deployment'
}
final Map properties = project.getProperties()
if (!properties['tag']) {
throw new StopExecutionException("Need to pass a tag parameter")
}
commandLine "command", tag
}
If I run another task I get an error because properties['tag'] is undefined, I guess because Gradle is executing everything in the task except commandLine. Is there a better way to do this or a way to stop Gradle from executing parts of the task even when I'm running another task?
Using Gradle 6.6.1
I use this pattern:
// Groovy DSL
tasks.register("exec1", Exec) {
def tag = project.findProperty("tag") ?: ""
commandLine "echo", tag
doFirst {
if (!tag) {
throw new GradleException("Need to pass a tag parameter")
}
}
}
It adds the tag property if it exists.
If it does not exist, it adds an empty string but checks for this before it actually runs.
It would be great if the Exec task accepted providers as arguments so you could just give it providers.gradleProperty("tag"), but unfortunately it doesn't.

Gradle, task type: Exec - commandLine not work in onLast

I want execute some command from command line in gradle task(e.g. print all files in dir):
task dir(type: Exec) {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
doLast {
println ("result = " + standardOutput)
}
}
It's work. OK. But when I put it on onLast section it's not work:
task dir(type: Exec) {
doLast {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
println ("result = " + standardOutput)
}
}
I get error:
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':app:dir'.
execCommand == null!
The reason is in the fact, that task of Exec should be configured during configuration phase of the build, otherwise your task will be not configured and fail.
In you first example everything works due to configuration happens at the configuratyion phase. Your second example tries to configure the task within doLast closure - right after the task is executed yet.
If you really need to execute something in doLast, you can use something like this, without creating special task:
task someTaskName {
doLast {
exec {
commandLine adbCommand
}
}
}
Here is exec-specification used to execute some command and it's configured and executed at the same time.

Gradle - How to set dependency tasks for Exec-type tasks?

Say, you have following task:
task commandA() {
doLast {
project.ext.ping = 'PING'
}
}
This will work:
task commandB() {
dependsOn commandA
doLast {
println ping
}
}
This will fail:
task commandC(type: Exec) {
dependsOn commandA
commandLine "echo", ping
}
With Could not find property 'ping' on task 'commandC'. error message.
So, how one can declare dependency for an exec-type task and set some variable in that dependency?
Just don't initialize the variable within the doLast block, since it's getting initialized at the execution phase, but commandLine "echo", ping is trying to get it at the configuration phase of the build.
So, you need something like that:
task commandA() {
project.ext.ping = 'PING'
}
Or even without task, as follows:
project.ext.ping = 'PING'
Because configuration of any task is always executed, even if the task's action won't be executed.
Another solution is to use exec-action, not exec-task, something like this:
task commandA() {
doLast {
project.ext.ping = 'PING'
}
}
task commandC {
dependsOn commandA
doLast {
exec {
commandLine ping, "192.168.100.1"
}
}
}
In this case, exec-closure will be done during execution phase wuth the ping variable already available.
You can read about build lifecycle in the official Gradle user guide

skipping tasks in gradle during runtime

I've got two simple tasks
task initdb { println 'database' }
task profile(dependsOn: initdb) << { println 'profile' }
During runtime the result in console looks like this
When my tasks looks like this
task initdb { println 'database' }
task profile() << { println 'profile' }
the result in console is
How to skip initdb task when it's not used in the task profile in runtime? (without using -x)
The reason for this behavior is that initDb isn't declared correctly. It's missing a <<, and hence the println statement gets run at configuration time rather than execution time. This also means that the statement always gets run. This doesn't mean that the task gets executed (in the second example it doesn't).
To avoid such mistakes, I recommend to use the more explicit and regular doLast syntax in favor of <<:
task profile {
// code in here is about *configuring* the task;
// it *always* gets run (unless `--configuration-on-demand` is used)
dependsOn initdb
doLast { // adds a so-called "task action"
// code in here is about *executing* the task;
// it only gets run if and when Gradle decides to execute the task
println "profile"
}
}

Run shell command in gradle but NOT inside a task

What I currently have is:
task myTask (type : Exec) {
executable "something.sh"
... (a lot of other things)
args "-t"
args ext.target
}
task doIt {
myTask.ext.target = "/tmp/foo"
myTask.execute();
myTask.ext.target = "/tmp/gee"
myTask.execute();
}
With this I thought I could run "myTask" with different parameters when I start "doIt". But only the first time the script is executed because gradle takes care that a task only runs once.
How can I rewrite the "myTask" so that I can call it more than once? It is not necessary to have it as a separate task.
You can do something like the following:
def doMyThing(String target) {
exec {
executable "something.sh"
args "-t", target
}
}
task doIt {
doLast {
doMyThing("/tmp/foo")
doMyThing("/tmp/gee")
}
}
The exec here is not a task, it's the Project.exec() method.

Resources