kotlingradlegradle-plugingradle-kotlin-dslkotlin-gradle-plugin

How can I apply a plugin to itself using Kotlin DSL?


We have an existing plugin project which configures various things (including static analysis), where we want to apply the plugin to the project itself.

The way this currently works for plugins written in Java is, you add the Java src dir to the buildSrc project, and then classes built there can be used in the main project. So I'm trying to get the same thing working for plugins written as Kotlin scripts.

But when I try to build it, compiling buildSrc fails with:

e: C:\Users\Trejkaz\Documents\test\self-applying-gradle-plugin\src\main\kotlin\example.common.gradle.kts: (1, 1): Unresolved reference: allprojects

> Task :buildSrc:compileKotlin FAILED

What's missing in order to make this work?

Further investigation:

I pushed a repo to play with this here but what follows is the contents of the build scripts in case it's ever deleted.

The main build.gradle.kts:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    `java-gradle-plugin`
    `kotlin-dsl`

    // Matching version in Gradle
    kotlin("jvm") version "1.5.31"
}

apply(from = "common-build.gradle.kts")

apply(plugin = "example.common") // 👈 trying to apply the compiled plugin here

group = "org.example"
version = "1.0-SNAPSHOT"

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "11"
}

In buildSrc/build.gradle.kts, we have this - note that it adds a source dir for the sources in the main directory:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    `java-gradle-plugin`
    `kotlin-dsl`

    // Matching version in Gradle
    kotlin("jvm") version "1.5.31"
}

apply(from = "../common-build.gradle.kts")

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "11"
}

kotlin {
    sourceSets["main"].kotlin.srcDir("../src/main/kotlin")
}

common-build.gradle.kts has everything common to both build scripts which we've figured out how to move to a common location (notably, the KotlinCompile isn't there, later I'll figure out why I can't move that as well):

repositories {
    mavenCentral()
}

dependencies {
    // Needed to compile Kotlin stuff but not added by the plugin for some reason
    "implementation"("org.jetbrains.kotlin:kotlin-scripting-jvm")
}

The plugin script, src/main/kotlin/example.common.gradle.kts, contains:

allprojects {
    // Configure something
}

Solution

  • This turns out to be a bug in Gradle's kotlin-dsl plugin.

    The workaround is to add the source dirs before applying the plugin.

    import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
    
    plugins {
        `java-gradle-plugin`
        `kotlin-dsl` apply false
    
        // Matching version in Gradle
        kotlin("jvm") version "1.5.31"
    }
    
    apply(from = "../common-build.gradle.kts")
    
    tasks.withType<KotlinCompile> {
        kotlinOptions.jvmTarget = "11"
    }
    
    kotlin {
        sourceSets["main"].kotlin.srcDir("../src/main/kotlin")
    }
    
    // Workaround for https://github.com/gradle/gradle/issues/21052 -
    // apply kotlin-dsl plugin last, because it erroneously fetches source dirs eagerly.
    apply(plugin = "org.gradle.kotlin.kotlin-dsl")