Report has differences when nothing changes
dalewking opened this issue · 6 comments
Was trying to upgrade some dependencies and wanted to make sure that I was not getting unexpected transitive dependency updates. What i wanted to do was:
- run dependencyUpdates
- save the report
- upgrade a dependency
- run dependencyUpdates
- compare the previous report to see what changed
The problem is there were differences in the report even with no changes to dependencies.
It appears for the most of the changes it it that it is somewhat randomly choosing between the old and new version for the project URL
For example, here is part of the JSON report:
{
"group": "androidx.compose.ui",
"name": "ui",
"version": "1.4.3",
"projectUrl": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.2",
"userReason": null,
"available": {
"release": null,
"milestone": "1.6.2",
"integration": null
}
},
compared to this entry with no changes to dependencies:
{
"group": "androidx.compose.ui",
"name": "ui",
"version": "1.4.3",
"projectUrl": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.4.3",
"userReason": null,
"available": {
"release": null,
"milestone": "1.6.2",
"integration": null
}
},
I also see differences in reason:
{
"group": "androidx.test",
"name": "rules",
"version": "1.6.0-alpha01",
"projectUrl": "1.5.0",
"userReason": null,
"reason": "org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve androidx.test:rules:{strictly 1.6.0-alpha01}.\nRequired by:....
vs.
{
"group": "androidx.test",
"name": "rules",
"version": "1.6.0-alpha01",
"projectUrl": "1.5.0",
"userReason": null,
"reason": "org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve androidx.test:rules:+.\nRequired by:
Since we defer to Gradle to resolve the dependency, maybe it is non-deterministic due to caching and repository ordering? I usually add --refresh-dependencies
so I wonder if that would make it more consistent for you, as it forces it to bypass the cache?
I don't think it is gradle, because it is not a question of versions (at least for the first part). It is getting the correct versions for current and milestone versions, it is the projectUrl
We actually get that from Gradle as well,
Could there be a race condition ambiguity here whether it uses resolvedCoordinate or originalCoordinate
private fun getStatus(
coordinates: Map<Coordinate.Key, Coordinate>,
resolved: Set<ResolvedDependency>,
unresolved: Set<UnresolvedDependency>,
): Set<DependencyStatus> {
val result = hashSetOf<DependencyStatus>()
for (dependency in resolved) {
val resolvedCoordinate = Coordinate.from(dependency.module.id)
val originalCoordinate = coordinates[resolvedCoordinate.key]
val coord = originalCoordinate ?: resolvedCoordinate
val projectUrl = getProjectUrl(dependency.module.id)
result.add(DependencyStatus(coord, resolvedCoordinate.version, projectUrl))
}
I believe the only shared mutable state in this plugin is the projectUrls
cache, which uses a precursor idiom to computeIfAbsent
as that was written in pre-Java 8 Groovy. The rest is thread local state, so assuming that the configuration is not modified at runtime it should be stable as computations passed down between methods. That's not always true as much of Gradle is mutable and allowed to change, e.g. #98 takes advantage of that. So your idea makes a lot of sense, but I don't think we could do much at the plugin level?
All i am asking is to do a little debugging to see where it is happening. For example, putting some printlns to see if which version number is being used to call getProjectUrl and see if that is changing.