# Chapter 13. More about Tasks

In the introductory tutorial (Chapter 4, Build Script Basics) you have learned how to create simple tasks. You have also learned how to add additional behavior to these tasks later on. And you have learned how to create dependencies between tasks. This was all about simple tasks. But Gradle takes the concept of tasks further. Gradle supports enhanced tasks, that is, tasks which have their own properties and methods. This is really different to what you are used to with Ant targets. Such enhanced tasks are either provided by you or are provided by Gradle.

## 13.1. Defining tasks

We have already seen how to define tasks using a keyword style in Chapter 4, Build Script Basics. There are a few variations on this style, which you may need to use in certain situations. For example, the keyword style does not work in expressions.

Example 13.1. Defining tasks

`build.gradle`

    task(hello) << {
        println "hello"
    }

    task(copy, type: Copy) {
        from(file('srcDir'))
        into(buildDir)
    }

You can also use strings for the task names:

Example 13.2. Defining tasks - using strings

`build.gradle`

    task('hello') <<
    {
        println "hello"
    }

    task('copy', type: Copy) {
        from(file('srcDir'))
        into(buildDir)
    }

There is an alternative syntax for defining tasks, which you may prefer to use:

Example 13.3. Defining tasks with alternative syntax

`build.gradle`

    tasks.add(name: 'hello') << {
        println "hello"
    }

    tasks.add(name: 'copy', type: Copy) {
        from(file('srcDir'))
        into(buildDir)
    }

Here we add tasks to the `tasks` collection. Have a look at `TaskContainer` for more variations of the `add()` method.

## 13.2. Locating tasks

You often need to locate the tasks that you have defined in the build file, for example, to configure them or use them for dependencies. There are a number of ways you can do this. Firstly, each task is available as a property of the project, using the task name as the property name:

Example 13.4. Accessing tasks as properties

`build.gradle`

    task hello

    println hello.name
    println project.hello.name

Tasks are also available through the `tasks` collection.

Example 13.5. Accessing tasks via tasks collection

`build.gradle`

    task hello

    println tasks.hello.name
    println tasks['hello'].name

You can access tasks from any project using the task's path using the `tasks.getByPath()` method. You can call the `getByPath()` method with a task name, or a relative path, or an absolute path.

Example 13.6. Accessing tasks by path

`build.gradle`

    project(':projectA') {
        task hello
    }

    task hello

    println tasks.getByPath('hello').path
    println tasks.getByPath(':hello').path
    println tasks.getByPath('projectA:hello').path
    println tasks.getByPath(':projectA:hello').path

Output of `gradle -q hello`

    > gradle -q hello
    :hello
    :hello
    :projectA:hello
    :projectA:hello

Have a look at `TaskContainer` for more options for locating tasks.

## 13.3. Configuring tasks

As an example, let's look at the `Copy` task provided by Gradle. To create a `Copy` task for your build, you can declare in your build script: [11]

Example 13.7. Creating a copy task

`build.gradle`

    task myCopy(type: Copy)

This creates a copy task with no default behavior. The task can be configured using its API (see `Copy` ). The following examples show several different ways to achieve the same configuration.

Example 13.8. Configuring a task - various ways

`build.gradle`

    Copy myCopy = task(myCopy, type: Copy)
    myCopy.from 'resources'
    myCopy.into 'target'
    myCopy.include('**/*.txt', '**/*.xml', '**/*.properties')

This is similar to the way we would normally configure objects in Java. You have to repeat the context (`myCopy`) in the configuration statement every time. This is a redundancy and not very nice to read.

There is a more convenient way of doing this.

Example 13.9. Configuring a task - fluent interface

`build.gradle`

    task(myCopy, type: Copy)
        .from('resources')
        .into('target')
        .include('**/*.txt', '**/*.xml', '**/*.properties')

You might know this approach from the Hibernates Criteria Query API or JMock. Of course the API of a task has to support this. The `from`, `to` and `include` methods all return an object that may be used to chain to additional configuration methods. Gradle's build-in tasks usually support this configuration style.

But there is yet another way of configuring a task. It also preserves the context and it is arguably the most readable. It is usually our favorite.

