Kotlin - Gradle

Gradle is a build automation tool for software development

Introduction

Gradle is a build automation tool used primarily for Java, Kotlin, and other JVM-based projects. It helps automate tasks such as compiling code, managing dependencies, running tests, and packaging applications.

Create a new Kotlin project using Gradle and Kotlin Gradle DSL:

You can see that different files have been created:

Gradle Wrapper

When creating the project, the gradle folder has been created:

Terminal window
ls .\gradle\wrapper\
Directory: C:\Users\david\gradle\gradle\wrapper
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/10/2024 8:40 43583 gradle-wrapper.jar
-a---- 4/10/2024 8:40 253 gradle-wrapper.properties

This folder contains the JAR file and the configuration of the Gradle Wrapper.

This application is executed with the file gradlew.bat (for Windows) or gradlew (for macOS and Linux).

The “Gradle Wrapper” uses a specific version of Gradle, and if this version is not on the computer, it downloads it directly from the Internet.

This way any user working with the project will use the same version of Gradle, even if they don’t have Gradle installed on their computer.

Project

The general project configuration is in the settings.gradle.kts file.

If you look at the file’s content, you can see that the project name is “gradle” and it includes the “app” subproject:

settings.gradle.kts
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
rootProject.name = "gradle"

The src folder contains your project code.

The build.gradle.kts file that contains the project configuration:

build.gradle.kts
plugins {
kotlin("jvm") version "2.2.21"
}
group = "dev.xtec"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
}
kotlin {
jvmToolchain(23)
}
tasks.test {
useJUnitPlatform()
}
Note

A project can consist of more than one subproject, and each one has its own particular configuration build.gradle.kts

Build

Execute this command to run the build task:

Terminal window
.\gradlew build
BUILD SUCCESSFUL in 4s
7 actionable tasks: 7 executed
Note

Powershell executes the gradlew.bat script even if you don’t put .bat at the end.

The first time you execute the “wrapper”, the “wrapper” downloads and caches the Gradle binaries if they are not installed on the computer.

The build task uses the source code and its dependencies to build the application.

If you execute the ls command you can see that two new folders have been created: .gradle and .kotlin.

Terminal window
> ls
Directory: C:\Users\david\gradle
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 4/10/2024 8:54 .gradle
d----- 4/10/2024 8:54 .kotlin
d----- 4/10/2024 8:54 app
d----- 4/10/2024 8:51 gradle
-a---- 4/10/2024 8:51 290 .gitattributes
-a---- 4/10/2024 8:51 108 .gitignore
-a---- 4/10/2024 8:51 8762 gradlew
-a---- 4/10/2024 8:51 2966 gradlew.bat
-a---- 4/10/2024 8:51 535 settings.gradle.kts

In the .gradle folder you have a local installation of Gradle that the project uses through the gradlew script.

In addition, the build task has also generated the build folder:

Terminal window
> ls .\build\
Directory: C:\Users\david\gradle\build
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 4/10/2024 8:23 classes
d----- 4/10/2024 8:23 distributions
d----- 4/10/2024 8:23 kotlin
d----- 4/10/2024 8:23 libs
d----- 4/10/2024 8:23 reports
d----- 4/10/2024 8:23 scripts
d----- 4/10/2024 8:23 test-results
d----- 4/10/2024 8:23 tmp

Everything generated from the code you have written is saved in this folder.

Run

Modify the build.gradle.kts file:

Apply the application plugin to add support for building a CLI application in Java.

plugins {
// ...
application
}

Configure the main class:

application {
mainClass = "gradle.AppKt"
}

This class is at the path src/main/kotlin/gradle/App.kt

With the run task you can run the application:

Terminal window
> .\gradlew run
Hello World!
BUILD SUCCESSFUL in 2s
2 actionable tasks: 1 executed, 1 up-to-date

Open the App.kt file with Windows “Notepad” and modify the file’s content:

package gradle
fun main() {
println("Hello World!")
}

Run the application again:

Terminal window
gradle run
Hello World!
BUILD SUCCESSFUL in 1s

Test

Next, we are going to create a test.

