Gradle Task

From NovaOrdis Knowledge Base
Jump to navigation Jump to search

External

Internal

Overview

A task is a core Gradle concept. It represents a single atomic piece of work for a build, such as compiling classes or generating javadoc. Task may depend on each other. Any build ends up executing a sequence of tasks in succession, or in parallel, after all tasks have been arranged in a directed acrylic graph. Understanding how the directed acyclic graph is built and how tasks are scheduled for execution is key to understanding how gradle works.

Each task belongs to a specific project. The association is made when the task is declared in build.gradle or when the plugin that declares the task is applied to the project in build.gradle.

Each task has a name, which can be used to refer to the task within its project, and a fully qualified path, which is unique across all projects. The path is the concatenation of the owning project's path and the task name, separated by the ":" character:

:sub-project-A:child-B:taskC

A build consists in executing a sequence of tasks in succession. Gradle computes the Directed Acyclic Graph of tasks necessary to be executed to fulfill the tasks specified on command line, and then executes the task actions, honoring inter-task dependencies and insuring the fact that a task is executed only once. Gradle builds the complete dependency graph before any tasks is executed.


Behavior must be declared in a task action to be executed at the execution phase. Anything declared in a task that does not belong to an action is executed at the configuration phase. For more details see Explicit Task Declaration.

Displaying Tasks

Some of the common tasks for a project can be displayed with:

gradle [:project-path:]tasks

In case of the root project, the project path is empty:

gradle tasks

For a sub-project:

gradle :sub-project-A:tasks

Custom tasks declared in the project's build.gradle are not present in the output.

All tasks of a project, including the custom tasks and the tasks of its sub-projects, if any, can be displayed with:

gradle [:project-path:]tasks --all

For the root project:

gradle tasks --all

Details about a specific task can be obtained with:

gradle help --task <task-name>

Display Tasks in Task Execution Graph in Execution Order

To display all tasks in the task execution graph, use:

println "Tasks in Task Execution Graph, in execution order: " + gradle.taskGraph.allTasks

Task Execution Order

A task may have dependencies on other tasks or might be scheduled to always run after another task. Gradle ensures that all task dependencies and ordering rules are honored during the execution phase, so that the task is executed after all of its dependencies and any "must run after" tasks have been executed.

Command Line to Task Execution Graph

The execution graph is built starting from task names specified on command line. The names specified on command line are looked up in all projects of the build, and if they exist in any project, they will be added to the execution graph.

Declaring Dependencies between Tasks

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

Dependencies can be declared directly inside tasks:

task a {

    // ...
}

task b {

    // ....

    dependsOn 'a'
}

Functions that can be used to declare dependencies between tasks are:

dependsOn '<task-name>', '<task-name>', ... 
mustRunAfter '<task-name>', ...

Tasks names as String can be used, but also the following:

  • An absolute and relative path, as String.
  • A Task.
  • A closure. The closure may task a task as a parameter. It may return any of the types returned here, and its return value is recursively converted into a task. null is treated as an empty collection.
  • A TaskDependency.
  • A Buildable.
  • A RegularFileProperty or DirectoryProperty.
  • An Iterable, Collection, Map or array that contains the types listed here.
  • A Callable.
setDependsOn


Describe overall execution process. How is the dependency graph started?

For a multi-project build, if each of the projects have a 'clean' task, when I run 'gradle clean' all of them are run. Why? If I add a 'clean' task to the root project, all (sub-projects' and root project's) are run. Why?


Parallel Execution

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

Task Action

Each task consists of a sequence of Action objects, which are executed in the order of their declaration. Actions can be added to a task by calling Task's doFirst() or doLast() methods with an action closure. When the action is executed, the closure is called with the task as parameter.

task someTask {
  doFirst|doLast { action-closure }
}

The last doFirst() invocation will configure the action that is executed first. The last doLast() invocation will configure the action that is executed last. The execution order is easy to figure out if you think of an action queue to which doFirst() and doLast() add actions at the head or at the tail.

