Gradle Task Dependencies and Ordering

From NovaOrdis Knowledge Base
Revision as of 01:49, 9 November 2020 by Ovidiu (talk | contribs) (→‎Overview)
Jump to navigation Jump to search

External

Internal

Overview

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.

In Gradle, task execution order is automatically determined taking into account explicit dependencies and implicit dependencies, and a specific execution order for the tasks that declared dependencies among themselves is not guaranteed. The only thing that is guaranteed is that the dependencies will be honored. This architectural decision has several benefits: you don't need to know the whole chain of task dependencies to make a change, and because the tasks don't have to be executed strictly sequentially, they can be parallelized.

Gradle offers a way to declare an execution order between tasks.

If tasks belonging to different sub-projects that are part of the same multi-project define dependencies among themselves, that automatically introduces a dependency between the owning projects:

Multi-project builds | Inter-project Dependencies

Explicit Dependencies

A task's explicit dependencies are maintained and can be configured with the task's "dependsOn" property. The Task API used to declare explicit task dependencies is Task.dependsOn(Object... paths), which surfaces in the DSL as:

task red {
  dependsOn 'blue', 'green' // dependency expressed using task names, comma is required for more than one dependencies
  ...
}
// dependency expressed using task objects
task red(dependsOn: [blue, green] {
  ...
}
task red {
  ...
}
red.dependsOn(blue, green) // dependency expressed using task objects
task red {
  ...
}
red.dependsOn blue // dependency expressed using task objects
red.dependsOn green // dependency expressed using task objects

Note that a task dependency may be another task name, the task instance itself or another objects.

If multiple tasks are provides as argument of dependsOn(...), the order in which they are declared does not influence the order in which they are executed. The only thing that is guaranteed is that all will be executed before the task that declares the dependency.

Adding Explicit Dependencies using a Lazy Block

Task dependencies can be defined using a lazy block. When evaluated, the block is passed the task whose dependencies are being calculated. The block should return one task or a collection of tasks, which are then treated as dependencies of the task:

task red {
  ...
}

red.dependsOn {
  tasks.findAll { task -> task.name.startsWith('b') }
}

Other Methods to Set Explicit Dependencies

Other methods that can be used to set explicit dependencies are:

Explicit Dependencies between Tasks belonging to Different Projects

In a multi-project situation, tasks belonging to two different projects can express the dependency on one another by using task paths:

red.dependsOn(':project-a:yellow')
task red(..., dependsOn: [':project-a:yellow', ':project-b:brown']) {
  ...
}
task red {
  dependsOn ':project-a:yellow', ':project-b:brown' // comma is required
}

This explicit dependency also introduces a dependency between projects, causing dependency project ("project-a") to be configured before the current project in the configuration phase.

Finalizer Tasks

A finalizer task is a task that will be scheduled to run after the task that requires finalization, regardless of whether the task succeeds or fails.

task a { ... }
task b { ... }
a.finalizedBy b

Ordering Tasks

Implicit Dependencies

Implicit dependencies are determined base on task inputs and outputs.