Skip to content

Preserve GString/StringTemplate in ChangeDependency when version unchanged#6830

Draft
timtebeek wants to merge 2 commits intomainfrom
timtebeek/preserve-gstring-in-change-dependency
Draft

Preserve GString/StringTemplate in ChangeDependency when version unchanged#6830
timtebeek wants to merge 2 commits intomainfrom
timtebeek/preserve-gstring-in-change-dependency

Conversation

@timtebeek
Copy link
Member

@timtebeek timtebeek commented Feb 26, 2026

Summary

  • Add overrideManagedVersion guard to GString and Kotlin StringTemplate code paths in ChangeDependency, matching the existing guard on the literal path
  • When only group/artifact changes (version unchanged), preserve the interpolated string structure instead of collapsing to a literal with a pinned version
  • Update two existing tests (worksWithGString, kotlinDslStringInterpolation) to expect the new behavior

Problem

When ChangeDependency renames a dependency that uses a GString or Kotlin StringTemplate (e.g. "group:artifact:${version}"), it unconditionally collapsed the interpolated string to a literal and pinned the resolved version. This caused the Spring Boot 4 migration recipe to turn "org.springframework.boot:spring-boot-starter-web:${springBootVersion}" into "org.springframework.boot:spring-boot-starter-webmvc:4.0.3", destroying the property reference.

The literal code path already had the correct guard: it only pins a new version when the original dependency had an explicit version or overrideManagedVersion=true. The GString and Kotlin StringTemplate paths were missing this guard.

Test plan

  • Existing worksWithGString test updated to expect GString preservation
  • Existing kotlinDslStringInterpolation test updated to expect StringTemplate preservation
  • All 19 ChangeDependencyTest tests pass
  • Integration test in rewrite-spring confirms Spring Boot 4 migration no longer pins starter versions

…rsion is unchanged

When `ChangeDependency` renames a dependency that uses a GString or Kotlin
StringTemplate (e.g. `"group:artifact:${version}"`), and the version is not
being changed, the GString/StringTemplate structure is now preserved instead
of being collapsed to a literal with a pinned version.

Previously, the GString and Kotlin StringTemplate code paths unconditionally
applied `newVersion` without checking the `overrideManagedVersion` guard that
the literal path already had. This caused recipes like the Spring Boot 4
migration to pin hardcoded versions on dependencies that used property
references for their version (e.g. `${springBootVersion}`).

The fix adds the same `overrideManagedVersion` guard to both the GString and
Kotlin StringTemplate paths, and when only group/artifact changes (not
version), updates only the literal prefix while preserving the interpolated
structure.
def version = '2.6'
dependencies {
implementation platform("org.apache.commons:commons-lang3:3.11")
implementation platform("org.apache.commons:commons-lang3:${version}")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we're effectively not making any change, other than the markers; We should add gradle.properties files here and assert those are updated.

Move version variables from inline definitions to gradle.properties in
worksWithGString and kotlinDslStringInterpolation tests, making them
closer to real-world usage patterns. The properties file remains
unchanged, confirming the GString/StringTemplate structure is preserved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant