Extending plugin by another plugin or extension

I’m wondering whether it is possible to extend a plugin in a plug and play kind of way. What I try to archieve is something like this.

I have a exisiting plugin, for example k4s by which I can deploy servles functions.

k4s {
  ....
}

I would like to ‘extend’ the plugin by including a (plugin) dependency. So something like this:

dependencies {
   dependendy(id=...mail)
}

k4s {
   mail {
   }
}

The mail part is added because i have added the dependency

You cannot really do this by adding a dependency, because when dependencies are (or should be) resolved, the build script is already evaluated.

But building a dynamic DSL by plugins is possible, yes.
So for example if you apply plugin k4s it adds the k4s extensions and if you apply the k4s-mail plugin, then this adds the mail extension to the k4s extension.
Any object created through Gradle is automatically implementing ExtensionAware, so you should always let Gradle create things.
And then you can cast to ExtensionAware or also declare your extensions to be ExtensionAware right away.

I was trying to find an example of a plugin in which this was done. Do you know any?

Not a public one from the top of my head, but it is trivial. Like you and the k4s extension to the project, you add the mail extension to the k4s extension, that’s it.

I’m quite new to writing gradle plugins so I assumed it was something as follows what you meant:

class MailPlugin: Plugin<Project> {
    /**
     * Apply this plugin to the given target object.
     *
     * @param target The target object
     */
    override fun apply(target: Project) {
        val mailExtension = target.extensions.create("mail", MailExtension::class.java)
        
        target.plugins.withType(K4sPlugin::class.java) {
           ????
        }
    }
}

Problem is that I can’t find how to add the mailExtension to the K4s Plugin

No, you create the extension on target which is the Project.
Instead at the ???? you get the k4s extension and on that create the extension.

Btw. have a look at the JavaDoc of .plugins to learn that you should not use it.
Instead target.pluginManager.withPlugin("...") { ... } is the way to go.

Not sure whether I understand you. Could you provide an example?

Not right now, I’m on mobile. What do you have problem with?

I believe it should be done as follows but not sure whether it is correct:

  override fun apply(target: Project) {
    val k4sExtension = target.extensions.getByName("extensions")
    with(k4sExtension as ExtensionAware) { extensions.create("mail", MailExtension::class.java) }
  }
}

I was also wondering whether you could traverse the (already) registered extensions (something like project.extensension.forEach(....))

That looks fine from a cursory look except for two things.

  1. You try to add the mail extension to an extension called extensions instead of the extension called k4s
  2. You should not assume the extension is there, that you require that whatever adds that other extension is applied before your plugin and that is bad practice. If you plugin can’t with without that other plugin, apply that other plugin from your plugin, if your plugin just cooperates with that other plugin in case it is applied, use pluginManager.withPlugin.