Modify the AppTest.kt file that is in the folder src/test/kotlin/gradle/AppTest.kt.

Create a test that doesn’t work:

package gradle
import kotlin.test.*
class AppTest {
@Test fun myTest() {
assertEquals(3, 5)
}
}

With the test task, verify that it doesn’t work:

Terminal window
gradle test
AppTest > myTest() FAILED
org.opentest4j.AssertionFailedError at AppTest.kt:8
1 test completed, 1 failed
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:test'.
> There were failing tests. See the report at: file:///C:/Users/david/gradle/app/build/reports/tests/test/index.html
* Try:
> Run with --scan to get full insights.
BUILD FAILED in 1s
3 actionable tasks: 1 executed, 2 up-to-date

The result is that at AppTest.kt:8 … 😮, 3 is not equal to 5 😇

Open the URL file:///... in the browser and you have a nicer “report”.

Modify the assertEquals so the test works:

Verify that it works:

Terminal window
gradle test
BUILD SUCCESSFUL in 1s
3 actionable tasks: 2 executed, 1 up-to-date

Dependencies

A project needs many functionalities that are not in the standard libraries.

For example, if you want to create graphs, you can use the Kandy library.

In the build.gradle.kts file of the “app” subproject you can declare dependencies.

Modify the dependencies entry and add a dependency with “Kandy”:

dependencies {
// ...
implementation("org.jetbrains.kotlinx:kandy-lets-plot:0.7.0")
}

Modify the App.kt file to create a bar chart:

package gradle
import org.jetbrains.kotlinx.dataframe.api.*
import org.jetbrains.kotlinx.kandy.dsl.*
import org.jetbrains.kotlinx.kandy.letsplot.export.save
import org.jetbrains.kotlinx.kandy.letsplot.layers.bars
fun main() {
val averageTemperature = dataFrameOf(
"city" to listOf("New York", "London", "Berlin", "Yerevan", "Tokyo"),
"average temperature" to listOf(12.5, 11.0, 9.6, 11.5, 16.0)
)
averageTemperature.plot {
bars {
x("city")
y("average temperature") {
axis.name = "Average Temperature (°C)"
}
}
}.save("plot.png", path = ".")
}

Run the application:

Terminal window
.\gradlew run
BUILD SUCCESSFUL in 3s
2 actionable tasks: 1 executed, 1 up-to-date

Open the plot.png file that has just been created.

Plugins

Gradle is structured around “plugins” that add functionality.

For example, if you want to create a distribution of your project, you have to add the application plugin.

Since at the beginning you said the project is of type kotlin-application, the plugin has already been declared in the plugins section of the build.gradle.kts file of the “app” subproject:

If you execute the distZip task to create a distribution of your project:

Terminal window
gradle distZip
BUILD SUCCESSFUL in 2s
4 actionable tasks: 3 executed, 1 up-to-date

The file is in the path build/distributions/:

Terminal window
ls .\build\distributions\
Directory: C:\Users\david\gradle\build\distributions
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 09/10/2024 17:08 4551293 app.zip

Unzip the file in the dist folder:

Terminal window
Expand-Archive -Path .\build\distributions\app.zip dist

You can now run the application directly:

Terminal window
> .\dist\app\bin\app
...

And, if you remove the application plugin from the build.gradle.kts file, the distZip task will disappear:

Terminal window
gradle distZip
Configure project : gradle
e: file:///C:/Users/ddemingo/gradle/build.gradle.kts:41:1: Expression 'application' cannot be invoked as a function. The function 'invoke()' is not found
...

Wrapper

https://docs.gradle.org/current/userguide/gradle_wrapper.html

The following command upgrades the Wrapper to the latest version:

Terminal window
./gradlew wrapper --gradle-version latest

The following command upgrades the Wrapper to a specific version:

Terminal window
./gradlew wrapper --gradle-version 8.11
BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed

Once you have upgraded the wrapper, you can check that it’s the version you expected by executing ./gradlew --version.

Remember to run the wrapper task again to download the Gradle distribution binaries (if needed) and update the gradlew and gradlew.bat files.

Pending