Gradle Task TODEPLETE
TO DEPLETE INTO
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
To hook this into a default task execution:
task debugPublish {
dependsOn 'publish'
doFirst {
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, for as many times they appear. For example, if tasks "t" was declared in the root project and "sub-project-A" and "sub-project-B", then the execution graph looks like:
task ':t', task ':subproject-A:t', task ':subproject-B:t'
More tasks are added to the execution graph if the initial tasks have dependencies on other tasks.
Declaring Dependencies between Tasks
Dependencies can be declared directly inside new task declarations:
task a {
// ...
}
task b {
// ....
dependsOn 'a'
}
The order of the declaration matters. The dependency task must be declared before the dependent task.
Dependencies can also be declared inside the script block that configures an existing task:
docker {
dependsOn build
...
}
Dependencies can be declared between tasks that do not belong to the same project. This makes sense as Gradle manages a global task dependency graph. In "project-B":
docker {
dependsOn rootProject.project(':project-A').getTasksByName("build", false).asList().get(0)
...
}
Functions that can be used to declare dependencies between tasks are:
dependsOn '<task-name>', '<task-name>', ...
mustRunAfter '<task-name>', ...
Unfortunately, there's no "mustRunBefore".
finalizedBy '<task-name>', ...
Describe 'mustRunAfter' and 'finalizedBy'.
The task name may be a fully qualified path, thus allowing us to declare dependencies on tasks from another projects, in a multi-project build.
If a task declares a dependency on a task that was declared in multiple projects, only the dependency task that was declared in the same project as the dependent task will be executed, and not all of them.
Aside from task names, the following can be used:
- A closure. The closure may take a task as a parameter. It may return any of the types mentioned below, and its return value is recursively converted into a task. null is treated as an empty collection. For example, the closure shown below returns a set of tasks. Note that the closure is executed after the configuration phase, at the time the closure is executed, all build configuration script have been evaluated.
dependsOn {
Set<Task> tasks = new HashSet<>();
subprojects.each {
tasks.add(it.tasks.findByName('t'))
}
return tasks;
}
- An absolute and relative path, as String.
- A Task.
- A TaskDependency.
- A Buildable.
- A RegularFileProperty or DirectoryProperty.
- An Iterable, Collection, Map or array that contains the types listed here.
- A Callable.
Gradle will detect circular dependencies, if they exist, and fail:
FAILURE: Build failed with an exception. * What went wrong: Circular dependency between the following tasks: :x \--- :subproject-A:t \--- :x (*) (*) - details omitted (listed previously)
Examples of Task Dependency Declarations
Root Project Task Depends on Specific Sub-Project Tasks
task topLevelTask {
dependsOn {
Set<Task> tasks = new HashSet<>();
subprojects.each {
tasks.add(it.tasks.findByName('someName'))
}
return tasks;
}
}
Update this if a better way is found.
The same example can be written by declaring the closure first and then invoking it:
def allSubProjectTasksNamedSomeName = { Task t ->
Set<Task> tasks = new HashSet<>();
subprojects.each {
tasks.add(it.tasks.findByName('someName'))
}
return tasks;
}
task topLevelTask {
dependsOn allSubProjectTasksNamedSomeName
}
Update this if a better way is found.
Declaring a Dependency between an Existing Task and a Custom Task
Declare the custom task with:
task myTask {
doFirst {
...
}
}
Then configure the existing task to depend on the custom task:
assemble {
dependsOn 'myTask'
}
Parallel Execution
By default, tasks are not executed in parallel unless a task is waiting on asynchronous work and another task, which is not dependent, is ready to execute. Parallel execution can be enabled by the --parallel flag when the build is initiated. In parallel mode, the tasks of different projects of a multi-project build able to be executed in parallel.
Task Failure
Any task failure stops the build, with two exceptions:
- If the task action throws StopActionException, it aborts the current action, and continues at the next action.
- 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
The project TaskContainer can be accessed from a build script with:
project-reference.tasks
The TaskContainer can then queried for tasks. Also see Gradle Programming - Obtaining a Task Reference.
Configuring Existing Tasks
TODO more, organize.
All tasks of the same type can be configured at once:
tasks.withType(Test) {
// configure the task
}
Also see Get the Reference of a Task by Name above.
I believe this also works:
test {
// configure the task
}
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:
gradle dependencyInsight
Displays the insight into a specific dependency. More details in:
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:
Task Types
Copy
Delete
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.
CreateStartScripts
clean
Under unclear circumstances, some Gradle deployments complain about not finding the task "clean", though others work well with the same configuration. This can be fixed by applying the "base" plugin:
apply plugin:'base'
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"
}
}