Introduction
So here a bit of details:
- Gradle is an open source build automation system.
- Kotlin is a general purpose, open source, statically typed programming language for both functional and object-oriented programming.
- A DSL (domain-specific language) is a language specialized to a particular application domain.
For example
Groovy
that was created for Gradle’s build scripts.
Kotlin dsl with gradle means to use the kotlin build.gradle.kts
instead of the groovy build.gradle
.
Kotlin is so general that it reaches specific programming niche.
Everything is hosted on GitHub: sylhare/kotlin
Basic set up
Basic set up for your kotlin project with Gradle > 4.8 (2018), may not apply to latest gradle releases:
- group: the top level package(s) under
src.main
- version: the version of your application
allprojects {
group = "hello"
version = "1.0"
repositories {
jcenter()
}
}
You want to specify the kotlin version and plugin you wish to use:
plugins {
kotlin("jvm") version "1.3.21"
// instead of id("org.jetbrains.kotlin.jvm") version "1.3.21"
}
You don’t need to apply the plugin just define it, and you’re good to go. Add the basic repositories for your dependencies:
repositories {
mavenCentral()
maven(url = "https://plugins.gradle.org/m2/")
}
Add dependencies like kotlin:
dependencies {
compile(kotlin("stdlib-jdk8"))
// Or compile("org.jetbrains.kotlin:kotlin-stdlib:1.3.21")
}
The kotlin
key word replaces org.jetbrains.kotlin you can also use it for plugins this way.
For higher version of gradle, compile has been deprecated to implementation
You can also add this for source compatibility:
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
Code Coverage
JUnit
To look at coverage that means you have unit test. Don’t forget to add something like JUnit into your dependencies:
dependencies {
testCompile("junit:junit:4.12")
}
Also you want to use the junit platform to run your tests with google using:
tasks.test {
useJUnitPlatform()
}
Which will use the junit-vintage-engine
incompatible with the newer Junit5 version
(you can recognize them by the jupiter in the package name), you may encounter the No tests found
issue
if you mix them up.
If you want to use org.junit.jupiter:junit-jupiter:5.7.2 with its junit-jupiter-api and junit-jupiter-engine, you might need to exclude junit4 modules like in springboot:
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "junit")
exclude(module = "junit-vintage-engine")
}
With that the useJunitPlatform()
will use the junit5 one.
Jacoco
Create code coverage task
Code coverage with jacoco plugin
plugins {
jacoco
}
Then add the task
tasks.withType<JacocoReport> {
reports {
xml.isEnabled = true
csv.isEnabled = false
html.destination = file("${buildDir}/reports/jacoco")
}
}
You can now roll the test code coverage with jacoco using gradle test jacocoTestReport
.
Ignore a class from coverage
If you have a main
class which can’t be tested and you’d rather remove it from coverage, you would do it like:
tasks.withType<JacocoReport> {
doFirst {
classDirectories = fileTree("build/classes/kotlin/main").apply {
exclude("**/MainKt.class")
}
}
// ... your other stuff
}
And MainKt
is not considered for the coverage anymore!
Execute the project
With the Application gradle plugin
It is a plugin available with gradle, add it to your gradle script like:
plugins {
application
}
Then set your application main file:
- It has to be outside a class
- The
Kt
at the end is normal, Kotlin automatically generates it for backward compatibility with Java classes
application {
mainClassName = "hello.MainKt"
}
// Or you can use
application.mainClassName = "hello.MainKt"
Now you can run your program with:
gradle run
Make the fat Jar
So the basic Jar file generated doesnt include all you need to run. You need to include them manually by adding this (gradle 5+):
tasks.withType<Jar> {
// Otherwise you'll get a "No main manifest attribute" error
manifest {
attributes["Main-Class"] = "com.example.MainKt"
}
// To add all of the dependencies otherwise a "NoClassDefFoundError" error
from(sourceSets.main.get().output)
dependsOn(configurations.runtimeClasspath)
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
})
}
The jar will be created as {project.name}-{version}.jar
like hello-kotlin-1.0.jar
.
You can then run it using:
java -jar hello-kotlin-1.0.jar
You can also create another task fatJar
that would create the jar with all of your dependencies.
Follow the documentation on gradle.
Make the wrapper
For your project to work almost anywhere, you can use the wrapper:
# To use the installed gradle version as wrapper
gradle wrapper
# To specify the gradle version
gradle wrapper --gradle-version 4.8 --distribution-type all
Then you’ll be able to use ./gradlew
instead of gradle, and your project should run fine 👍
Now if you have the opportunity to use a newer version of gradle, do it.