Actions can be anonymous or named.

Task Failure

Any task failure stops the build, with two exceptions:

  1. If the task action throws StopActionException, it aborts the current action, and continues at the next action.
  2. If the task action throws StopExecutionException, it aborts the current action, and continues at the next task.

Conditional Execution

onlyIf { closure }
onlyIf ( onlyIfSpec )

Task Properties

TODO when needed https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#N17986

Task Container

TODO https://docs.gradle.org/4.7/javadoc/org/gradle/api/tasks/TaskContainer.html

Task Sources

Default Tasks

Any build comes with a number of pre-defined default tasks, regardless on whether plugins have been applied or not. They are available below:

gradle dependencies

Displays all dependencies (classpath) for various dependency configurations of the root project or a sub-project. More details in:

Inspecting Dependencies
gradle dependencyInsight

Displays the insight into a specific dependency. More details in:

Inspecting Dependencies
gradle dependentComponents

Displays the dependent components of components in project ':subproject-A'.

gradle model

Displays the configuration model of project ':subproject-A'.

gradle projects

Displays the sub-projects of project ':subproject-A'.

gradle properties 

Displays the properties of project ':subproject-A'.

gradle tasks 

Displays the tasks runnable from project ':subproject-A'.

gradle buildEnvironment

Displays all buildscript dependencies declared in project ':subproject-A'.

gradle components

Displays the components produced by project ':subproject-A'.

Tasks From Plugins

Plugins that have been applied to the project may come with their own tasks. This is a non-exhaustive list:

Explicit Task Declaration

Tasks may be explicitly declared in build.gradle using the "task" keyword (Project's task() method). There are four forms to declare custom tasks:

task <task-name> // for empty tasks
task <task-name> { configuration-closure }
task <task-name>(type: <SomeTaskType>) // empty task of a specific type
task <task-name>(type: <SomeTaskType>)  { configuration-closure }

The configuration closures [#Task_Action|should add actions]], as described above.

As an example, a task can be declared as follows:

task sample {

    println 'this is not an action, but a statement to be executed when the task is declared, in the build configuration phase'

    doFirst {

         println 'action executed second'
    }

    doFirst {

         println 'action executed first'
    }
 
    doLast {

         println 'action executed last'
    }
}

Note that the statements that are not part of a task action, declared outside doFirst {} and doLast {} in the task configuration closure will be executed in the build configuration phase, when the task is declared, not in the build execution phase.

Task Types

https://docs.gradle.org/current/dsl/#N10376

Copy

Copy Task

Delete

Delete Task

Archive Tasks

Archive Tasks

Exec

Exec executes a command line process.

task runMain(type: Exec) {
    commandLine 'echo', 'something'
}

JavaExec

JavaExec executes a Java application in a child process.

task runMain(type: JavaExec) {
  classpath = 'something'
  main = 'io.example.Main'
}

JavaExec does not require implicitly the Java plugin, but it needs a classpath, and including the Java plugin allows us to express it as a project variable:

apply plugin: 'java'

task runMain(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'io.example.Main'
}

The Java plugin adds "main" to the sourceSets, and initializes its runtimeClasspath.

GenerateMavenPom

GenerateMavenPom generates a Maven module descriptor (POM) file.

PublishToMavenRepository

PublishToMavenRepository publishes a Maven publication to a Maven artifact repository.

React to a Task's Life Cycle Events

TODO: Research necessary.

Task Creation

tasks.whenTaskAdded { task ->
      task.ext.srcDir = 'src/main/java'
}

Task Execution

gradle.taskGraph.beforeTask { Task task ->
      println "executing $task ..."
}
gradle.taskGraph.afterTask { Task task, TaskState state ->
      if (state.failure) {
          println "FAILED"
      }
      else {
          println "done"
      }
}