Until now, we have defined tasks independent of each other. But in our projects we need dependencies between tasks. For example, a task to package compiled class files is dependent on the task to compile the class files. The build system should then first run the compile task, and when the task is finished, the package task must be executed.
In Gradle, we can add task dependencies with the
dependsOn
method for a task. First, let's look at a simple task dependency:
task first << { task -> println "Run ${task.name}" } task second << { task -> println "Run ${task.name}" } // Define dependency of task second on task first second.dependsOn 'first'
Note that we define the dependency of task second
on task first
, in the last line. When we run the script, we see that the first
task is executed before the second
task:
$ gradle second :first Run first :second Run second BUILD SUCCESSFUL Total time: 2.145 secs
Another way to define the dependency between tasks is to set the
dependsOn
property instead of using the dependsOn
method. There is a subtle difference; Gradle just offers several ways to achieve the same result. In the following piece of code, we use the property to define the dependency of task second
. And for task third
, we immediately define the property when we define the task:
task first << { task -> println "Run ${task.name}" } task second << { task -> println "Run ${task.name}" } // Use property syntax to define dependency. // dependsOn expects a collection object. second.dependsOn = ['first'] // Define dependsOn when we create the task: task third(dependsOn: 'second') << { task -> println "Run ${task.name}" }
When we run task third
on the command line, we see that all three tasks are executed:
$ gradle -q third Run first Run second Run third
The dependency between tasks is "lazy". We can define a dependency on a task that is defined later in the build script. Gradle will set up all task dependencies during the configuration phase and not during the execution phase. The following script shows that the order of the tasks doesn't matter in the build script:
task third(dependsOn: 'second') << { task -> println "Run ${task.name}" } task second(dependsOn: 'first') << { task -> println "Run ${task.name}" } task first << { task -> println "Run ${task.name}" }
We now have our build script with three tasks. But each task does the same thing—it prints out a string with the name of the task. It is good to keep in mind that our build script is just code, and code can be organized and refactored to create cleaner code. This applies to Gradle build scripts as well. It is important to take a good look at your build scripts and see if things can be organized better and if code can be reused instead of repeated. Even our simple build script can be rewritten like this:
def printTaskName = { task -> println "Run ${task.name}" } task third(dependsOn: 'second') << printTaskName task second(dependsOn: 'first') << printTaskName task first << printTaskName
This might seem trivial, but it is important to understand that we can apply the same coding techniques we use in our application code to our build code.
In our build scripts, we defined the task dependencies using the task name. But, there are more ways in which to define a task dependency. We can use the task
object instead of the task name to define a task dependency:
def printTaskName = { task -> println "Run ${task.name}" } task first << printTaskName task second(dependsOn: first) << printTaskName
We can also use a closure to define the task dependencies. The closure must return a single task name or task
object, or a collection of task names or task
objects. Using this technique, we can really fine-tune the dependencies for our task. For example, in the following build script, we define a dependency for task second
on all tasks in the project with task names that have the letter "f" in the task name:
def printTaskName = { task -> println "Run ${task.name}" } task second << printTaskName second.dependsOn { project.tasks.findAll { task -> task.name.contains 'f' } } task first << printTaskName task beforeSecond << printTaskName
When we run the build project we get the following output:
:beforeSecond Run beforeSecond :first Run first :second Run second BUILD SUCCESSFUL Total time: 2.515 secs
3.141.4.179