Defining dependencies between tasks

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.

Defining dependencies via tasks

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

Defining dependencies via closures

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
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.4.179