UpgradeDependencyVersion (Gradle): respect shared version variables#7491
Merged
UpgradeDependencyVersion (Gradle): respect shared version variables#7491
Conversation
…olve for all sharers
sambsnyd
approved these changes
May 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
org.openrewrite.gradle.UpgradeDependencyVersioncorrupts shared version variables. When a Kotlinval, Groovydef/ext { }, orgradle.propertiesentry backs more than one dependency, the recipe blindly picked the firstGroupArtifactfrom its scanner map and wrote that GA's resolved version into the variable — silently breaking every other dependency that used it.UpgradeJackson_2_3_Dependenciesupgradesjackson-annotationsto2.21.jackson-annotations:2.21exists;jackson-core:2.21does not (only2.21.0/.1/.2). Today the variable becomes2.21andjackson-coreis broken.Approach
Ports the
canUpdateVariablepattern fromChangeDependency(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
safeUpdatedVersionhelper returns the agreed-upon resolved version when the variable is safe to update, ornullotherwise. Consults the scanner'sgaToNewVersioncache before re-resolving so it stays cheap.The three existing variable-update sites (
postVisitext-property handler,UpdateProperties.visitEntry,settings.gradle extblock) are guarded bysafeUpdatedVersioninstead of blindly picking the first GA.updateDependencyfalls 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. MirrorsChangeDependency.updateDependency's detach behaviour.GradleDependency.withDeclaredVersionextended to handle replacing aJ.Identifier(variable reference) with aJ.Literalin the multi-component DSL form, since the previous implementation only handled literal-to-literal version updates.After the fix, the same scenario produces:
Test plan
val, Groovyext { }, andgradle.properties. All three fail onmainand pass on this branch.:rewrite-gradle:testpasses — no regressions in the 100+ existingUpgradeDependencyVersionTesttests, including the existing happy-path tests at every guarded site (updateVersionInVariable,upgradesVariablesDefinedInExtraProperties,versionInPropertiesFile,upgradeVersionInSettingsGradleExt).