I want to build a Gradle plugin written in Kotlin and publish it to the Gradle Plugin Portal. However, I am not clear about what build config I need to achieve this. There is a lot of confusing information, and strange errors regarding the 'embedded Kotlin' that Gradle uses.
The plugin development guide doesn’t any examples for a Kotlin + build.gradle.kts
(only a simple one that uses java-gradle-plugin
)
There’s some technical details about the embedded Kotlin, but it’s not clear about explicit requirements, and is more abstract technical implementation than a practical “how to” guide.
Using gradle init
(v8.0.2) creates a project that has the Kotlin version manually set, so it might not match the embedded Kotlin version
// generated by `gradle init` command
plugins {
// Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
`java-gradle-plugin`
// Apply the Kotlin JVM plugin to add support for Kotlin.
id("org.jetbrains.kotlin.jvm") version "1.8.10"
}
What config should I use to build a Gradle plugin written in Kotlin?
As I understand it, these are the best-practice rules for configuring a Gradle Project that will build a Gradle Plugin written in Kotlin.
First, note the markers † and ‡
kotlin-dsl
plugin is appliedMUST only use these combinations of plugins:
The Kotlin DSL Plugin, which also applies the java-gradle-plugin
and embedded-kotlin
plugin automatically.
plugins {
`kotlin-dsl`
}
The Gradle Plugin Development Plugin and embedded-kotlin
(which is not documented)
plugins {
`java-gradle-plugin`
`embedded-kotlin`
}
The Gradle Plugin Development Plugin and the Kotlin Gradle Plugin (but note the version restrictions below, and be aware that the Kotlin Gradle Plugin automatically exposes incompatible dependencies (again, see below))
plugins {
`java-gradle-plugin`
// valid, but be aware of exposing incomatible dependencies
kotlin("jvm") version embeddedKotlinVersion
}
MUST NOT use kotlin("jvm")
with embedded-kotlin
OR kotlin-dsl
// ❌ invalid example
plugins {
`java-gradle-plugin`
// don't specify two different Kotlin plugins
`embedded-kotlin`
kotlin("jvm") version "1.8.10"
}
MAY† use any version of kotlin("jvm")
, but SHOULD use the same version as is used by Gradle. There's a helper variable, embeddedKotlinVersion
, that will provide this automatically.
plugins {
`java-gradle-plugin`
kotlin("jvm") version embeddedKotlinVersion
}
‡ MUST set the Kotlin language level appropriately, following the Gradle compatibility matrix
// assume that the current Gradle version is 7.6
plugins {
`java-gradle-plugin`
`embedded-kotlin`
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
apiVersion = "1.4"
languageVersion = "1.4"
}
}
MUST NOT use add kotlin-stdlib-jdk8
or kotlin-reflect
Kotlin libraries, or gradleKotlinDsl()
as runtime/implementation dependencies, as they will conflict with Gradle’s embedded versions, and potentially with other Gradle plugins.
‡ SHOULD† use compileOnly()
dependencies on kotlin-stdlib-jdk8
, kotlin-reflect
, and gradleKotlinDsl()
with a version equal to embeddedKotlinVersion
‡ MUST use compileOnly(gradleApi())
(the version defaults to the version of Gradle being used to build the project) MAY† not match the Gradle versions that you want the plugin to support.
‡ MUST add Kotlin compiler arguments -java-parameters -Xjvm-default=all -Xsam-conversions=class Xjsr305=strict
for compatibility with Config Cache, and improved interoperability with Java and Groovy
SHOULD use Gradle's Plugin Publishing plugin to publish plugins to the Gradle Plugin Portal.
build.gradle.kts
Since most options are configured by the kotlin-dsl
plugin, that provides the simplest method for building a Gradle plugin written in Kotlin.
Create a project using a Gradle version that best matches the Gradle versions you want to support, since the Gradle version being used to build the plugin will provide most defaults.
(While it is possible to create variants of Gradle plugins per Gradle version, this is very complicated and not well supported by the Gradle API)
Create a build.gradle.kts
with the following config:
// build.gradle.kts
plugins {
`kotlin-dsl`
id("com.gradle.plugin-publish") version "$gradlePluginPublishVersion"
}
// Optional: enable stricter validation, to ensure Gradle configuration is correct
tasks.validatePlugins {
enableStricterValidation.set(true)
}
// create the plugin
// Read more: https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html#plugin-development-plugin
gradlePlugin {
plugins {
create("simplePlugin") {
id = "org.example.greeting"
implementationClass = "org.example.GreetingPlugin"
}
}
}