Gradle 7.2 Custom Plugin: How to consume a version catalog within the apply(project: Project)?
Asked Answered
A

5

6

I have a Gradle 7.2 custom plugin that is working properly. I want to configure it to use the new Gradle Version Catalog for dependency information. I know how to configure and use the version catalog, and have generated a shared jar for our shared dependencies. It is being read by a few other builds without any issues.

However, I cannot seem to find the correct incantation to consume the version catalog jar by the plugin when it is setting dependencies. I keep getting "Extension of type 'VersionCatalogsExtension' does not exist".

Here are two snippets showing what I have done to access the version catalog in the apply method:

    override fun apply(project: Project) {
        val libs = project
           .extensions
           .getByType(VersionCatalogsExtension::class.java)
           .named("libs")
        
        addBuildDependencies(libs)
            .
            .
            .
private fun Project.addBuildDependencies(libs: VersionCatalog) {
    dependencies.apply {
        // BOMs
        add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, platform(libs.findDependency("arrow.bom").get()))
        add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, platform(libs.findDependency("detekt.bom").get()))

I'd appreciate any snippets or redirects.

Thanks, Mike

Alesha answered 4/9, 2021 at 7:26 Comment(0)
W
0

How are you applying the plugin?

I noticed that if you're trying to do it from an allProjects or subprojects block it doesn't work, it fails with this error:

Extension of type 'VersionCatalogsExtension' does not exist. Currently registered extension types: ...

I assume this the same reason why we can't use libs directly inside those blocks, see this comment for more details.

A solution is to reference the custom plugin directly in the projects that will use it and avoid cross-configuration.

Wb answered 5/2, 2022 at 14:23 Comment(0)
H
0

One of possible reasons for this "Extension of type VersionCatalogsExtension does not exist" is that the target project the plugin is being applied to doesn't have the required version catalog declaration in its settings.gradle file. Even if you have the needed version catalog correctly configured in your environment, it doesn't mean the same catalog is going to be present in the environment where the plugin is actually applied.

In other words, no version catalogs are going to be included inside the distributed plugin, even if they were declared in settings.gradle during development. These version catalogs are bound to a particular Gradle buildscript project environment.

There are at least 3 possible solutions:

  1. Distribute your version catalog separately and request the users of plugin to link it (by the versionCatalogs { ... } section) in their settings.gradle configurations.
  2. Originally suggested here:

You can have a settings plugin that defines the version catalog and tell your consumers to apply that settings plugin to get the according version catalog.

  1. Generate the code (wrappers) for required version catalogs and include it into components (Gradle plugins) which are going to add dependencies from these catalogs to target projects. I wrote a project (Gradle plugin) doing exactly this here. It is not published to any public Gradle plugin portal, but can be used by including this project directly (by copying the code or using Gradle composite builds). This is an example of usage, inside build.gradle.kts:
plugins {
    id("org.jetbrains.kotlin.jvm")
    id("io.github.andrew-k-21-12.version-catalogs-generator")
    `java-gradle-plugin`
}

// Generating Kotlin sources for required version catalogs.
versionCatalogsGenerator {
    packageName.set("com.somepackage.versions")
    catalogs {
        register("KotlinVersionCatalog") {
            path.set("../dependencies/kotlin.toml")
        }
    }
}

kotlin {
    sourceSets {
        // Including the generated version catalogs into the sources.
        main.get().kotlin.srcDir(versionCatalogsGenerator.codeGenerationTask)
    }
}

gradlePlugin {
    plugins {
        create("your-plugin-declaration") {
            // ...
        }
    }
}

And inside the plugin's code:

internal class SomePlugin : Plugin<Project> {

    override fun apply(target: Project) {
        val catalog = KotlinVersionCatalog()
        target.dependencies.add("implementation", catalog.libraries.commonsIo.fullNotation)
    }

}
Hoar answered 6/9, 2023 at 13:39 Comment(0)
C
0

It a was a while, but here snipped, worked for me:

override fun apply(target: Project) {
    // ...
    val versionCatalogs = getVersionCatalogs(target).named("libs")
    
    target.dependencies.apply {
        // BOMs

        add(
            JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME,
            
            // Note for findLibrary: Alias will be automatically normalized: '-', '_' and '.' will be replaced with '.'
            platform(versionCatalogs.findLibrary("androidx.compose.bom").get())
        )
    }

    // ...
}
Cita answered 27/3, 2024 at 21:42 Comment(2)
I find the syntax overly complicated and the IDE won't detect new versions alike that. For comparison, with libs.versions.toml I can simply write implementation platform(libs.androidx.compose.bom).Overweigh
Yes, but if you use "convention plugins" in multi-module project, that is only option.Cita
O
0

Kotlin/Groovy version-catalogs are not being supported by Android Studio.
Better create the version-catalog as TOML file gradle/libs.versions.toml.

BOM entries can only be directly added, with //noinspection UseTomlInstead.
This is because the subsequent entries do not feature any version number.

This works pretty well, except for the buildSrc directory, where it cannot see the nested version-catalog. However, when opening the buildSrc directory as root project, the IDE will list it below "Gradle Scripts". It's basically all useless, unless being able to detect new versions (screenshot).

Screenhot: libs.versions.toml

Also can provide an example for a Gradle plugin: libs.versions.toml

Overweigh answered 27/3, 2024 at 21:51 Comment(0)
P
-1

Please make sure you add this block of code in your settings.gradle.kts file

enableFeaturePreview("VERSION_CATALOGS")
// == Define locations for components ==
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
    versionCatalogs {
        create("libs") {
            from(files("PATH/libs.versions.toml"))
        }
    }
}
Poisson answered 6/1, 2022 at 15:17 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.