The following was tested on 8.4 and 8.5.
Here’s a boiled down example. A TOML file is used for the version catalog and it looks like this:
[versions]
jedis = { require = "[4.4.6,)", prefer = "5.0.1" }
spotless = { require = "[6.12.0,)", prefer = "6.22.0"}
[libraries]
jedis = { module = "redis.clients:jedis", version.ref = "jedis" }
[plugins]
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
And the build file is this:
plugins {
kotlin("jvm") version "1.9.21"
alias(libs.plugins.spotless)
}
dependencies {
implementation(libs.jedis)
}
At the time of writing the latest version of the spotless plugin is 6.23.0, so one minor version before the prefer. For Jedis the latest is 5.1.0 and there is also a 5.0.2 patch version.
Based on the docs the expectation is both the plugin and normal dependency would resolve to the prefer in this scenario. What actually happens is the normal dependency, jedis, follows that behavior but the plugin does not.
$ ./gradlew buildEnvironment
...
+--- com.diffplug.spotless:com.diffplug.spotless.gradle.plugin:[6.12.0,) -> 6.23.0
...
$ ./gradlew dependencyInsight --configuration runtimeClasspath --dependency jedis
redis.clients:jedis:{require [4.4.6,); prefer 5.0.1} -> 5.0.1
\--- runtimeClasspath
It appears for the plugin it does not utilize the prefer which was unexpected and leads to non-repeatable builds.
In practice I don’t actually need rich versions for plugins and perhaps the maintainers also don’t think it makes sense but it shouldn’t silently ignore.
The larger context for how I’m using this is creating a version catalog and platform to be distributed more broadly within a company with the primary goal of setting a floor of certain versions (the min on the require range) but keep the prefer closer to latest. The mix of require/prefer was extended to plugins while not particularly necessary and I could use a single version (effectively a require).