Hello everyone - I have created a custom Gradle pl...
# community-support
m
Hello everyone - I have created a custom Gradle plugin for my team, to build Spring Boot-based microservices. The plugin encapsulates all of our best practices, which include applying and configuring a handful of other plugins (eg, the spring boot and axion-release plugin among others). Because my code needs visibility to the extension types of some of those plugins, I need them to be implementation dependencies of my plugin build. To satisfy warnings about Gradle 9 compatibility, I've implementing a settings plugin to use plugin management to set runtime versions of those plugins (effectively adding them to the classpath). I expected that I could set a different version there than the version that is included in my plugin build as a dependency, but it seems like regardless of the version I specify against plugin management at runtime, I wind up with the version of the plugin I built against. Is this expected? Is there a way to compile against one plugin version and run against another? (That is Gradle 9 compatible, preferably.) Thanks!
e
I believe settings is a parent classloader so anything that gets loaded there will be present in all buildscript classpaths
v
Please do not split topics across several threads. This makes following the conversation in the threads view very hard as the context of the other messages is missing. If you have additional information either edit the original message or post to its thread. Regarding the problem, usually if you only react to plugins being applied and do things if they are applied by something else, you would use
compileOnly
. If you apply the actual plugins, then it is usually more idiomatically to use
implementation
. I did not fully get what you meant with Gradle 9 compatibility and using plugin management to specify plugin version. If you meant that you tried to specify a different plugin version in
pluginManagement { plugins { ... } }
, then yes, it is expected that this is ignored, because things in there just define default versions that are used if you apply the plugin without specifying a version later on which is not your case.
If the plugin is a settings plugin and you use the (top-level)
plugins
block in the settings script, or a version constraint in
buildscript { dependencies { ... } }
, you can influence / control the 3rd party plugin version. Same if your plugin is a project plugin and you do it there. You just have to make sure that your version controlling happens in the same classpath / configuration, so that version resolution works like expected.
m
Thank you for the reply; I've removed my follow-up about
compileOnly
. The Gradle 9 compatibility errors I encountered were warnings about manipulating the buildscript classpath "late" in the lifecycle. I'm going to try working with
buildscript { dependencies
in my settings plugin. Going to try some things and update the thread.
v
Not in the settings plugin, why?
In your settings plugin you just declare a dependency in its build script
m
The Gradle 9 compatibility warnings gave me the impression that the settings plugin was the appropriate place to manipulate the buildscript classpath, rather than the build plugin. Not the case?
e
gradle 9 or not, you can't affect a buildscript classpath after your plugin loaded in that buildscript has started executing
depending on the versions you need to switch on though, I would have guessed that https://docs.gradle.org/current/userguide/variant_attributes.html#sub:gradle_plugins_default_attributes is easier than doing settings manipulation
m
Ok. So I think what it comes down to then is if I build my plugin against (say) spring boot plugin 3, there is no way for my plugin to specify spring boot plugin 4 - my users would have to edit
settings.gradle.kts
and add their own buildscript block to do that. Correct? That's an acceptable outcome, I think.
e
I would suggest using variants to have different behavior on different gradle versions (and at that point do you still need a settings plugin?)
v
You can manipulate the build script
buildscript
classpath from a settings plugin though. But you really shouldn't
🙂 1
e
you can't affect the settings buildscript classpath but you can affect projects, yes
still better not to
v
Let's take a step back. What is your exact use-case. What would you want to manipulate in the
buildscript
classpath from your settings plugin and for what reason?
m
I'm trying to preserve the freedom of my users to specify a different version of a plugin than our team-standards plugin was built against. e.g., a new version of lombok comes out and somebody wants to use it. I'd like them to be able to without cutting a new version of the team standards plugin. Of course, there are ways this could totally not work (eg if the extension class is no longer compatible) but I'm OK with that.
Certainly this does not have to be from a settings plugin, I only went there because I got the mistaken impression it was the way to accomplish my goal.
v
But I still did not get how you think / thought the solution should be. For the goal you stated you just have absolutely nothing to do in your plugin, you users can upgrade or downgrade the version however they like if they do it correctly. Thus I wonder what/ how you tried to do, messing around with any buildscript classpath.
m
It's definitely not true that there's nothing to do in my plugin. The extension types of those other plugins are populated to abide by our conventions. e.g.
Copy code
project.extensions.configure(IdeaModel::class.java) {
            it.project {
                it.vcs = "Git"
            }
            it.module {
                it.isDownloadJavadoc = true
                it.isDownloadSources = true
            }
        }
This will work at runtime even with newer versions of the idea plugin than this code compiles against. (Unless one of those fields is removed from IdeaModel of course.) I'd like a user to be able to use IDEA plugin x+1 even though this code may have been built against IDEA plugin x.
If the answer is that this simply isn't possible because the classpath is fixed before any plugins start running - or will be in some future of Gradle - that's a valid answer.
v
Why are you saying I lie
You don't need to do anything special
The user can upgrade or downgrade those 3rd party plugins without any problem as I told you
e
if the third-party plugins evolve in a binary-compatible way, there is no issue with a consumer using
Copy code
plugins {
    id("local.convention.plugin") version "x" // usually uses idea x
    id("idea") version "y"
m
I absolutely intended no disrespect at all, simply trying to clarify. Apologies.
e
Gradle will resolve to the highest versions (as normal) before running any plugin code
m
Ah, I see, I would not have thought that explicit plugin application in the build.gradle.kts would be the way, but it makes sense.
v
It using a version constraint as I said before, your users can even downgrade the version without any problem
e
if they plugins evolve in binary-incompatible ways, then you need to use reflection
creating a settings plugin won't help with that
m
Yes if plugins evolve in incompatible ways, at that point users are either on their own or we will create an updated local conventions plugin.
Thank you both so much for your help!
👌 1