Version catalog access from plugin

I’ve implemented a versions catalog in my system, really loving this new api. I’m wondering if it is possible to access the version catalog from inside a plugin? I’d like to detect if a catalog exists, apply some entries to various configurations.

1 Like

Use the version of libs.version.toml in buildSrc?

Yeah, that’s what I’m asking, I’ve built a plugin implementing org.gradle.api.Plugin<org.gradle.api.Project>. I can’t seem to find a way to access catalog from the project api, and I was curious if I missed something, or if there is an alternative approach to get data from the catalog into my plugin.

it’s not difficult
You should add this code in settings.gradle in buildSrc

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

Here is my usage example

def springbootVersion = project.rootProject
                .extensions
                .getByType(VersionCatalogsExtension.class)
                .named("libs")
                .findVersion("springBoot")
                .get()
                .displayName

If you still don’t understand, you can refer to my github
my github
Good luck

1 Like

This is exactly what I was looking for! Thanks!!!

How about composite builds? Let’s say there are two builds: buildscript and example, example includes buildscript by the following declaration in its settings.gradle.kts:

pluginManagement {
    includeBuild("../buildscript")
}

All attempts to access version catalogs declared in buildscript’s settings.gradle.kts fail for me if done from inside of some org.gradle.api.Plugin located in buildscript. With the code provided above (project.rootProject.extensions.getByType(VersionCatalogsExtension.class)...) it’s only possible to get example’s version catalogs.

Is there any way to access a version catalog declared inside buildscript’s settings.gradle.kts to use it from some buildscript’s Plugin?

Update. I think I’ve got the picture - when we use constructions like project.rootProject.extensions.getByType(VersionCatalogsExtension.class)... inside plugins, the only version catalogs we can access - are those declared in the target project’s (to which we are going to apply the plugin) settings.gradle.kts. In other words, there seems to be no straightforward way to encapsulate version catalogs to be used inside plugins.

One more update. What I want to have is some automatic type-safe codebase generation allowing to add similar version catalogs from .toml files not at the Gradle’s buildscript level, but inside Gradle project’s codebase (which is usually src/main/kotlin/... or anything else linked by the sourceSet configuration). So in the case of composite builds described above, buildscript’s plugins get an access to version catalogs in an encapsulated manner regardless from what these plugins are going to be applied to eventually.

So everything I wrote above can be rephrased as: is there any Gradle plugin generating type-safe wrappers for .toml-based version catalogs and adding generated classes to project’s sources? Something like:

plugins {
  id("toml-wrappers-generator")
}

tomlWrappersGenerator {
  addTargetTomlCatalog(../dependencies.toml)
}

// Now this project has got DependenciesCatalog.kt included into its compilation sources.

buildSrc or composite build are totally the same here, no difference.
All you can access from the code of a plugin is the version catalog that is present in the target project.
If you make sure it is the same version catalog in both projects, you could use my hack-around in the according GitHub issue to use the type-safe accessors within the plugin code.
But other than that, you can just use the string-y API.

You can publish a version catalog though and tell the consumers to use that version catalog in their builds.
Or 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.

Not that I’m aware of, but you can probably do it relatively easily as you can loop through the entries and then generate some accessors from them, even if that is not how the version catalogs were meant to be used. :smiley:

Yeah, agree - will try to do it myself - now at least I have the entire picture of how it works and what I need eventually. Thank you :slight_smile:

even if that is not how the version catalogs were meant to be used. :smiley:

In my case there is a compilation of composite builds: one for required buildscripts, one for the core codebase (which is applied as a dependency to target projects by some of buildscript plugins) and one as an example of usage. Some of dependencies are shared between these builds. I want to have one ground truth for all of my dependencies by using corresponding .toml-catalogs inside some separate dependencies folder. At the same time I don’t want end users of my Gradle plugins to place any kinds of toml version catalogs into their projects just to make the plugins work.

Where you able to find a good solution to this and/or aware of a Gradle issue regarding this?

I’m migrating composite functionality from Maven (static using Tiles/Mixins) to Gradle (dynamic using Convention Plugins) but the dynamic nature of Gradle is actually causing a lot more overhead than I had hoped for.

It surprises me that one can’t have the plugin’s libs.versions.toml available during the plugins runtime without interference from the target project’s libs.versions.toml.

There are of course workarounds but they add boilerplate, slow down build time (when the information is in fact static), interferes with type safety etc. I also like a solution that works out of the box with dependabot/renovate.

Well, that is not what the feature is meant for mainly.
Usually, the target project controls which dependencies it depends on, and a plugin could use the string-y VersionCatalogsExtension to get what the target project has in the version catalog if it does.

