Gradle
To make it quick Gradle is an open source build tool. They moved from groovy to kotlin dsl as their main language, both have been there for multiple version, the real change is that the documentation will be oriented toward the kotlin examples first. I would recommend the kotlin version too, however in 2023, it could still be possible find some edge case where groovy could be slightly more performant on complex build.
Why not just use Maven? 🤪
In my opinion one of the advantages of gradle over Maven are mainly thanks to the syntax, the xml
of the maven build files can be really
bulky and hard to maintain, whereas the groovy or kotlin syntax of gradle is much more human-readable and maintainable.
The build “manifest” is not crowded with uninformative tags… less code for more logic is something I appreciate.
Cheat sheet
In this article, I wanted to sum up some quick tips with gradle, and keep up with the newest syntax of the latest version. Since I have already went through some specific use case, I might skip or not go into too many details, so if you are interested check out those articles:
- Java concepts for an overview of java and gradle
- Kotlin with Gradle 4.8 for an example setup with an old version of gradle
- How to publish with Gradle, that showcase how to save a project in the GitHub Package Registry
- How to set up gradle with OpenApi plugin to generate code automatically during build
And now let’s proceed, get your build.gradle.kts
ready!
Wrapper
The Gradle wrapper is a script that invokes a declared version of Gradle, downloading it beforehand if necessary as
per the documentation. It’s a foundation for your project, to make it easier to build it consistently.
Create the gradle wrapper to call ./gradlew
in the version you want with:
gradle wrapper --gradle-version 8.2.1
That’s useful when working with legacy projects that may use older gradle version, or if you want to set a working gradle version in your project.
Dependencies
To show the project dependencies use:
./gradlew dependencies
./gradlew dependencies --configuration <configuration>
The second one is to check the dependency tree for a specific configuration like compileClasspath
or kotlinCompilerClasspath
for kotlin projects.
Add dependencies
To add a dependency, you need to add a repository from where to fetch it and the actual dependency:
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
The compile
and testCompile
has been deprecated. For more info, check the gradle documentation.
Exclude dependencies
This is to either avoid conflicts with clashing dependencies or for any reason you wouldn’t want a specific dependency in your project. To exclude a dependency from your build, from all dependency use:
configurations.all {
exclude(group= "org.group", module= "conflicting-lib")
}
To exclude from a specific configuration (here testImplementation
), you can use:
configurations.testImplementation {
exclude(group = "junit", module = "junit")
}
Why excluding junit 4 in this example? Because I don’t want a mix of junit 4 and 5 in my project. And if the problem is only in one dependency you can also exclude it from there only using:
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "junit")
exclude(module="junit-vintage-engine")
}
The exclude
function is called in the closure of the testImplementation
configuration for the spring-boot-starter-test
dependency.
Multi project dependency
For your multi project build, you can follow the gradle documentation. And to add a subproject as a dependency of another project, you can check the stackoverflow answer.
Publishing
To publish, in a maven repository you will need the maven-publish plugin. Then you will need to add the publishing
script in your build.gradle.kts
:
plugins {
`maven-publish`
}
publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/OWNER/REPOSITORY")
credentials {
username = 'username'
password = 'password'
}
}
}
publications {
create<MavenPublication>("gpr") {
from(components["java"])
}
}
}
group="com.github.OWNER"
version="1.0-SNAPSHOT"
Using properties
Properties are useful to avoid hardcoding values in your build file (e.g. passwords), to add one you can use:
val gprUser: String? by project
val gprApiKey: String? by project
credentials {
username = gprUser
password = gprApiKey
}
Then you can pass the properties via command line on publish
./gradlew publish -PgprUser="username" -PgprApiKey="password"
You can also save some variable in a gradle.properties
file in your project root directory:
gprUser=username
There are other ways to pass the variables, with environment variables or without declared variables:
password = project.findProperty("gprApiKey") as String? ?: System.getenv("GPR_API_KEY")
Tests
Using junit 5, you can improve your testing experience with gradle:
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
Then to run your test, you can use the junit engine using useJUnitPlatform
in your test task:
tasks.test {
useJUnitPlatform()
testLogging {
showStandardStreams = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
events("skipped", "failed")
}
maxParallelForks = 3
}
The maxParallelForks
is to run your tests in parallel, but it can’t be higher than your number of cores. The testLogging
is optional as well to log the tests output in the terminal.