Example 13.10. Configuring a task - with closure

`build.gradle`

    task myCopy(type: Copy)

    myCopy {
       from 'resources'
       into 'target'
       include('**/*.txt', '**/*.xml', '**/*.properties')
    }

This works for any task. Line 3 of the example is just a shortcut for the `tasks.getByName()` method. It is important to note that if you pass a closure to the `getByName()` method, this closure is applied to configure the task.

There is a slightly different ways of doing this.

Example 13.11. Configuring a task - with configure() method

`build.gradle`

    task myCopy(type: Copy)

    myCopy.configure {
       from('source')
       into('target')
       include('**/*.txt', '**/*.xml', '**/*.properties')
    }

Every task has a `configure()` method, which you can pass a closure for configuring the task. Gradle uses this style for configuring objects in many places, not just for tasks.

You can also use a configuration closure when you define a task.

Example 13.12. Defining a task with closure

`build.gradle`

    task copy(type: Copy) {
       from 'resources'
       into 'target'
       include('**/*.txt', '**/*.xml', '**/*.properties')
    }

## 13.4. Adding dependencies to a task

There are several ways you can define the dependencies of a task. In Section 4.3, “Task dependencies” you were introduced to defining dependencies using task names. Task names can refer to tasks in the same project as the task, or to tasks in other projects. To refer to a task in another project, you prefix the name of the task with the path of the project it belongs to. Below is an example which adds a dependency from `projectA:taskX` to `projectB:taskY`:

Example 13.13. Adding dependency on task from another project

`build.gradle`

    project('projectA') {
        task taskX(dependsOn: ':projectB:taskY') << {
            println 'taskX'
        }
    }

    project('projectB') {
        task taskY << {
            println 'taskY'
        }
    }

Output of `gradle -q taskX`

    > gradle -q taskX
    taskY
    taskX

Instead of using a task name, you can define a dependency using a `Task` object, as shown in this example:

Example 13.14. Adding dependency using task object

`build.gradle`

    task taskX << {
        println 'taskX'
    }

    task taskY << {
        println 'taskY'
    }

    taskX.dependsOn taskY

Output of `gradle -q taskX`

    > gradle -q taskX
    taskY
    taskX

For more advanced uses, you can define a task dependency using a closure. When evaluated, the closure is passed the task whose dependencies are being calculated. The closure should return a single `Task` or collection of `Task` objects, which are then treated as dependencies of the task. The following example adds a dependency from `taskX` to all the tasks in the project whose name starts with `lib`:

Example 13.15. Adding dependency using closure

`build.gradle`

    task taskX << {
        println 'taskX'
    }

    taskX.dependsOn {
        tasks.findAll { task -> task.name.startsWith('lib') }
    }

    task lib1 << {
        println 'lib1'
    }

    task lib2 << {
        println 'lib2'
    }

    task notALib << {
        println 'notALib'
    }

Output of `gradle -q taskX`

    > gradle -q taskX
    lib1
    lib2
    taskX

For more information about task dependencies, see the `Task` API.

## 13.5. Adding a description to a task

You can add a description to your task. This description is for example displayed when executing `gradle -t`.

Example 13.16. Adding a description to a task

`build.gradle`

    task copy(type: Copy) {
       description = 'Copies the resource directory to the target directory.'
       from 'resources'
       into 'target'
       include('**/*.txt', '**/*.xml', '**/*.properties')
    }

## 13.6. Replacing tasks

Sometimes you want to replace a task. For example if you want to exchange a task added by the Java Plugin with a custom task of a different type. You can achieve this with:

Example 13.17. Overwriting a task

`build.gradle`

    task copy(type: Copy)

    task copy(overwrite: true) << {
        println('I am the new one.')
    }

Output of `gradle -q copy`

    > gradle -q copy
    I am the new one.

Here we replace a task of type `Copy` with a simple task. When creating the simple task, you have to set the `overwrite` property to true. Otherwise Gradle throws an exception, saying that a task with such a name already exists.

## 13.7. Skipping tasks

