I’m getting started with plugins and I struggle a bit to understand how a plugin can apply another plugin. I would like to create a KotlinApplicationPlugin which applies both the Kotlin plugin and the application plugin. Roughly, I’d like my build.gradle file to look like this:
For the application side of things, my plugin simply calls project.apply(plugin = "org.gradle.application") in my plugin (in buildSrc/src/main/kotlin/com/github/jdemeulenaere/plugins/KotlinApplication.kt). Unfortunately if I do that the build fails with:
$ ./gradlew :application:run
> Configure project :application
e: application/build.gradle.kts:3:1: Expression 'application' cannot be invoked as a function. The function 'invoke()' is not found
e: application/build.gradle.kts:3:1: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val PluginDependenciesSpec.application: PluginDependencySpec defined in org.gradle.kotlin.dsl
e: application/build.gradle.kts:4:5: Unresolved reference: mainClass
It looks like the application {} configuration is not recognized even though my KotlinApplication is applied to the project. Is it because the file is still executing the top-level functions like application {} before the "org.gradle.application" plugin is actually applied by my plugin? What is the typical way to apply a plugin in another plugin and let the build script still configure it and/or have my plugin also configure it? I think I can make it work by creating my own extension that captures an Action<JavaApplication> then apply that project.extensions.findByType<JavaApplication>() but I’m not sure that this is how I’m supposed to do it?
Your problem simply is, that you apply your plugin the legacy way. The necessary type-safe accessors for a Kotlin DSL are generated for plugins applied using the plugins { ... } block. So apply your plugin using the plugins block instead of the legacy way and it will work as you want.
Unfortunately IIUC there is no way to apply a plugin with plugins {} and using the class name, and therefore I can’t apply a plugin that is in buildSrc/src right? Having my plugin in buildSrc/ is important for me because those plugins will be used in a monorepo and I want to be able to make a change to a plugin that will directly be applied to all my projects, without having to publish an intermediate jar in-between.
IIUC there is no way to apply a plugin with plugins {} and using the class name
That’s correct, you always apply using the ID in the plugins { ... } block.
and therefore I can’t apply a plugin that is in buildSrc/src right?
That’s not correct in any way.
Why should this be the case? o_O
Just apply the Gradle Plugin Development Plugin and define your plugin in your build script or create the plugin meta-inf file manually if you prefer and then apply it via ID as usual.
It works indeed! I had tried it yesterday and it broke but that was probably because of some other error I made somewhere else. Thanks a lot, I’m pretty happy with the result so far, it makes the configuration of my build files much less verbose