Using the Gradle π as a powerful instrument for your builds requires a little bit of practice π
- Process of automating software creation and release
- Typical examples:
- Compiling source code
- Running tests
- Building binary artifacts
- Gradle is a general-purpose build automation tool
- Flexible yet powerful for different use cases
- Building Java applications
- Building Android applications
- Automating Go or Python projects
- Generating documentation
- and a lot of other β¦
- Runs on the Java virtual machine
- Build logic defined as instructions in a script
- Plugins can provide predefined functionality
- Tool can be executed fro the terminal and IDE, or on CI server
- Requires JDK pre-installed
- Can be installed as a standalone application in system
- manually from site https://gradle.org/install/
- from package manager of your system (
brew
,apt-get
, etc)
- Using Gradle Wrapper
- From an IDE like Intellij IDEA
- create empty Gradle project
- Project: models a software component
- Build script: contains automation instructions for a project
- Task: defines executable automation instructions
- open
gradle-learning-playground
project - go to
theory/hello-world
module - execute task from terminal
- execute task from IDEA
- Gradle defines a domain-specific language (DSL)
- Can mix in imperative logic
- But more focused on declarative approach
flowchart TD;
BS[Build Script]-.->Kotlin([Kotlin DSL]);
BS-.->Groovy([Groovy DSL]);
tasks.register("helloWorld") {
doLast {
println("Hello World")
}
}
flowchart TD;
Project -- 1..n --o Task
Task -- 1.. n --o Action
Kotlin DSL
tasks.create("helloWorld") {
doLast {
println("Hello World")
}
}
Groovy DSL
task helloWorld {
doLast {
println "Hello World"
}
}
- π€Β difference
tasks.register(...)
vstasks.create(...)
- Gradle API can include breaking changes in between major versions
- Maintaining multiple Gradle installations on a developer machine is not convenient
- Gradle Wrapper is a set of files checked into Git alongside source code
- Standardizes compatible Gradle version for a project
- Automatically downloads the Gradle distribution with defined version
- Show Gradle Wrapper distribution location
- Show
wrapper
task configuration
- Developers do not need to install the Gradle runtime
- Developers can check out project source code and build right away
- Wrapper works the same way on continuous integration servers
flowchart TD;
build.gradle([build.gradle.kts]) -.- src([src])
style build.gradle stroke: orange
style src fill: #417DB7,
Characteristics
- Placed in root directory of project hierarchy
- Contains all build logic
- Can become hard to maintain
flowchart LR;
build.gradle([build.gradle.kts]) --- module1([module1])
build.gradle([build.gradle.kts]) --- module2([module2])
module1 ~~~ build.gradle1
module2 ~~~ build.gradle2
build.gradle1([build.gradle.kts]) -.- src1([src])
build.gradle2([build.gradle.kts]) -.- src2([src])
style build.gradle stroke: orange
style module1 fill: #0e2469, stroke: #0e2469
style module2 fill: #0e2469, stroke: #0e2469
style build.gradle1 stroke: orange
style src1 fill: #417DB7
style build.gradle2 stroke: orange
style src2 fill: #417DB7
flowchart TB;
build.gradle([build.gradle.kts]) ~~~ settings.gradle([settings.gradle.kts])
settings.gradle --- module1([module1])
settings.gradle --- module2([module2])
style build.gradle stroke: orange
style settings.gradle stroke: orange
Characteristics
- Placed in root directory of project hierarchy
- Declares participating projects
- Can contain common build configurations and settings
flowchart TB;
build.gradle([build.gradle.kts]) ~~~ settings.gradle([settings.gradle.kts])
settings.gradle ~~~ gradle.properties([gradle.properties])
style build.gradle stroke: orange
style settings.gradle stroke: orange
style gradle.properties stroke: orange
Characteristics
- Placed in root directory of project hierarchy or Gradle user home directory
- Pre configures runtime behaviour
Configuring the Build Environment
- Defines executable unit of work
- Actions contain logic to be executed during runtime
- General categorisation:
- ad hoc tasks
- tasks explicitly declaring a type
flowchart BT;
DefaultTask([Default Task])
AdHocTask([Ad Hoc Task]) -. extends .-> DefaultTask
style DefaultTask stroke: orange
style AdHocTask fill: #417DB7,
Characteristics
- Implements one-off, simple action code by defining
doFirst
ordoLast
- Automatically extend
DefaultTask
without having to declare it
tasks.register("helloWorld") { // No explicit type
doLast {
println("Hello World") // Action definition
}
}
flowchart BT;
CopyTask([Copy])
TypedTask([Typed Task]) -. extends .-> CopyTask
style CopyTask stroke: orange
style TypedTask fill: #417DB7,
Characteristics
- Explicitly declares type (for example
Copy
) - Does not necessarily need to define actions as they are already provided by type
- Can be configured for specific needs
tasks.register<Copy>("copyFiles") { // Explicit type as generic
group = "custom-copy"
description = "Copies files from one directory to another"
from("sourceFiles") // Method provided by Copy task API
into("destinationFiles") // Method provided by Copy task API
}
- copy task example and run
- zip task example and run
flowchart LR;
A -- dependsOn --> B
A -- dependsOn --> C
- Ensures that B and C is executed before A
- Does not explicitly define A if B or C is executed first
- Execution is not deterministic before runtime
flowchart TD;
A -- dependsOn --> B
A -- dependsOn --> C
B -- mustRunAfter --> C
- Order of task execution can be specified by:
- dependsOn
- mustRunAfter
- shouldRunAfter
- More at https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#org.gradle.api.Task.dependencies
flowchart LR;
A[A - Node] -- Graph Edge --> B[B - Node]
- Task is represented as node
- Task dependency is represented as graph edge
flowchart LR;
A <--X--> B
- Dependency cycles cannot be formed
- Gradle will fail build if detected
- Evaluates instructions in build scripts
- Creates and configures tasks
- Executes tasks in correct order
flowchart LR;
init[Initialization Phase] --> config[Configuration Phase]
config --> exec[Execution Phase]
Init - evaluates settings file and sets up build
Config - evaluates build scripts and runs configuration logic
Exec - executes task actions in correct order
// configuration code
tasks.register("helloWorld") {
// configuration code
doFirst {}
doLast {}
}
- Always outside of
doFirst
anddoLast
actions - Executed during configuration phase
tasks.register("helloWorld") {
doFirst {
// execution code
}
doLast {
// execution code
}
}
- Always inside of
doFirst
anddoLast
actions - Executed during execution phase
- Avoid repetitive code
- Make build logic more maintainable
- Provide reusable functionality across projects
- There are two types:
- Script plugins
- Binary plugins
flowchart LR;
build.gradle(["build.gradle"]) -- includes --> publishing.gradle(["publishing.gradle"])
build.gradle -- includes --> deployment.gradle(["deployment.gradle"])
style build.gradle stroke: orange
style publishing.gradle stroke: orange
style deployment.gradle stroke: orange
flowchart LR;
build.gradle(["build.gradle"]) -- includes --> core.plugin(["Gradle core plugin"])
build.gradle -- includes --> community.plugin(["Community plugin"])
style build.gradle stroke: orange
style core.plugin stroke: orange
style community.plugin stroke: orange
- Simple Zip script plugin
- Binary plugins example in
plugins { ... }
block
- Why we need them?
- Application vs Testing dependencies, and others
- Dependency notation
group:name:version
- What is SNAPSHOT version?
- Semantic versioning β https://semver.org/
- Transitive dependencies PROBLEM !
- Duplicate/Different versions problem
- BOM as dependencies versions management approach
- usage of dependencies example
- BOM usage example
allprojects { ... }
configurationsubprojects { ... }
configuration- Intellij IDEA examples
- !!! skip for current moment