2

I have a Gradle plugin in buildSrc/src/main/kotlin/foo.bar.kts where I am trying to modify tasks, but those modification are failing. If I remove task modification parts, the rest, namely setting up repositories, works just fine.

I think I am missing the syntax how to modify tasks in the module that imports this plugin.

buildSrc/src/main/kotlin/foo.bar.kts:

repositories {
    mavenCentral()
}

tasks.test {
    useJUnitPlatform()
}

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

Using the plugin in my build.gradle.kts

plugins {
  id("foo.bar")
}

The errors that ./gradlew clean build generates

> Task :buildSrc:compileKotlin FAILED
e: /some/path/buildSrc/src/main/kotlin/foo.bar.gradle.kts: (8, 7): Unresolved reference: test
e: /some/path/buildSrc/src/main/kotlin/foo.bar.gradle.kts: (9, 5): Unresolved reference: useJUnitPlatform
e: /some/path/buildSrc/src/main/kotlin/foo.bar.gradle.kts: (12, 16): Unresolved reference: KotlinCompile
e: /some/path/buildSrc/src/main/kotlin/foo.bar.gradle.kts: (12, 33): Type mismatch: inferred type is () -> Unit but Class<TypeVariable(S)!> was expected
e: /some/path/buildSrc/src/main/kotlin/foo.bar.gradle.kts: (13, 5): Unresolved reference: kotlinOptions
e: /some/path/code/buildSrc/src/main/kotlin/foo.bar.gradle.kts: (13, 19): Variable expected

1 Answer 1

2

That's because foo.bar.kts from the buildSrc has to be compiled first, so it must be self-contained. It cannot foresee that it will be applied in other build scripts that will have the Kotlin plugin applied already (and that would actually be brittle).

This means 2 things:

  • at compile time, you cannot access types and functions from the plugin without a dependency on it (most likely declared in buildSrc/build.gradle.kts)
  • at runtime, you cannot assume the presence of tasks and extensions that would only be available when applying some plugin (here, the Kotlin plugin) - you need to make sure it has been applied.

To solve this, you can apply the Kotlin plugin in foo.bar.kts itself, or react to it with things like withPlugin() or plugins.withId():

plugins {
    kotlin("jvm")
}

repositories {
    mavenCentral()
}

tasks.test {
    useJUnitPlatform()
}

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

And to do that, you may need a dependency on the Kotlin plugin in buildSrc/build.gradle.kts:

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21")
}

Sometimes you don't want to forcefully apply the Kotlin plugin when yours is applied (because maybe the consuming projects might want Kotlin JVM or Kotlin Multiplatform, but not both). The is probably not the case for you because when using convention plugins like this, you usually do want to be opinionated on the plugins, but it can still be useful when defining a convention that works both on JVM and multiplatform for instance. So for the sake of completeness let me elaborate on this case.

If you need this laziness and/or conditional configuration, you can register configuration that will only be applied when and if a given plugin is applied using plugins.withId(...). No need for afterEvaluate and the likes. For instance:

plugins.withId("org.jetbrains.kotlin.jvm") {
    tasks.named<Test>("test") {
        useJUnitPlatform()
    }
    tasks.withType<KotlinCompile>() {
        kotlinOptions.jvmTarget = "11"
    }
}

plugins.withId("org.jetbrains.kotlin.multiplatform") {
    tasks.withType<Test>().configureEach {
        useJUnitPlatform()
    }
    tasks.withType<KotlinCompileCommon>() {
        // ..
    }
}

Note that you will still need your buildSrc/build.gradle.kts to declare the dependency on the plugins if you need to use classes from them.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.