This message was deleted.
# dependency-management
s
This message was deleted.
1
m
you can use:
Copy code
java {
     consistentResolution {
           useCompileClasspathVersions()
     }
}
see https://docs.gradle.org/current/javadoc/org/gradle/api/plugins/JavaResolutionConsistency.html
v
t
Those are the ones! ♥️
👌 1
d
Would using a platform also work?
v
Not really, except maybe you enforce the platform, which should usually not be done.
d
Using
enforcedPlatform
should be fine right if you don't have anyone consuming the build? From https://docs.gradle.org/current/userguide/platforms.html#sub:bom_import "This declaration is effectively transitive and so will apply to the dependency graph of your consumers."
m
because you can doesn't mean you should.
my advice would be : don't use
enforcedPlatform
☝️ 1
it's a hammer
d
Can you elaborate why? And what else should be used to pin the version? If it's not a good idea I wonder why it's available in the first place
v
It's available as a last resort if you really need it. But usually you shouldn't use it.
t
just
platform()
, no need to enforce, I think @melix is only against
enforcedPlatform()
, right?
👍 1
m
it's available for backwards compatibility reasons. Even when it was introduced, we never recommended using it. It was designed for very special use cases where you want to override dependency versions without using diligence. It's not reliable either, since it can be order sensitive (e.g like
force
, which is also bad)
you can use
platform()
, yes, but this wouldn't solve this consistency use case, unless the platform only uses strict dependencies.
t
or the platform defines all the latest and greatest 😉, because then it'll win in resolution
m
it depends, if a transitive dependency has a strict version it would loose
also depends what resolutions strategy you use (e.g fail on version conflict)
d
In my case there were 4 different versions of
slf4j-api
resolved in different components of the build, I assumed to align the same version across the build would be to use
enforcedPlatform()
. But based on the above it's better to use
platform()
with
strictly
?
t
in my case using a platform will actually also align the main and test, because my problem was using
compileOnly
and mismatching on
testImplementation
because it was missing the dependency that wasn't provided by
implementation
, but was transitively available
m
But based on the above it's better to use platform() with strictly?
Yes, it's better, but you can try without
strictly
first, if as @twisterrob said you use the latest, in general it would just work smoothly.
t
test, test, test 😄
m
or use consistent resolution, which is designed for this use case
then you don't care what version you use, it will automatically be aligned
t
After reading the docs you linked in the beginning I found platform, and started using it to align my subprojects, which "accidentally" also solves the main/test inconsistency issue, so I don't need consistentResolution.
d
I kinda want both, consistent resolution and a pinned version across the build 😅. Thanks for the insight, I'll try to use
platform()
and fail on version conflicts
t
I tried what you said @Daan, because that's my dream too, but I can't get
failOnVersionConflict
to build successfully, do you have luck? simple real example:
Copy code
implementation("com.google.android.material:material:1.8.0")
// transitively pulls in androidx.drawerlayout:drawerlayout:1.1.1
implementation("androidx.appcompat:appcompat:1.6.1")
// transitively pulls in androidx.drawerlayout:drawerlayout:1.0.0

implementation(platform("..."))
// which contains constraint api("androidx.drawerlayout:drawerlayout:1.1.1")
results in
Copy code
> Could not resolve all dependencies for configuration ':debugRuntimeClasspath'.
   > Conflict(s) found for the following module(s):
       - androidx.drawerlayout:drawerlayout between versions 1.1.1 and 1.0.0
