Skip to content

UpgradeDependencyVersion (Gradle): respect shared version variables#7491

Merged
MBoegers merged 4 commits intomainfrom
mboegers/shared-version
May 5, 2026
Merged

UpgradeDependencyVersion (Gradle): respect shared version variables#7491
MBoegers merged 4 commits intomainfrom
mboegers/shared-version

Conversation

@MBoegers
Copy link
Copy Markdown
Contributor

@MBoegers MBoegers commented Apr 28, 2026

Summary

org.openrewrite.gradle.UpgradeDependencyVersion corrupts shared version variables. When a Kotlin val, Groovy def/ext { }, or gradle.properties entry backs more than one dependency, the recipe blindly picked the first GroupArtifact from its scanner map and wrote that GA's resolved version into the variable — silently breaking every other dependency that used it.

val jacksonVersion = "2.17.3"
implementation("com.fasterxml.jackson.core", "jackson-annotations", jacksonVersion)
implementation("com.fasterxml.jackson.core", "jackson-core", jacksonVersion)

UpgradeJackson_2_3_Dependencies upgrades jackson-annotations to 2.21. jackson-annotations:2.21 exists; jackson-core:2.21 does not (only 2.21.0/.1/.2). Today the variable becomes 2.21 and jackson-core is broken.

Approach

  • Ports the canUpdateVariable pattern from ChangeDependency (introduced in ChangeDependency skips dependencies whose new coordinates don't resolve #7321), tightened so the variable is only updated when every GA sharing it is targeted by the recipe's matcher and every GA resolves to the same concrete version.

  • New scanner pass records variable usages for all dependencies — matched and unmatched — so the visitor can detect cross-dependency sharing.

  • New safeUpdatedVersion helper returns the agreed-upon resolved version when the variable is safe to update, or null otherwise. Consults the scanner's gaToNewVersion cache before re-resolving so it stays cheap.

  • The three existing variable-update sites (postVisit ext-property handler, UpdateProperties.visitEntry, settings.gradle ext block) are guarded by safeUpdatedVersion instead of blindly picking the first GA.

  • updateDependency falls through to inline a literal version on the matched call site when the variable cannot be safely updated, leaving the variable (and the other dependencies sharing it) untouched. Mirrors ChangeDependency.updateDependency's detach behaviour.

  • GradleDependency.withDeclaredVersion extended to handle replacing a J.Identifier (variable reference) with a J.Literal in the multi-component DSL form, since the previous implementation only handled literal-to-literal version updates.

After the fix, the same scenario produces:

val jacksonVersion = "2.17.3"  // unchanged
implementation("com.fasterxml.jackson.core", "jackson-annotations", "2.21")  // detached to literal
implementation("com.fasterxml.jackson.core", "jackson-core", jacksonVersion)  // unchanged

Test plan

  • Three new tests reproduce the bug across Kotlin DSL val, Groovy ext { }, and gradle.properties. All three fail on main and pass on this branch.
  • Full :rewrite-gradle:test passes — no regressions in the 100+ existing UpgradeDependencyVersionTest tests, including the existing happy-path tests at every guarded site (updateVersionInVariable, upgradesVariablesDefinedInExtraProperties, versionInPropertiesFile, upgradeVersionInSettingsGradleExt).

@MBoegers MBoegers changed the title UpgradeDependencyVersion (Gradle): do not corrupt shared version variables UpgradeDependencyVersion (Gradle): respect shared version variables Apr 28, 2026
@MBoegers MBoegers marked this pull request as ready for review April 29, 2026 13:18
@MBoegers MBoegers requested a review from sambsnyd May 4, 2026 12:12
@github-project-automation github-project-automation Bot moved this to Ready to Review in OpenRewrite May 4, 2026
@MBoegers MBoegers merged commit 5a28936 into main May 5, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite May 5, 2026
@MBoegers MBoegers deleted the mboegers/shared-version branch May 5, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants