Please advise on kotlin dsl based multiproject setup

Hello,

Could anybody advise on how to set up a multiproject kotlin dsl based project where all common functionality is extracted to a single place? Currently I have a single project which configured kotlin, junit dependencies, and maven central publishing rules. I need to add one more module, so, want to extract the common setup into a single place and re-use it from all modules. Tried two approaches below, but they didn’t work. Appreciate if someone points me on how that is done in gradle.

Approach 1 - subprojects

root build.gradle.kts

plugins {
    kotlin("jvm") version "1.6.10" apply false
    // other plugins
}

allprojects {
    apply(plugin = "java-library")
    apply(plugin = "org.jetbrains.kotlin.jvm")

    group = "tech.harmonysoft"
    version = Version.APP

    repositories {
        mavenCentral()
    }

    dependencies {
        testImplementation("org.assertj:assertj-core:3.22.0")
        testImplementation("org.junit.jupiter:junit-jupiter:${Version.JUNIT}")
        testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Version.JUNIT}")
    }
}

getting this error:

Script compilation errors:

  Line 23:         testImplementation("org.assertj:assertj-core:3.22.0")
                   ^ Unresolved reference: testImplementation

  Line 24:         testImplementation("org.junit.jupiter:junit-jupiter:${Version.JUNIT}")
                   ^ Unresolved reference: testImplementation

  Line 25:         testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Version.JUNIT}")
                   ^ Unresolved reference: testRuntimeOnly

Approach 2 - buildSrc

root build.gradle.kts

plugins {
    kotlin("jvm") version "1.6.10" apply false
}

buildSrc/build.gradle.kts

plugins {
    `kotlin-dsl`
}

repositories {
    mavenCentral()
}

buildSrc/src/main/kotlin/library-conventions.gradle.kts

plugins {
    kotlin("jvm")
    id("java-library")
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation("org.assertj:assertj-core:3.22.0")
    testImplementation("org.junit.jupiter:junit-jupiter:${Version.JUNIT}")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Version.JUNIT}")
}

common/build.gradle.kts

plugins {
    id("library-conventions")
}

Error:

org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'org.jetbrains.kotlin.jvm'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (plugin dependency must include a version number for this source)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.resolveToFoundResult(DefaultPluginRequestApplicator.java:221)
        ... 160 more

Approach 1 is bad and like that also only works nicely in Groovy DSL as you don’t get the type-safe accessors for Kotlin DSL generated. You only get them for plugins you apply using the plugins DSL, not the legacy apply(...) way. Besides that, almost any instance of allprojects or subprojects is bad, as it introduces coupling between the projects which for example works against advanced optimizations like configure on demand or configuration cache.

Approach 2, using convention plugins, is the way to go and you are almost there.
Just remove those three lines from the root build script that make no sense and add the missing dependency on the kotlin pluing in your buildSrc/build.gradle.kts file, then it should work.

Great, Thanks!

Looks like a way to go