Using Tasks
The work that Gradle can do on a project is defined by one or more tasks.
A task represents some independent unit of work that a build performs. This might be compiling some classes, creating a JAR, generating Javadoc, or publishing some archives to a repository.
When a user runs ./gradlew build
in the command line, Gradle will execute the build
task along with any other tasks it depends on.
List available tasks
Gradle provides several default tasks for a project, which are listed by running ./gradlew tasks
:
> Task :tasks
------------------------------------------------------------
Tasks runnable from root project 'myTutorial'
------------------------------------------------------------
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'myTutorial'.
...
Tasks either come from build scripts or plugins.
Once we apply a plugin to our project, such as the application
plugin, additional tasks become available:
plugins {
id("application")
}
plugins {
id 'application'
}
$ ./gradlew tasks
> Task :tasks
------------------------------------------------------------
Tasks runnable from project ':app'
------------------------------------------------------------
Application tasks
-----------------
run - Runs this project as a JVM application
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Other tasks
-----------
compileJava - Compiles main Java source.
...
Many of these tasks, such as assemble
, build
, and run
, should be familiar to a developer.
Task classification
There are two classes of tasks that can be executed:
-
Actionable tasks have some action(s) attached to do work in your build:
compileJava
. -
Lifecycle tasks are tasks with no actions attached:
assemble
,build
.
Typically, a lifecycle tasks depends on many actionable tasks, and is used to execute many tasks at once.
Task registration and action
Let’s take a look at a simple "Hello World" task in a build script:
tasks.register("hello") {
doLast {
println("Hello world!")
}
}
tasks.register('hello') {
doLast {
println 'Hello world!'
}
}
In the example, the build script registers a single task called hello
using the TaskContainer API, and adds an action to it.
If the tasks in the project are listed, the hello
task is available to Gradle:
$ ./gradlew app:tasks --all
> Task :app:tasks
------------------------------------------------------------
Tasks runnable from project ':app'
------------------------------------------------------------
Other tasks
-----------
compileJava - Compiles main Java source.
compileTestJava - Compiles test Java source.
hello
processResources - Processes main resources.
processTestResources - Processes test resources.
startScripts - Creates OS-specific scripts to run the project as a JVM application.
You can execute the task in the build script with ./gradlew hello
:
$ ./gradlew hello
Hello world!
When Gradle executes the hello
task, it executes the action provided.
In this case, the action is simply a block containing some code: println("Hello world!")
.
Task group and description
The hello
task from the previous section can be detailed with a description and assigned to a group with the following update:
tasks.register("hello") {
group = "Custom"
description = "A lovely greeting task."
doLast {
println("Hello world!")
}
}
tasks.register('hello') {
group = 'Custom'
description = 'A lovely greeting task.'
doLast {
println 'Hello world!'
}
}
Once the task is assigned to a group, it will be listed by ./gradlew tasks
:
$ ./gradlew tasks
> Task :tasks
Custom tasks
------------------
hello - A lovely greeting task.
To view information about a task, use the help --task <task-name>
command:
$./gradlew help --task hello
> Task :help
Detailed task information for hello
Path
:app:hello
Type
Task (org.gradle.api.Task)
Options
--rerun Causes the task to be re-run even if up-to-date.
Description
A lovely greeting task.
Group
Custom
As we can see, the hello
task belongs to the custom
group.
Task dependencies
You can declare tasks that depend on other tasks:
tasks.register("hello") {
doLast {
println("Hello world!")
}
}
tasks.register("intro") {
dependsOn("hello")
doLast {
println("I'm Gradle")
}
}
tasks.register('hello') {
doLast {
println 'Hello world!'
}
}
tasks.register('intro') {
dependsOn tasks.hello
doLast {
println "I'm Gradle"
}
}
$ gradle -q intro Hello world! I'm Gradle
The dependency of taskX
to taskY
may be declared before taskY
is defined:
tasks.register("taskX") {
dependsOn("taskY")
doLast {
println("taskX")
}
}
tasks.register("taskY") {
doLast {
println("taskY")
}
}
tasks.register('taskX') {
dependsOn 'taskY'
doLast {
println 'taskX'
}
}
tasks.register('taskY') {
doLast {
println 'taskY'
}
}
$ gradle -q taskX taskY taskX
The hello
task from the previous example is updated to include a dependency:
tasks.register("hello") {
group = "Custom"
description = "A lovely greeting task."
doLast {
println("Hello world!")
}
dependsOn(tasks.assemble)
}
tasks.register('hello') {
group = "Custom"
description = "A lovely greeting task."
doLast {
println("Hello world!")
}
dependsOn(tasks.assemble)
}
The hello
task now depends on the assemble
task, which means that Gradle must execute the assemble
task before it can execute the hello
task:
$ ./gradlew :app:hello
> Task :app:compileJava UP-TO-DATE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE
> Task :app:jar UP-TO-DATE
> Task :app:startScripts UP-TO-DATE
> Task :app:distTar UP-TO-DATE
> Task :app:distZip UP-TO-DATE
> Task :app:assemble UP-TO-DATE
> Task :app:hello
Hello world!
Task configuration
Once registered, tasks can be accessed via the TaskProvider API for further configuration.
For instance, you can use this to add dependencies to a task at runtime dynamically:
repeat(4) { counter ->
tasks.register("task$counter") {
doLast {
println("I'm task number $counter")
}
}
}
tasks.named("task0") { dependsOn("task2", "task3") }
4.times { counter ->
tasks.register("task$counter") {
doLast {
println "I'm task number $counter"
}
}
}
tasks.named('task0') { dependsOn('task2', 'task3') }
$ gradle -q task0 I'm task number 2 I'm task number 3 I'm task number 0
Or you can add behavior to an existing task:
tasks.register("hello") {
doLast {
println("Hello Earth")
}
}
tasks.named("hello") {
doFirst {
println("Hello Venus")
}
}
tasks.named("hello") {
doLast {
println("Hello Mars")
}
}
tasks.named("hello") {
doLast {
println("Hello Jupiter")
}
}
tasks.register('hello') {
doLast {
println 'Hello Earth'
}
}
tasks.named('hello') {
doFirst {
println 'Hello Venus'
}
}
tasks.named('hello') {
doLast {
println 'Hello Mars'
}
}
tasks.named('hello') {
doLast {
println 'Hello Jupiter'
}
}
$ gradle -q hello Hello Venus Hello Earth Hello Mars Hello Jupiter
The calls doFirst and doLast can be executed multiple times.
They add an action to the beginning or the end of the task’s actions list.
When the task executes, the actions in the action list are executed in order.
|
Here is an example of the named
method being used to configure a task added by a plugin:
tasks.dokkaHtml.configure {
outputDirectory.set(buildDir)
}
tasks.named("dokkaHtml") {
outputDirectory.set(buildDir)
}
Task types
Gradle tasks are a subclass of Task
.
In the build script, the HelloTask
class is created by extending DefaultTask
:
// Extend the DefaultTask class to create a HelloTask class
abstract class HelloTask : DefaultTask() {
@TaskAction
fun hello() {
println("hello from HelloTask")
}
}
// Register the hello Task with type HelloTask
tasks.register<HelloTask>("hello") {
group = "Custom tasks"
description = "A lovely greeting task."
}
// Extend the DefaultTask class to create a HelloTask class
class HelloTask extends DefaultTask {
@TaskAction
void hello() {
println("hello from HelloTask")
}
}
// Register the hello Task with type HelloTask
tasks.register("hello", HelloTask) {
group = "Custom tasks"
description = "A lovely greeting task."
}
The hello
task is registered with the type HelloTask
.
Executing our new hello
task:
$ ./gradlew hello
> Task :app:hello
hello from HelloTask
Now the hello
task is of type HelloTask
instead of type Task
.
The Gradle help
task reveals the change:
$ ./gradlew help --task hello
> Task :help
Detailed task information for hello
Path
:app:hello
Type
HelloTask (Build_gradle$HelloTask)
Options
--rerun Causes the task to be re-run even if up-to-date.
Description
A lovely greeting task.
Group
Custom tasks
Built-in task types
Gradle provides many built-in task types with common and popular functionality, such as copying or deleting files.
This example task copies *.war
files from the source
directory to the target
directory using the Copy
built-in task:
tasks.register<Copy>("copyTask") {
from("source")
into("target")
include("*.war")
}
tasks.register('copyTask', Copy) {
from("source")
into("target")
include("*.war")
}
There are many task types developers can take advantage of, including GroovyDoc
, Zip
, Jar
, JacocoReport
, Sign
, or Delete
, which are available in the DSL.
Next Step: Learn how to write Tasks >>