Search code examples
kotlingradlegradle-pluginkotlin-gradle-plugin

Nested configuration for Gradle plugin with Kotlin


I have a working Gradle plugin with an extension implemented using Kotlin. And I want to improve it by adding "nested" configuration. How should I extend my extension class for this?

This is how I configure my plugin in the build.gradle.kts file in the project which uses the plugin.

myName {
    nexusServer.set("https://some-url")
    nexusUser.set("some-user")
    nexusPass.set("some-password-taken-from-env-variable-provider")
    nexusRepository.set("some repository")
}

Instead of this I want to have the following "nested" configuration.

myName {
    nexus {
        server.set("https://some-url")
        user.set("some-user")
        pass.set("some-password-taken-from-env-variable-provider")
        repository.set("some repository")
    }
}

For this I want to do something like explained in the following document Developing Custom Gradle Types. However, the examples are in Java and for the task but not the plugin extension. I do not know how to convert it to Kotlin and plugin extension.

Here is what I already have and want to update.

The extension class.

import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property

abstract class MyPluginExtension {
    abstract val nexusServer: Property<String>

    abstract val nexusUser: Property<String>

    abstract val nexusPass: Property<String>

    abstract val nexusRepository: Property<String>
}

The plugin class.

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.register

class MyPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        val extension = target.extensions.create("myName", MyPluginExtension::class.java)

        with(target.tasks) {
            register<MyTask>("taskName") {
                group = "myGroup"
                description = "Do something"

                nexusServer.set(extension.nexusServer)
                nexusUser.set(extension.nexusUser)
                nexusPass.set(extension.nexusPass)
                nexusRepository.set(extension.nexusRepository)
            }
        }
    }
}


Solution

  • To define a nested configuration inside an extension we add property and method to the extension.

    First, we define property with the Nested attribute.

        @get:Nested
        abstract val appCenter: AppCenter
    

    Second, we define a method with the same name as the property.

        fun appCenter(action: Action<AppCenter>) = action.execute(appCenter)
    

    Here is the complete example.

    import org.gradle.api.Action
    import org.gradle.api.provider.Property
    import org.gradle.api.tasks.Nested
    
    abstract class MyExtension {
        @get:Nested
        abstract val appCenter: AppCenter
    
        fun appCenter(action: Action<AppCenter>) = action.execute(appCenter)
    
        abstract class AppCenter {
            abstract val token: Property<String>
    
            abstract val owner: Property<String>
        }
    }
    

    Here is the usage of the configuration.

    extName {
        appCenter {
            token = providers.environmentVariable("VAR1")
            owner = providers.environmentVariable("VAR2")
        }
    }