Make a Gradle plugin compatible with Kotlin DSL


(Eyal LEZMY) #1


I’m trying to make our plugin compatible with Kotlin DSL.
Our current plugin is written in Groovy and the code is available on Github. This plugin is supposed to be integrated on Android project to control some emulators during instrumented tests.

The DSL looks like this:

genymotion {
  config {
    verbose = true
  devices {
    nexus5 {
      template "Google Nexus 5 - 4.4.4 - API 19 - 1080x1920"
    anotherNexus5 {
      template "Google Nexus 5 - 5.1.0 - API 22 - 1080x1920"
  • “genymotion” is the first level extension
  • the “config” block is a nested extension
  • the “device” block is a NamedDomainObjectContainer. For now, we use a Closure to handle devices but I implemented a version of the plugin using Action to be more compatible for this test.

I tried to add our plugin to the hello-android sample:

  • I added our plugin on the buildscript dependencies
  • I applied our plugin
  • I patched the project-schema.json file to add our extension

Then on the build.gradle.kts file, I tried to configure our plugin using the “genymotion” extension. I added the same snippet that I pasted at the beginning of this post (I just added parenthesis on the template property).

Then, the build fails with this output :

Unresolved reference: config
Unresolved reference: verbose
Unresolved reference: nexus5
Unresolved reference: template
Unresolved reference: anotherNexus5
Unresolved reference: template

Apparently “genymotion” node is correctly accepted. “devices” is also correctly handled (because it is a method declared on the extension class.
But the nested extension and the NamedDomainObjectContainer are raising errors.

Do you have an idea why this is happening?
Does the nested extensions and NamedDomainObjectContainer are currently supported with this language?

EDIT: I just tried to declare productFlavors on the Android plugin (this is using NamedDomainObjectContainer) and I have the same behaviour. This does not sound good :disappointed:

(Rodrigo B. de Oliveira) #2


I’ve put together a sample that tries to answer the most common questions about how to expose a Kotlin DSL friendly API from Groovy:

Please take a look, your feedback is appreciated.

Tip #3 seems particularly relevant to your case.

Also notice how collections elements must be defined via the string based "elementName" { } syntax in Kotlin instead of the elementName { } syntax as in Groovy.

Dynamic nested extensions are still missing from the sample. Can you point me at the code that adds the nested config extension to the top level extension?

Kind regards,

(Eyal LEZMY) #3

Hi Rodrigo and thanks for the answer.

Your sample is really cool and instructive.

I modified the DSL to have 2 methods a you advise:

  • one for Kotlin, exposing the container instance NamedDomainObjectContainer<LocalVDLaunchDsl> getDevices()
  • and another one, for Groovy, with the “traditional” Closure configuration def devices(Closure closure)

And finally this DSL is working. Great news!

genymotion {
//    config {
//        verbose = true
//    }

    devices {
        "nexus5" {
            template = "Google Nexus 5 - 4.4.4 - API 19 - 1080x1920"

As you see, the “config” nested extension is commented as it is still raising errors.
Here is the line where we create it.