Gradle supports two types of task. One such type is the simple task, where you define the task with an action closure. We have seen these in Chapter 5, Build Script Basics. For this type of task, the action closure determines the behaviour of the task. This type of task is good for implementing one-off tasks in your build script.
The other type of task is the enhanced task, where the behaviour is built into the task, and the task provides some properties which you can use to configure the behaviour. We have seen these in Chapter 14, More about Tasks. Most Gradle plugins use enhanced tasks. With enhanced tasks, you don't need to implement the task behaviour as you do with simple tasks. You simply declare and configure the task using its properties. In this way, enhanced tasks let you reuse a piece of behaviour in many different places, possibly across different builds.
Implementing your own custom enhanced tasks in Gradle is easy. You can implement a custom task in pretty much any language you like, provided it ends up compiled to bytecode. In our examples, we are going to use Groovy as the implementation language, but you could use, for example, Java or Scala.
There are several places where you can put the source for the task.
You can include the task implementation directly in the build script. This has the benefit that the task class is automatically compiled and included in the classpath of the build script without you having to do anything. However, the task class is not visible outside the build script, and so you cannot reuse the task class outside the build script it is defined in.
buildSrc
projectYou can put the source for the task implementation in the
directory.
Gradle will take care of compiling and testing the task class and making it available on the
classpath of the build script. The task class is visible to every build script used by the build.
However, it is not visible outside the build, and so you cannot reuse the task class outside the
build it is defined in.
Using the rootProjectDir
/buildSrc/src/main/groovybuildSrc
project approach keeps separate
the task declaration - that is, what the task should do - from the task implementation - that is,
how the task does it.
See Chapter 39, Organizing Build Logic for more details about the buildSrc
project.
You can create a separate project for your task implementation. This project produces and publishes a JAR which you can then use in multiple builds and share with others. Generally, this JAR might include a custom plugin, or bundle several related custom tasks into a single library. Or some combination.
In our examples, we will start with the task implementation in the build script, to keep things simple. Then we will look at creating a standalone project.
To implement a custom task, you extend DefaultTask
.
This task doesn't do anything useful, so let's add some behaviour. To do so, we add a method to the task
and mark it with the TaskAction
annotation. Gradle will call the
method when the task executes. You don't have to use a method to define the behaviour for the task. You
could, for instance, call doFirst()
or doLast()
with a closure in the
task constructor to add behaviour.
Example 37.2. A hello world task
build.gradle
task hello(type: GreetingTask) class GreetingTask extends DefaultTask { @TaskAction def greet() { println 'hello from GreetingTask' } }
Output of gradle -q hello
> gradle -q hello hello from GreetingTask
Let's add a property to the task, so we can customize it. Tasks are simply POGOs, and when you declare a
task, you can set the properties or call methods on the task object. Here we add a greeting
property, and set the value when we declare the greeting
task.
Example 37.3. A customizable hello world task
build.gradle
// Use the default greeting task hello(type: GreetingTask) // Customize the greeting task greeting(type: GreetingTask) { greeting = 'greetings from GreetingTask' } class GreetingTask extends DefaultTask { def String greeting = 'hello from GreetingTask' @TaskAction def greet() { println greeting } }
Output of gradle -q hello greeting
> gradle -q hello greeting hello from GreetingTask greetings from GreetingTask
Now we will move our task to a standalone project, so we can publish it and share it with others. This project is simply a Groovy project that produces a JAR containing the task implementation. Here is a simple build script for the project. It applies the Groovy plugin, and adds the Gradle API as a compile-time dependency.
Example 37.4. A build for a custom task
build.gradle
apply plugin: 'groovy'
dependencies {
compile gradleApi()
}
Note: The code for this example can be found at samples/customPlugin
which is in both the binary and source distributions of Gradle.
We just follow the convention for where the source for the task should go.
Example 37.5. A custom task
src/main/groovy/org/gradle/GreetingTask.groovy
package org.gradle import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction class GreetingTask extends DefaultTask { @TaskAction def greet() { println 'hello from GreetingTask' } }
You can use the ProjectBuilder
class to create
Project
instances to use when you test your task implementation.
Example 37.6. Testing a custom task
src/test/groovy/org/gradle/GreetingTaskTest.groovy
class GreetingTaskTest { @Test public void canAddTaskToProject() { Project project = ProjectBuilder.builder().build() def task = project.task('greeting', type: GreetingTask) assertTrue(task instanceof GreetingTask) } }