Gradle7 Version Catalog: How to use it with buildSrc?

With Gradle 7.3.3, it is possible. Note version catalogs are GA since Gradle 7.4

The code snippet assumes Gradle is at least 7.4, but if you need them prior that version, insert enableFeaturePreview("VERSION_CATALOGS") at the beginning of each settings.gradle.kts.

Using buildSrc

buildSrc/settings.gradle.kts

dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

buildSrc/build.gradle.kts

dependencies {
    implementation(libs.gradleplugin.intellij) // <- the lib reference
}

You can even use the version catalog for plugins

gradle/libs.versions.toml

...

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
jetbrains-changelog = { id = "org.jetbrains.changelog", version.ref = "changelog-plugin" }
jetbrains-intellij = { id = "org.jetbrains.intellij", version.ref = "intellij-plugin" }
hierynomus-license = { id = "com.github.hierynomus.license", version.ref = "license-plugin" }
nebula-integtest = { id = "nebula.integtest", version.ref = "nebula-integtest-plugin" }

build.gradle.kts

plugins {
    id("java")
    alias(libs.plugins.kotlin.jvm)
    alias(libs.plugins.nebula.integtest)
    alias(libs.plugins.jetbrains.intellij)
    alias(libs.plugins.jetbrains.changelog)
    alias(libs.plugins.hierynomus.license)
}

Note for accessing the catalog within scripts, please refer to the below section, the trick is the same.

Using convention plugins and included build

In the main project include a the Gradle project that holds the convention plugins.

build.gradle.kts

includeBuild("convention-plugins") // here it's a subfolder

convention-plugins/settings.gradle.kts

dependencyResolutionManagement {
    repositories {
        gradlePluginPortal()
    }
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

rootProject.name = "convention-plugins"

The trick to enable convention plugins to access the version catalog is split in two part, add an ugly implementation dependency that locate where the version catalog generated classes are located.

libs.javaClass.superclass.protectionDomain.codeSource.location

Then in the convention plugin refer to the libs extension via Project::the.

val libs = the<LibrariesForLibs>()

This is tracked by gradle/gradle#15383.

convention-plugins/build.gradle.kts

plugins {
    `kotlin-dsl`
}

dependencies {
    implementation(libs.gradleplugin.kotlin.jvm)

    // https://github.com/gradle/gradle/issues/15383
    implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
}

And in the actual convention plugin

import org.gradle.accessors.dm.LibrariesForLibs

plugins {
    id("org.jetbrains.kotlin.jvm")
}

// https://github.com/gradle/gradle/issues/15383
val libs = the<LibrariesForLibs>()

dependencies {
    detektPlugins(libs.bundles.kotlinStuff) // access catalog entries
}

The org.gradle.accessors.dm.LibrariesForLibs class is generated by gradle is somewhere in local gradle folder ./gradle/<version>/dependency-accessors/<hash>/classes


Quick note that older IntelliJ IDEA currently (2022.3) reports alias(libs.gradleplugin.thePlugin) as an error in the editor,
although the dependencies are correctly resolved.
This tracked by KTIJ-19369, the ticket indicates this is actually a bug in Gradle Kotlin DSL gradle/gradle#22797, and someone made a simple IntelliJ IDEA plugin to hide this error until resolved.

Leave a Comment