Gradle Task: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
(Replaced content with "=External= * https://docs.gradle.org/current/dsl/org.gradle.api.Task.html =Internal= * Gradle Concepts =TO DEPLETE= {{Internal|Gradle Task TOD...")
Line 7: Line 7:
* [[Gradle_Concepts#Task|Gradle Concepts]]
* [[Gradle_Concepts#Task|Gradle Concepts]]


=Overview=
=TO DEPLETE=
 
{{Internal|Gradle Task TODEPLETE|Gradle Task TODEPLETE}}
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 [[#Parallel_Execution|in parallel if explicitly configured]], after all tasks have been arranged in a [[Graph#Directed_Acyclic_Graph|directed acyclic graph]]. Understanding how the directed acyclic graph is built and how tasks are scheduled for execution is key to understanding how gradle works.
 
Tasks can be explicitly declared in a build configuration file, or can be exposed by plugins.
 
Each task '''belongs to a specific project'''. The association is made when the task is declared in [[Gradle_Project_and_Build_Script#Overview|build.gradle]] or when the plugin that declares the task is applied to the project in [[Gradle_Project_and_Build_Script#Overview|build.gradle]].  A project is essentially a collection of tasks. The tasks of a project can be accessed in a build script with:
 
''project-reference''.tasks
 
This will return the project's [[#Task Container|TaskContainer]].
 
Example:
 
<syntaxhighlight lang='groovy'>
println "" + project.tasks
</syntaxhighlight>
 
<span id='Task_Name'></span>Each task has a '''name''', which can be used to refer to the task within its project, and a <span id='Task_Fully_Qualified_Path'></span>'''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 [[Graph#Directed_Acyclic_Graph|Directed Acyclic Graph]] of tasks necessary to be executed to fulfill the tasks specified on command line, and then executes the [[Gradle_Task#Task_Action|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.
 
{{Warn|Behavior must be declared in a [[#Task_Action|task action]] to be executed at the [[Gradle_Concepts#Build_Execution_Phase|execution phase]]. Anything declared in a task that does not belong to an action is executed at the [[Gradle_Concepts#Build_Configuration_Phase|configuration phase]]. For more details see [[#Explicit_Task_Declaration|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 [[Gradle_Concepts#Overview|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:
 
<syntaxhighlight lang='groovy'>
println "Tasks in Task Execution Graph, in execution order: " + gradle.taskGraph.allTasks
</syntaxhighlight>
 
To hook this into a default task execution:
 
<syntaxhighlight lang='groovy'>
task debugPublish {
  dependsOn 'publish'
  doFirst {
    println "Tasks in Task Execution Graph, in execution order: " + gradle.taskGraph.allTasks
  }
}
</syntaxhighlight>
 
==Dry Run==
 
Display the tasks that would be executed, without actually doing anything
 
[[Gradle_Operations#-m.2C_--dry-run|gradle -m|--dry-run]] ...
 
This is useful in understanding task execution order.
 
=<span id='Get_the_Reference_of_a_Task_by_Name'></span>Obtaining a Task Reference=
 
{{Internal|Gradle_Programming#Obtaining_a_Task_Reference|Gradle Programming - Obtaining a Task Reference}}
 
=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 [[Gradle_Concepts#Execution|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 [[#Declaring_Dependencies_between_Tasks|dependencies on other tasks]].
 
==<span id='Declaring_Dependencies_between_Custom_Tasks'></span>Declaring Dependencies between Tasks==
 
{{External|https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#N1790C}}
 
Dependencies can be declared directly inside new task declarations:
 
<syntaxhighlight lang='groovy'>
task a {
 
    // ...
}
 
task b {
 
    // ....
 
    dependsOn 'a'
}
</syntaxhighlight>
 
{{Warn|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:
 
<syntaxhighlight lang='groovy'>
docker {
 
  dependsOn build
  ...
}
</syntaxhighlight>
 
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":
 
<syntaxhighlight lang='groovy'>
docker {
 
  dependsOn rootProject.project(':project-A').getTasksByName("build", false).asList().get(0)
  ...
}
</syntaxhighlight>
 
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''>', ...
 
<font color=darkgray>Describe 'mustRunAfter' and 'finalizedBy'.</font>
 
The task name may be a [[#Task_Fully_Qualified_Path|fully qualified path]], thus allowing us to declare dependencies on tasks from another projects, in a [[Gradle_Multi-Project_Builds#Overview|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 [[Gradle_Concepts#Configuration|configuration phase]], at the time the closure is executed, all build configuration script have been evaluated.
 
<syntaxhighlight lang='groovy'>
dependsOn {
 
  Set<Task> tasks = new HashSet<>();
  subprojects.each {
      tasks.add(it.tasks.findByName('t'))
  }
  return tasks;
}
</syntaxhighlight>
 
* An absolute and relative path, as String.
* A [https://docs.gradle.org/current/dsl/org.gradle.api.Task.html Task].
* A [https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskDependency.html TaskDependency].
* A [https://docs.gradle.org/current/dsl/org.gradle.api.Buildable.html Buildable].
* A [https://docs.gradle.org/current/javadoc/org/gradle/api/file/RegularFileProperty.html RegularFileProperty] or [https://docs.gradle.org/current/javadoc/org/gradle/api/file/DirectoryProperty.html 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:
 
<font color=red>FAILURE: Build failed with an exception.</font>
* 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====
 
<syntaxhighlight lang='groovy'>
task topLevelTask {
 
    dependsOn {
 
        Set<Task> tasks = new HashSet<>();
 
        subprojects.each {
 
            tasks.add(it.tasks.findByName('someName'))
        }
 
        return tasks;
  }
}
</syntaxhighlight>
 
<font color=darkgray>Update this if a better way is found.</font>
 
The same example can be written by declaring the closure first and then invoking it:
 
<syntaxhighlight lang='groovy'>
def allSubProjectTasksNamedSomeName = { Task t ->
 
    Set<Task> tasks = new HashSet<>();
 
    subprojects.each {
 
        tasks.add(it.tasks.findByName('someName'))
    }
 
    return tasks;
}
 
task topLevelTask {
 
    dependsOn allSubProjectTasksNamedSomeName
}
</syntaxhighlight>
 
<font color=darkgray>Update this if a better way is found.</font>
 
==Declaring a Dependency between an Existing Task and a Custom Task==
 
Declare the custom task with:
 
<syntaxhighlight lang='groovy'>
task myTask {
  doFirst {
    ...
  }
}
</syntaxhighlight>
 
Then configure the existing task to depend on the custom task:
 
<syntaxhighlight lang='groovy'>
assemble {
  dependsOn 'myTask'
}
</syntaxhighlight>
 
==Parallel Execution==
 
{{External|https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#N179C7}}
 
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 [[Gradle_Multi-Project_Builds#Overview|multi-project build]] able to be executed in parallel.
 
=Default Task=
 
A default task can be declared in the build script, so when gradle is invoked without any argument, that task is executed.
 
<syntaxhighlight lang='groovy'>
defaultTasks 'distZip'
</syntaxhighlight>
 
More than one tasks can be declared as "default".
 
=Task Action=
 
Each task consists of a sequence of [https://docs.gradle.org/current/javadoc/org/gradle/api/Action.html 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:
 
# If the task action throws [https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/StopActionException.html StopActionException], it aborts the current action, and continues at the ''next action''.
# If the task action throws [https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/StopExecutionException.html StopExecutionException], it aborts the current action, and continues at the ''next task''.
 
=Conditional Execution=
 
onlyIf { ''closure'' }
 
onlyIf ( ''onlyIfSpec'' )
 
=Task Properties=
 
<font color=darkgray>TODO when needed https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#N17986</font>
 
=Task Container=
 
{{External|https://docs.gradle.org/4.7/javadoc/org/gradle/api/tasks/TaskContainer.html}}
 
The project TaskContainer can be accessed from a build script with:
 
  ''project-reference''.tasks
 
The [https://docs.gradle.org/4.7/javadoc/org/gradle/api/tasks/TaskContainer.html TaskContainer] can then queried for tasks. Also see [[Gradle_Programming#Obtaining_a_Task_Reference|Gradle Programming - Obtaining a Task Reference]].
 
=Configuring Existing Tasks=
 
<font color=darkgray>TODO more, organize.</font>
 
All tasks of the same type can be configured at once:
 
<syntaxhighlight lang='groovy'>
tasks.withType(Test) {
// configure the task
}
</syntaxhighlight>
 
Also see [[#Get_the_Reference_of_a_Task_by_Name|Get the Reference of a Task by Name]] above.
 
<font color=darkgray>I believe this also works: </font>
<syntaxhighlight lang='groovy'>
 
test {
// configure the task
}
</syntaxhighlight>
 
=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 [[Gradle_Concepts#Configurations|configurations]] of the root project or a sub-project. More details in: {{Internal|Gradle_Operations#Inspect_Dependencies|Inspecting Dependencies}}
 
gradle dependencyInsight
 
Displays the insight into a specific dependency. More details in: {{Internal|Gradle_Operations#Inspect_Dependencies|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==
 
[[Gradle_Plugins#Overview|Plugins]] that have been applied to the project may come with their own tasks. This is a non-exhaustive list:
 
* [[Gradle_Java_Plugin#Tasks|Java Plugin Tasks]]
 
==<span id='Explicit_Task_Declaration'></span>Explicit Task Declaration (Custom Tasks)==
 
Tasks may be explicitly declared in [[Gradle_Project_and_Build_Script#Overview|build.gradle]] using the "task" keyword (Project's task() method). There are four forms to declare custom tasks:
 
task <''task-name''> { ''configuration-closure'' }
 
task <''task-name''>(type: <''[[#Task_Types|SomeTaskType]]''>)  { ''configuration-closure'' }
 
The configuration closures [[#Task_Action|should add actions]], as described above.
 
As an example, a task can be declared as follows:
 
<syntaxhighlight lang='groovy'>
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'
    }
}
</syntaxhighlight>
 
Note that the statements that are not part of a [[#Task_Action|task action]], declared outside doFirst {} and doLast {} in the task configuration closure will be executed in the [[Gradle_Concepts#Build_Configuration_Phase|build configuration phase]], when the task is declared, not in the [[Gradle_Concepts#Build_Execution_Phase|build execution phase]].
 
A task can be first declared and then configured later:
 
<syntaxhighlight lang='groovy'>
task something(type: SomeType)
 
something {
 
  // task configuration closure
}
</syntaxhighlight>
 
=Task Types=
 
{{External|https://docs.gradle.org/current/dsl/#N10376}}
 
===Copy===
 
{{Internal|Gradle Copy Task|Copy Task}}
 
===Delete===
 
{{Internal|Gradle Delete Task|Delete Task}}
 
===<span id='Zip'></span><span id='Jar'></span>Archive Tasks===
 
{{Internal|Gradle Archive Tasks|Archive Tasks}}
 
===Exec===
 
[https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Exec.html Exec] executes a command line process.
 
<syntaxhighlight lang='groovy'>
task runMain(type: Exec) {
    commandLine 'echo', 'something'
}
</syntaxhighlight>
 
===JavaExec===
 
[https://docs.gradle.org/current/dsl/org.gradle.api.tasks.JavaExec.html JavaExec] executes a Java application in a child process.
 
<syntaxhighlight lang='groovy'>
task runMain(type: JavaExec) {
  classpath = 'something'
  main = 'io.example.Main'
}
</syntaxhighlight>
 
JavaExec does not require implicitly the [[Gradle_Java_Plugin#Overview|Java plugin]], but it needs a classpath, and including the [[Gradle_Java_Plugin#Overview|Java plugin]] allows us to express it as a project variable:
 
<syntaxhighlight lang='groovy'>
apply plugin: 'java'
 
task runMain(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'io.example.Main'
}
</syntaxhighlight>
 
The [[Gradle_Java_Plugin#Overview|Java plugin]] adds "main" to the sourceSets, and initializes its runtimeClasspath.
 
===GenerateMavenPom===
 
[https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.tasks.GenerateMavenPom.html GenerateMavenPom] generates a Maven module descriptor (POM) file.
 
===PublishToMavenRepository===
 
[https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.tasks.PublishToMavenRepository.html PublishToMavenRepository] publishes a Maven publication to a Maven artifact repository.
 
===CreateStartScripts===
 
{{Internal|Gradle_Application_Plugin#Configure_the_Default_.27startScripts.27_Task|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:
 
<syntaxhighlight lang='groovy'>
apply plugin:'base'
</syntaxhighlight>
 
=React to a Task's Life Cycle Events=
 
<font color=darkgray>TODO: Research necessary.</font>
 
==Task Creation==
 
<syntaxhighlight lang='groovy'>
tasks.whenTaskAdded { task ->
      task.ext.srcDir = 'src/main/java'
}
</syntaxhighlight>
 
==Task Execution==
 
<syntaxhighlight lang='groovy'>
gradle.taskGraph.beforeTask { Task task ->
      println "executing $task ..."
}
gradle.taskGraph.afterTask { Task task, TaskState state ->
      if (state.failure) {
          println "FAILED"
      }
      else {
          println "done"
      }
}</syntaxhighlight>
 
=Display Tasks that Are Executed by a Build=
 
<syntaxhighlight lang='text'>
gradle --info ...
</syntaxhighlight>

Revision as of 20:31, 23 September 2020