Skip to content

Don't pin explicit version on a renamed dep managed only by a remote ancestor parent#7498

Closed
MBoegers wants to merge 4 commits intomainfrom
mboegers/wrapper-parent-fix
Closed

Don't pin explicit version on a renamed dep managed only by a remote ancestor parent#7498
MBoegers wants to merge 4 commits intomainfrom
mboegers/wrapper-parent-fix

Conversation

@MBoegers
Copy link
Copy Markdown
Contributor

Summary

  • ChangeDependencyGroupIdAndArtifactId previously added an explicit <version> to the renamed artifact whenever the new GAV was not in the resolved dependencyManagement chain. That is correct for projects that manage versions locally (own <dependencyManagement> or a BOM import), but pinned versions unnecessarily for projects whose parent is a custom wrapper that itself extends a managed parent (e.g. spring-boot-starter-parent).
  • The fix skips the pin when the old dep is managed transitively (via isDependencyManaged, which walks the merged dependencyManagement list) AND no local <dependencyManagement> exists in the project's own POM or any local-parent POM (new hasLocalDependencyManagement helper). The lookup is cached per-document on the visitor, matching the existing pattern used for availableVersions and safeVersionPlaceholdersToChange.
  • Existing tests for BOM-import / locally-defined-management cases (managedToUnmanagedExternalizedDepMgmt, managedToUnmanagedWithoutChangeManagedDependency) still pin, because hasLocalDependencyManagement returns true.
  • Also bumps the expected junit-jupiter version in noDependencyManagementSection from 5.14.3 to 5.14.4 (a separate one-line maintenance fix; Maven Central now resolves 5.x to 5.14.4).

Test plan

  • New test ChangeDependencyGroupIdAndArtifactIdTest.doesNotPinVersionWhenOldDepManagedOnlyByRemoteAncestor — synthetic wrapper-parent scenario via withLocalRepository. Fails on main, passes with the fix.
  • ./gradlew :rewrite-maven:test --tests "org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactIdTest" — all 62 tests pass after the JUnit version bump.

Maven Central now resolves the `5.x` selector to 5.14.4 after the
JUnit Jupiter 5.14.4 release, so the hardcoded expected version had
to be bumped.
…ancestor parent

ChangeDependencyGroupIdAndArtifactId previously added an explicit
<version> to the renamed artifact whenever the new GAV was not in
the resolved dependencyManagement chain. That is correct for projects
that manage versions locally (own <dependencyManagement> or a BOM
import), but pinned versions unnecessarily for projects whose parent
is a custom wrapper that itself extends a managed parent (e.g.
spring-boot-starter-parent).

Skip the pin when the old dep is managed transitively AND no local
<dependencyManagement> exists in the project's own POM or any
local-parent POM. In that case the user is in a parent-managed
workflow and the new managed version will flow through once the
wrapper parent is upgraded.

The local-management lookup is cached as a per-document field on the
visitor, matching the existing visitor-field pattern used for
availableVersions and safeVersionPlaceholdersToChange.

Adds a synthetic Maven test (doesNotPinVersionWhenOldDepManagedOnlyByRemoteAncestor)
that publishes a wrapper parent via withLocalRepository and asserts
that javax.activation:javax.activation-api ->
jakarta.activation:jakarta.activation-api is renamed without an
explicit version.
…nt-fix

# Conflicts:
#	rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java
@MBoegers
Copy link
Copy Markdown
Contributor Author

Pulling this PR back at this stage. The test shows we would break version pinning, which is a crucial building block of security remediations.
The problem was raised in a situation where a project has a parent POM that wraps the Spring Boot parent's dependency management, and the Spring Boot upgrade recipes (which rename starters to new artifact names like spring-boot-starter-webspring-boot-starter-webmvc) are used. The new artifact isn't in the wrapper's still-old transitive BOM, so the recipe pins an explicit version. Once the customer upgrades their wrapper, that pin becomes redundant.
A run of RemoveRedundantDependencyVersions after the wrapper upgrade resolves it, or upgrading the wrapper before running the Spring Boot recipes avoids the pin in the first place.

@MBoegers MBoegers closed this Apr 29, 2026
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Apr 29, 2026
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.

1 participant