Gradle Task

From NovaOrdis Knowledge Base
Revision as of 21:31, 8 October 2020 by Ovidiu (talk | contribs) (→‎Group)
Jump to navigation Jump to search

External

Internal

Overview

A task represents a well defined piece of work that is executing during a build, such as compiling Java classes or creating a distribution file. The work executed by a task is further divided into individual task actions, defined and managed by the task. The goal of a Gradle build is to execute a set of tasks in a well defined sequence, after the task have been arranged in a directed acyclic graph, computed based on each task's implicit and explicit dependencies. Understanding how the directed acyclic graph is built and how tasks are scheduled for execution is key to understanding how Gradle works.

A tasks belongs to a project. Each project comes with a set of pre-defined, built-in tasks. Each declared plugin may add its own tasks. New simple tasks can be defined in-line in build.gradle or in script plugins. Tasks whose implementations are available on the build's classpath can be declared and configured in build.gradle, as enhanced tasks, and thus made available for use during the build. Complex tasks can even be fully defined in-line or in script plugins, by providing the task code in-line in the script, though this is not a recommended practice, as it does not encourage modularization, encapsulation and sharing.

Any task instance implements org.gradle.api.Task interface. By default, every newly created task is of type org.gradle.api.DefaultTask, the standard implementation of org.gradle.api.Task.

Declaring, configuring and defining tasks is done via corresponding Project API methods:

Project.task(String name)
Project.task(String name, Closure configureClosure)
Project.task(String name, Action<? super Task> configureAction)
Project.task(Map<String, ?> args, String name)
Project.task(Map<String, ?> args, String name, Closure configureClosure)

A Gradle build executes the task specified on command line, including all explicit and implicit dependencies of the task.

./gradlew build

Task Lifecycle

The tasks are instantiated and configured in the build configuration phase, by executing their configuration closures. The task's actions are executed in the execution phase.

Task Configuration Closure

Task configuration closures declare code that configures the task during the build configuration phase. The configuration closure usually add actions. Note that the statements that are not part of a task action, declared outside doFirst and doLast closures, will be executed in the configuration phase, when the task is initialized and configured, not in the build execution phase. For more details, see Task Lifecycle, above.

Task Structure

Name and Path

Each task has a name, which is unique within the context of its owning project. The name must not contain dashes. Since different projects may contain tasks with the same name, a task is uniquely identified by its path in the context of a multi-project build. The path is the concatenation of the task owning project name and the task name, separated by the ":" character.

Action

An action is the place within a task where to place the build logic. Each task contains a list of actions, which are executed in order in which they were added to the task's internal list of actions when the task is executed.

Usually, actions can also be added in-line with corresponding DSL keywords doFirst and doLast, followed by closure that contain executable code, as shown in Defining a Simple Task section. However, actions can be added to the task by invoking the Task API methods doFirst(Action|Closure), which adds the action at the head of the list, and doLast(Action|Closure), which adds the action at the tail of the list, on the task reference.

Other Task State

Group

A task group defines the logical grouping of tasks. The task group is available via the "group" property of the task instance, and can be set within the task constructor or directly setting the property:

task example {
  group = "experimental"
  doLast {
    ...
  }
}
task example(group: "experimental", description: "experimental task") {
  doLast {
    ...
  }
}

Description

Dependencies and Ordering

https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#N18D13

May times, a task requires another task to run first, especially if the task depends on the produced output of its dependency task. A task may declared its dependencies explicitly. A task may depend on other tasks implicitly, as described in the Implicit Dependencies section.

Explicit Dependencies

The Task API used to declare explicit task dependencies is Task.dependsOn(Object... paths), which surfaces in the DSL as:

task red {
  dependsOn 'blue'
}

Note that a task dependency may be another task name, the task instance itself or another objects. TODO: https://docs.gradle.org/current/javadoc/org/gradle/api/Task.html#dependencies

Implicit Dependencies

Inputs and Outputs

Task inputs and outputs are obtained with Task.getInputs() and Task.getOutputs(), which return TaskInputs and TaskOutputs instances, respectively.

Other Task State

Enabled

Description

Defining Custom Tasks

https://docs.gradle.org/current/userguide/custom_tasks.html

The simplest way of extending Gradle is write a custom task. The custom task can be declared in-line in the default build script build.gradle, as a simple task. The simple task can also be declared in-line in a separate build script, which is then included from the default build script. The code of the custom task can live in a separate source file or multiple files, which in turn can be declared in buildSrc, which is a special area of the Gradle project, or can be shared with other projects as part of a library, developed in its own project. Such a task is referred to as a enhanced task.

Simple Task

A simple task is an implementation of org.gradle.api.DefaultTask that can be declared in-line in build.gradle or in script plugin using DSL keywords ("task", "doFirst", "doLast", etc.) corresponding to Task API methods. The example below shows a syntax where the task name and a task configuration closure are provided.

task <task-name> { <configuration-closure> }
task customSimpleTask {

  // this is the task configuration closure, it is executed during the configuration phase
  println "this will be displayed during configuration phase"

  // will add the action defined in the closure at the head of the action list
  doFirst {
    println "this will be executed second when the action is executed in the build execution phase"
  }

  doFirst {
    println "this will be executed first when the action is executed in the build execution phase"
  }

  // will add the action defined in the closure at the tail of the action list
  doLast {
    println "this will be executed last when the action is executed in the build execution phase"
  }
}

Examples:

Enhanced Task

Extending Gradle with Custom Enhanced Tasks

Built-in Tasks

Each build exposes a set of built-in tasks, that can be used right away without any additional configuration or loading any plugin:

Task Operations

TO DEPLETE

Gradle Task TODEPLETE