v
Yeah, I always wondered where failing on version conflict would be helpful, except if you exclude 90% of your transitive dependencies. 😄
💡 1
t
Few years ago I was managing that, I was excluding things and forcing a few, it was working, but very hard to maintain. Easier to allow the resolution happen naturally and diff the
:dependencies
output when things change.
👌 1
d
No I didn't unfortunately, trying it out here: https://github.com/daanschipper/consistent-dep-resolving. Will try to get something else than
enforcedPlatform()
working.
Using
platform()
,
strictly
and
failOnVersionConflict
seems to work 😄 Now trying to find out how to get the version reference from the version catalog, I'll leave the repo up as an example
v
libs.versions.foo
?
t
or
Copy code
libs.foo.get().version
libs.foo.get().versionConstraint.requiredVersion
d
Ty, didn't know methods were generated for versions as well. Had to do
libs.versions.jackson.get()
as
strictly
only accepts a
String
.
t
but isn't setting
strictly
in the version catalog better? https://github.com/gradle/gradle/issues/21544#issuecomment-1225234761
👀 1
☝️ 1
@Vampire does it have a side effect if we do this ^? as in, we would use
constraints { api(lib.foo) }
as well as
implementation(lib.foo)
, don't we only want
strictly
in the platform?
v
I have no idea, but I wouldn't expect problems if you have the strict version in the platform and in the dependency as long as it is the same strict version.
t
if the artifact is published, the POM might expose the strictly accidentally, while with platform constraints I would imagine that only the resolution result ends up in the pom
v
Well, decide what you want to have published and where you want to have strict versions. You can also have a
lib.foo
and a
lib.foo.strictly
if that is what you need.
d
Using
jackson = { strictly = "2.8.9" }
in the version catalog works 😄 Updated the repo accordingly
👍 2
t
You can also have a
lib.foo
and a
lib.foo.strictly
if that is what you need.
related https://gradle-community.slack.com/archives/CAH4ZP3GX/p1679054200794169, the same approach could be used for this
v
while with platform constraints I would imagine that only the resolution result ends up in the pom
Where constraints end up depends afair on whether you do them on
api
or
implementation
like other dependencies. The POM versions should afair not be influenced by the platform unless you configure to publish resolved versions which is an explicit setting.
Using
jackson = { strictly = "2.8.9" }
in the version catalog works 😄 Updated the repo accordingly
Or
jackson = "2.8.9!!"
if you like the inline syntax more
d
I like
strictly
a bit more as its easier to google for other devs than
!!
, thanks for the tip and all the help
👌 1
t
if you publish this project, please make sure you don't publish strictly, it's not fun to deal with strict transitive deps
☝️ 1
d
Luckily I don't need to publish, but that does question me how you would align versions only for your project but not the consumers of your project
v
Platform with strict versions that is not used on
api
but on
implementation
probably
d
Is that even possible? Tried it with the following:
Copy code
dependencies {
    constraints {
        // 1. Configuration with name 'implementation' not found.
        add('implementation', libs.jackson.core)
        add('implementation', libs.jackson.databind)
        // 2. > Could not find method implementation() for arguments [map(valueof(DependencyValueSource))] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyConstraintHandler.
        implementation libs.jackson.core
        implementation libs.jackson.databind
    }
}
v
And
api
works at that spot? o_O
I'd have guessed neither works as it is not a Java project where you try that
Besides that, everything is possible: 😄
🎉 1
d
Yes,
api
works 🤷 See the repo as example
The
java-platform
plugin only creates the
api
configuration, not the
implementation
one: https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaPlatformPlugin.java#L109.
v
I talked about where you apply your platform, not within the platform
t
I need to solve the publishing part, so will report back
d
Sorry @Vampire, I don't follow what you mean
v
implementation platform(project(':platform'))
vs.
api platform(project(':platform'))
d
oh 🤦‍♂️
t
that sounds natural to work
d
that was already set to
implementation
🙂
v
Yes, afair with
implementation
it should not propagate to consumers. But just double-check what happens. 🙂
t
so, I found a way to do
strictly
only in platform:
Copy code
api(constraintNotation) { version { strictly(version!!) } } // !! is Kotlin, not Gradle
d
That's what I had before 😛
Which one is better to use?
t
TOML
= "x!!"
-> does strictly everywhere (including dependencies, which can easily leak) platform
api { strictly(version!!)
-> strictly only in platform so
strictly(version!!)
is safer, but testing POM now
so far didn't learn much, it seems
strictly
is the default in maven?! maybe I should be experimenting on a simpler project, because Android could be making things more interesting...
anyway, the platform is added as
Copy code
<dependencyManagement>
    <dependency>
      <groupId>platform-group</groupId>
      <artifactId>platform-name</artifactId>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
unless we do
compileOnly(platform(...))
, so exactly the same as with deps. compileOnly -> nothing api -> as shown above implementation -> as shown above runtimeOnly -> as shown above
so far I think platform only affects the local build, it only shows up in dependencyManagement, and has no effect on
<dependencies>
. I declared an outdated dependency, that has
!!
and
strictly(version!!)
, but in the POM, it shows up as the old version I declared in build.gradle directly. On
:dependencies
the
strictly
shows and all instances of the lib are
-> strictVersion
.
v
Unless you declare to publish resolved versions, yes