gradle scripts for Kotlin lovers

Sry for that artwork 😅

Quite some time ago gradle announced gradle-script-kotlin (now just Kotlin DSL). At this time my filter bubble freaked out. Because hey, Kotlin is the new silver bullet and to be honest no one has ever understood groovy, right?

But then there was silence. No one has ever tried or even used Kotlin DSL (or it feels like that). Not a single blog post appears how to use it (or what for great benefit it gives).

Whatever. Since Hans Docktor announced — more or less — that Kotlin DSL will be the de facto gradle default in the first quarter 2018 at the KotlinConf I wanted to take a deeper look at it and how to use it. Because I ran into some basic problems I wanted to share my experience in this post.


Before I dive into the code some goods things first:

  • Kotlin DSL is directly bundled in gradle. You don’t need an extra buildscript or something to use it.
  • It is possible to use the same configuration code in Kotlin DSL as in groovy. But not always. I will explain that later.
  • You can mix groovy scripts with Kotlin DSL (e.g. having a Kotlin gradle file but the settings.gradle in groovy).

How to use it

First thing to know is that the gradle files don’t call build.gradle anymore but build.gradle.kts.

Fun fact: 
The .kts extension comes from Kotlin directly and it aims to be a “scripting language”.

Vóila that’s basically all… 😃
You are now able to write your build-scripts in Kotlin 🎉

If you aren’t end up like me :

Everything is red… How do I apply and configure that plugin 🤔

The configuration of applied plugins is a little bit different than in a typical groovy build.gradle file.
First of all — to solve the apply plugin issue — you have to use the apply{} method to apply some plugins. In this closure you can use the plugin(String) method to apply plugins by its name:

apply {
plugin("com.pascalwelsch.gitversioner")
}

The tricky part is now to find out how the extensions class is named. If you haven’t developed a gradle plugin by yourself yet, an extension class is a simple class which is used to “setup” some properties for that plugin. In this example the extension name is called gitVersioner but that doesn’t mean that the “setup class” is called GitVersionerExtension.

Understood? Good! But why do we need that class?
In Kotlin DSL you have to use (with an exception, I’ll explain it later) the configure<ExtensionClass>{} method to setup your applied plugin. Otherwise the configuration method doesnt know which class/extension it has to setup.

Hopefully the plugin you applied is well documented or even better open source. Otherwise it is nearly impossible to find that class. 
Luckily passsys gitversioner can be found here at GitHub. And with a little bit of research you’ll find in the GitVersionerPlugin class something like that:

rootProject.extensions.create(“gitVersioner”, GitVersioner::class.java, gitVersionExtractor, project.logger)

In a nutshell it says: create a new extension with the extension name gitVersioner and the extension class GitVersioner.class with the given arguments (if you are curious about how that works take a look into this gradle doc).

Phew. Now we know that GitVersioner is for our configure method. But configure<GitVersioner>{} doesn’t work:

Unresolved reference? Do we need a import here? 🤔

To fix that issue we can either import the class or use the fully qualified class name as generic:

// Use as import 
import com.pascalwelsch.gitversioner.GitVersioner
configure
<GitVersioner> {
baseBranch = "develop"
}
// Or use with fully qualified class name
configure
<com.pascalwelsch.gitversioner.GitVersioner> {
baseBranch = "develop"
}
Don`t want the new config? “No problem… “

You want your always loved and known config back? No problem. You can.

If you use a plugin which is published to the gradle plugin portal then everything is setup on the fly. You can just use the old configuration style.

You can “detect” if a plugin is published there (and not at jcenter() or mavenCentral() or somewhere else) if you can apply the plugin with the plugins{} method:

plugins {
id("org.shipkit.java") version "1.0.0"
}

If it’s not published there (like the Android Gradle Plugin) you can make some changes in the settings.gradle (or settings.gradle.kts).

I’ll focus here on the settings.gradle.kts. Meaning the Kotlin DSL version. But it is similar to the groovy version. But note that you have to use at least gradle 4.4 to use settings.gradke.kts. Prior versions don’t support a Kotlin DSL version of the gradle settings file.

Configuration of the settings.gradle.kts

gradle gives us a handy class to change the plugins{} “behaviour”: PluginManagment. We can change the plugins{} behaviour so that it doesn’t look up only at the gradles plugin portal but also at jcenter() (or other locations of course):

I don’t want to go into detail. But what it does is something like: looking up at gradlePluginPortal() and jcenter() (to find gradle plugins) and check each applied plugin if its id is equal to gitVersioner and if yes take a look at one of the repositories for the given artifact name and download it.

Easy, no? 😅

After this setup we can change the previous implementation of applying the gitVersioner from:

apply {
plugin("com.pascalwelsch.gitversioner")
}

to:

plugins {
id("com.pascalwelsch.gitversioner") version "0.3.1"
}

Finally we can use the old configuration style: 🎉

gitVersioner {
baseBranch = "develop"
}

Lesson learned

I love the Kotlin DSL. Seriously! My new favourite programming language inside my favorite build tool. Can it be better? Yes! My favorite IDE should support it better 😊.

Currently — at time of writing — I use Android Studio 3.0. And even if everything build the code is just red:

The support of Kotlin DSL in Android Studio (and/or IntelliJ) is subpar.

Kotlin DSL recommend to use at least IntelliJ 2017.1.3. I don’t know which version AS 3.0 uses underlined but AS 3.1 (Canary 6+) will use 2017.3. So I expect some improvements here with the release of AS 3.1.

Beside of that Kotlin DSL hit just release 0.14.0 and it feels like that. It is not really stable and not everything works perfectly. But that was expected since it hasn’t reached a stable 1.0 yet.

Personally I’m very excited to see the process here and can’t wait to use it in production. With a stable Kotlin DSL and a great support in Android Studio!