Gradle offers multiple ways to skip the execution of a task.

### 13.7.1. Using a predicate

You can use the `onlyIf()` method to attach a predicate to a task. The task's actions are only executed if the predicate evaluates to true. You implement the predicate as a closure. The closure is passed the task as a parameter, and should return true if the task should execute and false if the task should be skipped. The predicate is evaluated just before the task is due to be executed.

Example 13.18. Skipping a task using a predicate

`build.gradle`

    task hello << {
        println 'hello world'
    }

    hello.onlyIf { !project.hasProperty('skipHello') }

Output of `gradle hello -PskipHello`

    > gradle hello -PskipHello
    :hello SKIPPED as onlyIf is false

    BUILD SUCCESSFUL

    Total time: 1 secs

### 13.7.2. Using StopExecutionException

If the rules for skipping a task can't be expressed with predicate, you can use the `StopExecutionException` . If this exception is thrown by an action, the further execution of this action as well as the execution of any following action of this task is skipped. The build continues with executing the next task.

Example 13.19. Skipping tasks with StopExecutionException

`build.gradle`

    task compile << {
        println 'We are doing the compile.'
    }

    compile.doFirst {
        // Here you would put arbitrary conditions in real life. But we use this as an integration test, so we want defined behavior.
        if (true) { throw new StopExecutionException() }
    }
    task myTask(dependsOn: 'compile') << {
       println 'I am not affected'
    }

Output of `gradle -q myTask`

    > gradle -q myTask
    I am not affected

This feature is helpful if you work with tasks provided by Gradle. It allows you to add conditional execution of the built-in actions of such a task. [12]

### 13.7.3. Enabling and disabling tasks

Every task has also an `enabled` flag which defaults to `true`. Setting it to `false` prevents the execution of any of the task's actions.

Example 13.20. Enabling and disabling tasks

`build.gradle`

    task disableMe << {
        println 'This should not be printed if the task is disabled.'
    }
    disableMe.enabled = false

Output of `gradle disableMe`

    > gradle disableMe
    :disableMe SKIPPED

    BUILD SUCCESSFUL

    Total time: 1 secs

## 13.8. Task rules

Sometimes you want to have a task which behavior depends on a large or infinite number value range of parameters. A very nice and expressive way to provide such tasks are task rules:

Example 13.21. Task rule

`build.gradle`

    tasks.addRule("Pattern: ping<ID>") { String taskName ->
        if (taskName.startsWith("ping")) {
            task(taskName) << {
                println "Pinging: " + (taskName - 'ping')
            }
        }
    }

Output of `gradle -q pingServer1`

    > gradle -q pingServer1
    Pinging: Server1

The String parameter is used as a description for the rule. This description is shown when doing for example `gradle -t`.

Rules not just work for calling tasks from the command line. You can also create dependsOn relations on rule based tasks:

Example 13.22. Dependency on rule based tasks

`build.gradle`

    tasks.addRule("Pattern: ping<ID>") { String taskName ->
        if (taskName.startsWith("ping")) {
            task(taskName) << {
                println "Pinging: " + (taskName - 'ping')
            }
        }
    }

    task groupPing {
        dependsOn pingServer1, pingServer2
    }

Output of `gradle -q groupPing`

    > gradle -q groupPing
    Pinging: Server1
    Pinging: Server2

## 13.9. Summary

If you are coming from Ant, such an enhanced Gradle task as Copy looks like a mixture between an Ant target and an Ant task. And this is actually the case. The separation that Ant does between tasks and targets is not done by Gradle. The simple Gradle tasks are like Ant's targets and the enhanced Gradle tasks also include the Ant task aspects. All of Gradle's tasks share a common API and you can create dependencies between them. Such a task might be nicer to configure than an Ant task. It makes full use of the type system, is more expressive and easier to maintain.

[11] If you use the Java Plugin, this task is automatically created and added to your project.

[12] You might be wondering why there is neither an import for the `StopExecutionException` nor do we access it via its fully qualified name. The reason is, that Gradle adds a set of default imports to your script. These imports are customizable (see Appendix C, Existing IDE Support and how to cope without it).