Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report has differences when nothing changes #844

Open
dalewking opened this issue Mar 5, 2024 · 6 comments
Open

Report has differences when nothing changes #844

dalewking opened this issue Mar 5, 2024 · 6 comments

Comments

@dalewking
Copy link

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:
@ben-manes
Copy link
Owner

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?

@dalewking
Copy link
Author

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

@ben-manes
Copy link
Owner

We actually get that from Gradle as well,

private fun resolveProjectUrl(id: ModuleVersionIdentifier): String? {
return try {
val resolutionResult =
project.dependencies
.createArtifactResolutionQuery()
.forComponents(DefaultModuleComponentIdentifier.newId(id))
.withArtifacts(MavenModule::class.java, MavenPomArtifact::class.java)
.execute()
// size is 0 for gradle plugins, 1 for normal dependencies
for (result in resolutionResult.resolvedComponents) {
// size should always be 1
for (artifact in result.getArtifacts(MavenPomArtifact::class.java)) {
if (artifact is ResolvedArtifactResult) {
val file = artifact.file
project.logger.info("Pom file for $id is $file")
var url = getUrlFromPom(file)
if (!url.isNullOrEmpty()) {
project.logger.info("Found url for $id: $url")
return url.trim()
} else {
val parent = getParentFromPom(file)
if (parent != null &&
"${parent.group.orEmpty()}:${parent.name}" != "org.sonatype.oss:oss-parent"
) {
url = getProjectUrl(parent)
if (!url.isNullOrEmpty()) {
return url.trim()
}
}
}
}
}
}
project.logger.info("Did not find url for $id")

@dalewking
Copy link
Author

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))
    }

@ben-manes
Copy link
Owner

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?

@dalewking
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants