is it possible to reach `libs` from `gradle/libs.v...
# gradle
m
is it possible to reach
libs
from
gradle/libs.versions.toml
in pre-compiled scripts located in
buildScr/src/main/kotlin
?
c
Yes, you have to configure your included build to access it. Here's an example with an included build in
gradle/conventions
, it's the same in
buildSrc
: https://gitlab.com/opensavvy/decouple/-/blob/110-gradle/gradle/conventions/settings.gradle.kts#L11
m
I have that part actually, it makes it visible in
buildScr/build.gradle.kts
that’s fine but I want to reach it also inside
buildScr/src/main/kotlin/some.name.gradle.kts
c
Ah, sorry. I don't know, then.
there’s a workaround in that issue
m
Ohh great thanks a lot Adam!
v
It's a hack-around, not a work-around. :-D
And there is a proper but stringly API to access them
m
Yea but works like a charm thank you 🙂
j
@Vampire it is almost an official hackaround, everyone is using it hahah
v
Yep, glad I could help so many with it. :-)
m
it looks like this
hackaround
is still not enough to use in
plugin
block right ? I confirm that I am now able to use libs in gradle file of included build but I can not use the libs inside
plugins {…}
block, perhaps it is not integrated yet when the
plugins
block is being read. Maybe there is another
hackaround
for that too ? 😄
a
the plugins block is pretty limited, intentionally https://docs.gradle.org/current/userguide/plugins.html#sec:constrained_syntax What are you trying to do though? I suspect there might be a better way...
h
I think you should use alias() in the plug-in block
v
Your are right that it does not work and there is no other hackaround.
He cannot use alias, as he cannot use the version catalog.
m
Yea, I also wanted to reach
[plugins]
from TOML file in my
build.gradle
but it seems not possible, I mean it is possible everywhere except
Copy code
plugins {
   // here is not possible
}

dependencies {
   // here is possible
}
I think the reason is when the
plugins
block is applied the version catalogs are not integrated yet. I wanted to keep the name of pre-compiled plugins inside TOML file and avoid statically writing
a
yes that's true, you will have to duplicate the plugin IDs. But that's not such a big problem tbh. Either the plugin name is right, and it works, or it's wrong and Gradle will throw an error. And because precompiled-script plugins cannot specify a version in the
plugins {}
block (see docs), you have to specify the plugin version in the dependencies block in
buildSrc/build.gradle.kts
. And you can use version catalog to do that.
and you can re-use the plugin aliases in
buildSrc/build.gradle.kts
to specify the version of the external plugins
Copy code
public fun DependencyHandlerScope.plugin(id: String, version: String): String =
    "$id:$id.gradle.plugin:$version"

public fun DependencyHandlerScope.plugin(plugin: Provider<PluginDependency>): Provider<String> =
    plugin.map { "${it.pluginId}:${it.pluginId}.gradle.plugin:${it.version}" }
https://www.linen.dev/s/gradle-community/t/10015775/one-feature-that-i-liked-about-buildsrc-is-that-i-could-defi#3c55229f-e2d0-4cd6-bff8-8137a717bd53
m
Ohh according to PR in the conversatation that you send frim gradle-community, it should be possible in gradle 8.1-RC i will try with that
v
No
m
v
Nothing changed in 8.1, except that you do not get an error displayed when using plugins from the version catalog in normal build scripts
You still can't use them in pre-compiled script plugins
As my hackaround cannot work there as it has preconditions that are not fulfilled for them
m
I think they are referring for the default
buildScr
, and your hack-around should work for that as well
v
Then you think wrong. My hackaround is for precompiled script plugins, no matter whether in an included build or
buildSrc
. That change is only about normal build script's plugins blocks.
Those where you already can use them fine without my hack around, but get an ide error displayed even though it works
m
Ohh right I get what you mean
a
so, in this context, there are two types of Gradle config files. Precompiled script plugins, e.g.
buildSrc/src/main/kotlin/my-project-conventions.gradle.kts
. You can't use Plugin Aliases here, and even if you could, the plugins' coordinates would have to be defined in
dependencies [}
in
buildSrc/build.gradle.kts
anyway. And regular
build.gradle.kts
files e.g. •
./build.gradle.kts
./buildSrc/build.gradle.kts
./my-cool-subproject/build.gradle.kts
. You can use plugin aliases in these since Gradle 7.3 or something. The bugfix in 8.1 is specifically about fixing an IDE warning.
m
Yea the one I want achieve is the first one you mentioned
buildSrc/src/main/kotlin/my-project-conventions.gradle.kts
and it seems not possible to get plugins from version catalog in
plugins
block, i just have to write it statically. We wanted to share this module as git submodule between projects and then each project could have different plugin id with same name in TOML file
a
🤯 huh
sorry, I don't mean to be rude, but that sounds quite complicated. If you were able apply a plugin from versions catalog into the plugins block of a pre-compiled script plugin, what would that help you achieve? What's your end goal?
m
Yes indeed it is 🙂 I am not fan of it either, it was just an idea of future structuring of the build scripts for multiple projects. It is hard to explain without a solid example but we wanted to hold all the convention scripts in shared git repo where each project could override the id of plugin in its TOML file because they are also submodule of other projects..
But the more we dig the more complicated it gets so it is not a good idea overall, anyways thanks a lot for everyone who contributes to this conversation ❤️
a
okay, so basically wanted a subproject to override a plugin ID as a form of 'scoping', so that plugin IDs don't clash?
m
Yea clashing is a point and also as an example some project want to use
Copy code
detekt = { id = "detek-commercial" }
whereas some
Copy code
detekt = {id = "detek-library" }
in their TOML file but their submodules will only use
Copy code
plugins { id(libs.plugins.detekt.get().pluginId) }
in gradle, so TOML file of root project will help which scripts to be used over all submodules
a
Gotcha. I don't think such a dynamic way of loading plugins will be workable though, as you're finding out :)
m
actually it could be, if we were able to use libs in
plugins
block, it will allow us to create only 1 PR with 1 file into main repo, instead of creating 4-5 PRs to different repositories modifying 40-50 different build.gradle files and replacing
"detek-commercial"
to
"detek-library"
a
so
detek-commercial
and
detek-library
are two of your own convention plugins. I presume both apply Detekt, and each have some slightly different configuration based on the final product you want to build?
so for example a debug build will be less strict, and a production build will be more strict?
m
yes, and there are more of those scripts not only detekt and it is not for debug and release rather in-company vs client builds
a
to me that sounds like you just need one convention plugin, and in it it applies Detekt and sets configuration values dynamically using the Gradle Provider API, based on a build-time variable
m
It can be another workaround do you have any example for that ?
a
yup! So I did something recently in Dokka. The problem was that we wanted to run the tests using a different Java version. In CI/CD there's a GitHub matrix, so we can pass in a different Java version via an environment variable. And the Gradle config will read this variable, and dynamically change the version of Java
for convenience I made an extension that will contain all of the variables that control a Dokka build https://github.com/Kotlin/dokka/blob/e66f9d8711b5c1ba5e75fdcde8cfe998042c294a/build-logic/src/main/kotlin/org/jetbrains/DokkaBuildProperties.kt#L17-L49
I used a Gradle Property to fetch the Java Test Version, which is convenient because it can be set either via an environment variable that's prefixed with
ORG_GRADLE_PROJECT_
, or in a
gradle.properties
file, or via the command line
m
I think this can solve some of our needs i will check with the team thank you for sharing it 🙂
a
the DokkaBuildProperties extension is created in a base plugin that's applied to all subprojects and convention plugins, so it's always available https://github.com/Kotlin/dokka/blob/e66f9d8711b5c1ba5e75fdcde8cfe998042c294a/build-logic/src/main/kotlin/org/jetbrains/conventions/base.gradle.kts#L15
and then in the base Java convention, it uses the
testJavaLauncherVersion
variable to set the default Java launcher version for all test tasks https://github.com/Kotlin/dokka/blob/e66f9d8711b5c1ba5e75fdcde8cfe998042c294a/build-logic/src/main/kotlin/org/jetbrains/conventions/base-java.gradle.kts#L25-L31
and then because it's just a convention, subprojects can override the value if required. Which we needed to do in an integration test project, because one of the test project requires a minimum of Java 11 https://github.com/Kotlin/dokka/blob/e66f9d8711b5c1ba5e75fdcde8cfe998042c294a/integration-tests/gradle/build.gradle.kts#L22-L27
generally, it's a bit of a shift in thinking. It's the biggest difference between Maven and Gradle - composition vs inheritance. You can make Gradle behave like Maven, where there's a 'parent' and it controls everything, but that's not how Gradle works best.
m
Yea superficially looking it will solve some of our needs, we will give a close look definitely with a team thankfully it is public repo 🙂 Thanks a lot for sharing!
a
my pleasure! If you want to get more info, there's also a Gradle Slack that would be better suited to more general Gradle usage questions https://gradle.org/slack-invite
j
you can solve that issue by not using precompiled plugins and using normal plugins tho
m
Yea with Adam’s approach that is also a possibility