Gradle is a powerful build automation tool used in JVM-based projects like Java, Kotlin, and Groovy. Understanding its task lifecycle is essential for writing efficient and well-structured build scripts. This article explains the Gradle task lifecycle, execution phases, plugin tasks, and the role of doLast {}
in defining main actions.
Gradle Task Lifecycle
A Gradle build goes through three main phases:
1. Initialization Phase
- Identifies the projects involved in the build.
- Creates
Project
objects but does not execute tasks.
2. Configuration Phase
- Evaluates
build.gradle
orbuild.gradle.kts
scripts. - Defines tasks and their dependencies, but does not execute them.
3. Execution Phase
- Determines which tasks need to run based on dependencies.
- Executes each task in the correct order.
- Each task runs in three steps:
doFirst {}
(Pre-action, runs before the main task logic)- Main task action (Defined within
doLast {}
if no type is set) doLast {}
(Post-action, executes after the main task logic)
Execution Phase Example
Let's define some simple tasks and observe their execution order:
// Define taskA
task taskA {
doFirst { println "Before taskA" }
doLast { println "Main action of taskA" }
doLast { println "After taskA" }
}
// Define taskB
task taskB {
doFirst { println "Before taskB" }
doLast { println "Main action of taskB" }
doLast { println "After taskB" }
}
// Define taskC, which depends on taskA and taskB
task taskC {
dependsOn taskA, taskB
doLast { println "Main action of taskC" }
}
Expected Output when Running "gradle taskC"
> Task :taskA
Before taskA
Main action of taskA
After taskA
> Task :taskB
Before taskB
Main action of taskB
After taskB
> Task :taskC
Main action of taskC
Since taskC
depends on taskA
and taskB
, Gradle ensures that taskA
and taskB
execute before taskC
.
Common Main Task Actions
Gradle tasks can perform various actions, such as:
✅ Compiling code (compileJava
)
task compileCode {
doLast { println "Compiling source code..." }
}
✅ Copying files (Copy
task)
task copyFiles(type: Copy) {
from 'src/resources'
into 'build/resources'
}
✅ Running tests (test
task)
task runTests {
doLast { println "Running unit tests..." }
}
✅ Creating a JAR file (Jar
task)
task createJar(type: Jar) {
archiveBaseName.set("myApp")
destinationDirectory.set(file("$buildDir/libs"))
}
✅ Running an application (JavaExec
task)
task runApp(type: JavaExec) {
mainClass = "com.example.Main"
classpath = sourceSets.main.runtimeClasspath
}
✅ Cleaning build directories (clean
task)
task cleanBuild {
doLast {
delete file("build")
println "Build directory cleaned!"
}
}
Are Plugin Tasks Part of the Main Task?
- No, plugin tasks do not run automatically unless explicitly executed or added as dependencies.
- Applying a plugin (e.g.,
java
) provides tasks likecompileJava
,test
, andjar
, but they must be invoked or referenced.
Example:
apply plugin: 'java' // Adds Java-related tasks
task myBuildTask {
dependsOn 'build' // Now includes plugin tasks
doLast { println "Custom build complete!" }
}
Running gradle myBuildTask
executes Java plugin tasks (compileJava
, test
, jar
, etc.) before myBuildTask
.
Do You Need doLast for the Main Task?
-
If a task has no type, the main action must be inside
doLast {}
.task myTask { doLast { println "Executing my task!" } }
-
If a task has a type, it already has built-in behavior, so
doLast {}
is only needed for additional actions.task copyFiles(type: Copy) { from 'src/resources' into 'build/resources' }
Avoid Running Actions Outside doLast
task badTask {
println "This runs during the configuration phase!"
}
❌ Problem: The message prints immediately during configuration, not when the task executes.
✅ Solution: Use doLast {}
.
Final Takeaways
✅ Gradle tasks go through Initialization → Configuration → Execution phases.
✅ Tasks without a type need doLast {}
for their main logic.
✅ Plugin tasks are independent but can be linked via dependencies.
✅ Use built-in tasks (e.g., Copy, Jar, JavaExec) when possible.
✅ Always place executable logic inside doLast{}
for tasks without predefined behavior.
By understanding these concepts, you can write efficient Gradle scripts that optimize build processes. 🚀
Recent Comments