For using version catalog accessors in Groovy DSL precompiled build scripts in an included build, that just works.
For using the type-safe catalog accessors in Kotlin DSL precompiled build scripts, there is Make generated type-safe version catalogs accessors accessible from precompiled script plugins · Issue #15383 · gradle/gradle · GitHub with also a hack-around by me and further down some plugin that can generate such accessors for the included build.

How good and clean that plugin is, or whether you could use those accessors also in normal code in the included build, I have no idea.

But either of those solutions still depend on the target project having the expected version catalog with the expected entries.

One of the main benefits of version catalogs in TOML files in the target project is, that if you do not add or remove entries but only change a version, the build scripts do not need to be recompiled and all unaffected tasks can stay up-to-date or taken from cache. Other solutions to centralize versions that were used previously like having constants in a class in an included build have the problem, that changing any version changes the buildscript classpath and so invalidate all up-to-date state or cache keys of all tasks that are not built-in and also all buildscript compile results.

If you want to have the versions baked into the plugin, you should probably not use a version catalog for that, or have some generation task that generates something for runtime-usage from the version catalog, or package the TOML file and parse that at runtime of your plugin with any TOML parser out there. But you will of course have mentioned drawback.

Thanks for the response.

Gradle’s inner is new to me though, so I hope that I have missed something.
Why should we have to create something custom-made when this functionality code be included in Gradle (which will most likely also make support for it in e.g. dependabot/renovate more likely).

The use-case I have is a Convention plugin where the dependency versions used the target project is set by the convention plugin and NOT the target project, i.e. composition.

I created a demo for Maven (using Mixins) and Gradle (using convention plugin) last week which manifested the challenge in this thread.

Demo project (README contains my “findings”): GitHub - jimisola/arconia-composition-demo: Demonstration project showcasing Spring Boot composition patterns for automatic Redis and observability (LGTM stack) integration using Arconia Dev Services

If the versions are directly in the plugin Java source file then:

  • dependabot/renovate etc will not work out of the box
  • it makes less obvious for users as compared to if the files were in a libs.versions.toml

Why should we have to create something custom-made when this functionality code be included in Gradle

There could be many functionality included in Gradle and there could be many bugs fixed.
Why something specific is not in can have many reasons, for example shortage of software engineers, decision not to do it for some reason, noone requested something like that, … You need to ask Gradle folks if you want to know.

The use-case I have is a Convention plugin where the dependency versions used the target project is set by the convention plugin and NOT the target project, i.e. composition.

Yes, I got you, and I told you how you could do it, and what drawback it would have.

If the versions are directly in the plugin Java source file then:

  • dependabot/renovate etc will not work out of the box
  • it makes less obvious for users as compared to if the files were in a libs.versions.toml

And I told you how you could deal with it if you don’t mind the drawback.
Either package the toml file and parse it at runtime of your plugin, or generate some other form out of it at build time that you then consume at runtime.

I was actually hoping that a Gradle contributor would reply. Do not see the benefit of starting a new thread, so I’ll try Slack and otherwise file a feature request.

I am a regular Gradle contributor.
If you meant a Gradle employee, well, this is a user community.
Same for Slack.
Occasionally in both places it can also happen that Gradle employees read and answer,
but both are mainly user-help-users communities.

Ok. I see. What is your suggestion then? I rather not file a feature request out of the blue.

With your insight as a regular contributor do you think it’s feature request worth filing?
I know that from my point of view it is since I think that the current solution are more workaround than actual solution and it would useful to have something standardized instead of each plugin creating it’s own custom solution.

It’s always worth to create feature requests for functionality you are missing in all projects. If noone requests it, the authors are not aware of the demand. Whether it will be considered or rejected, you will see then. I could only guess or state my opinion.

1 Like

For info: Support plugin-owned, type-safe TOML version catalogs for convention plugins (independent of target projects) · Issue #36337 · gradle/gradle · GitHub

Gradle intentionally does not allow plugins to access the target project’s libs.versions.toml

That’s not correct at all.
Gradle of course provides explicit access to target project’s version catalog.
It just does not provide type-safe accessors in pre-compiled Kotlin DSL script plugins, because type-safe accessors are only available for things Gradle knows will be available at runtime and for version catalogs it does not know which will be there. This is not a boundary topic.

Re-declaring catalogs manually in every consuming build

Not necessarily, the plugin can also publish a version catalog that target builds can then apply.

1 Like

Thank you. Was a little too fast there when I asked ChatGPT to lay a final touch.
Mainly been using and developing for Maven, so appreciate you taking the time.

1 Like