diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java index 30a0467d16e..4da3c55ccf4 100755 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java @@ -94,12 +94,22 @@ public class ChangeDependencyGroupIdAndArtifactId extends Recipe { @Nullable Boolean changeManagedDependency; + @Option(displayName = "Update dependency management", + description = "Also update the dependency management section. The default for this flag is `true`.", + required = false) + @Nullable + Boolean changePropertyVersionNames; + public ChangeDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifactId, @Nullable String newGroupId, @Nullable String newArtifactId, @Nullable String newVersion, @Nullable String versionPattern) { - this(oldGroupId, oldArtifactId, newGroupId, newArtifactId, newVersion, versionPattern, false, true); + this(oldGroupId, oldArtifactId, newGroupId, newArtifactId, newVersion, versionPattern, false, true, false); } - @JsonCreator public ChangeDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifactId, @Nullable String newGroupId, @Nullable String newArtifactId, @Nullable String newVersion, @Nullable String versionPattern, @Nullable Boolean overrideManagedVersion, @Nullable Boolean changeManagedDependency) { + this(oldGroupId, oldArtifactId, newGroupId, newArtifactId, newVersion, versionPattern, overrideManagedVersion, changeManagedDependency, false); + } + + @JsonCreator + public ChangeDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifactId, @Nullable String newGroupId, @Nullable String newArtifactId, @Nullable String newVersion, @Nullable String versionPattern, @Nullable Boolean overrideManagedVersion, @Nullable Boolean changeManagedDependency, @Nullable Boolean changePropertyVersionNames) { this.oldGroupId = oldGroupId; this.oldArtifactId = oldArtifactId; this.newGroupId = newGroupId; @@ -108,6 +118,7 @@ public ChangeDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifac this.versionPattern = versionPattern; this.overrideManagedVersion = overrideManagedVersion; this.changeManagedDependency = changeManagedDependency; + this.changePropertyVersionNames = changePropertyVersionNames; } @Override @@ -156,13 +167,13 @@ public TreeVisitor getVisitor() { @Override public Xml visitDocument(Xml.Document document, ExecutionContext ctx) { - // Any managed dependency change is unlikely to use the same version, so only update selectively. - if ((changeManagedDependency == null || changeManagedDependency) && newVersion != null || versionPattern != null) { + // Any managed dependency change is unlikely to use the same version, so only update selectively. If the new dependency is already managed, don't change the old dependency. It will be removed at the end. + if ((changeManagedDependency == null || changeManagedDependency) && newVersion != null && !isDependencyManaged(newGroupId, newArtifactId, newVersion)) { doAfterVisit(new ChangeManagedDependencyGroupIdAndArtifactId( oldGroupId, oldArtifactId, Optional.ofNullable(newGroupId).orElse(oldGroupId), Optional.ofNullable(newArtifactId).orElse(oldArtifactId), - newVersion, versionPattern).getVisitor()); + newVersion, versionPattern, changePropertyVersionNames).getVisitor()); } return super.visitDocument(document, ctx); } @@ -203,13 +214,35 @@ public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { t = (Xml.Tag) new RemoveContentVisitor<>(versionTag.get(), false).visit(t, ctx); } else { // Otherwise, change the version to the new value. - t = changeChildTagValue(t, "version", resolvedNewVersion, ctx); + if (Objects.requireNonNull(currentVersion).contains("$")) { + // If the version is a property value, change version in property section and rename the property if changePropertyNames is true. + String propertyVariable = currentVersion.substring(2, currentVersion.length() - 1); + String newPropertyVariable = propertyVariable; + if (Boolean.TRUE.equals(changePropertyVersionNames)){ + newPropertyVariable = newArtifactId + ".version"; + doAfterVisit(new RenamePropertyKey(propertyVariable, newPropertyVariable).getVisitor()); + t = changeChildTagValue(t, "version", "${"+newPropertyVariable+"}", ctx); + } + doAfterVisit(new ChangePropertyValue(newPropertyVariable, resolvedNewVersion, false, false).getVisitor()); + } else { + //If the version is no property value, change it right here. + t = changeChildTagValue(t, "version", resolvedNewVersion, ctx); + } + } - } else if (configuredToOverrideManageVersion || !newDependencyManaged) { - //If the version is not present, add the version if we are explicitly overriding a managed version or if no managed version exists. - Xml.Tag newVersionTag = Xml.Tag.build("" + resolvedNewVersion + ""); - //noinspection ConstantConditions - t = (Xml.Tag) new AddToTagVisitor(t, newVersionTag, new MavenTagInsertionComparator(t.getChildren())).visitNonNull(t, ctx, getCursor().getParent()); + } else if (!(newDependencyManaged && configuredToChangeManagedDependency)) { + //If the Version not present and the new version is not managed and/or the changeManagedDependency Option is false. + List md = getResolutionResult().getPom().getDependencyManagement(); + if (configuredToOverrideManageVersion || ((!md.isEmpty() && md.get(0).getRequestedBom() != null) && !newDependencyManaged) || !configuredToChangeManagedDependency) { + //If the version is not present, add the version if we are explicitly overriding a managed version, if no managed version exists with no collection of dependencies or changeManageDependency is false. + Xml.Tag newVersionTag = Xml.Tag.build("" + resolvedNewVersion + ""); + //noinspection ConstantConditions + t = (Xml.Tag) new AddToTagVisitor(t, newVersionTag, new MavenTagInsertionComparator(t.getChildren())).visitNonNull(t, ctx, getCursor().getParent()); + } + + } else if (oldDependencyManaged){ + //If the version is not present and the new and old version are managed, remove the old dependency + doAfterVisit(new RemoveManagedDependency(oldGroupId,oldArtifactId, null).getVisitor()); } } catch (MavenDownloadingException e) { return e.warn(tag); @@ -243,6 +276,17 @@ private boolean isDependencyManaged(Scope scope, String groupId, String artifact return false; } + private boolean isDependencyManaged(String groupId, String artifactId, String version) { + + MavenResolutionResult result = getResolutionResult(); + for (ResolvedManagedDependency managedDependency : result.getPom().getDependencyManagement()) { + if (groupId.equals(managedDependency.getGroupId()) && artifactId.equals(managedDependency.getArtifactId()) && version.equals(managedDependency.getVersion())) { + return true; + } + } + return false; + } + @SuppressWarnings("ConstantConditions") private String resolveSemverVersion(ExecutionContext ctx, String groupId, String artifactId, @Nullable String currentVersion) throws MavenDownloadingException { if (versionComparator == null) { diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactId.java b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactId.java index 19c6744d118..6b54dceb2e6 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactId.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactId.java @@ -72,29 +72,36 @@ public class ChangeManagedDependencyGroupIdAndArtifactId extends Recipe { @Option(displayName = "Version pattern", description = "Allows version selection to be extended beyond the original Node Semver semantics. So for example," + - "Setting 'version' to \"25-29\" can be paired with a metadata pattern of \"-jre\" to select Guava 29.0-jre", + "Setting 'version' to \"25-29\" can be paired with a metadata pattern of \"-jre\" to select Guava 29.0-jre", example = "-jre", required = false) @Nullable String versionPattern; + @Option(displayName = "Change property version names", + description = "Allows property version names to be changed to best practice naming convention", + example = "-jre", + required = false) + @Nullable + Boolean changePropertyVersionNames; + public ChangeManagedDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifactId, String newGroupId, String newArtifactId, @Nullable String newVersion) { - this.oldGroupId = oldGroupId; - this.oldArtifactId = oldArtifactId; - this.newGroupId = newGroupId; - this.newArtifactId = newArtifactId; - this.newVersion = newVersion; - this.versionPattern = null; + this(oldGroupId, oldArtifactId, newGroupId, newArtifactId, newVersion, null, false); } - @JsonCreator public ChangeManagedDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifactId, String newGroupId, String newArtifactId, @Nullable String newVersion, @Nullable String versionPattern) { + this(oldGroupId, oldArtifactId, newGroupId, newArtifactId, newVersion, versionPattern, false); + } + + @JsonCreator + public ChangeManagedDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifactId, String newGroupId, String newArtifactId, @Nullable String newVersion, @Nullable String versionPattern, @Nullable Boolean changePropertyVersionNames) { this.oldGroupId = oldGroupId; this.oldArtifactId = oldArtifactId; this.newGroupId = newGroupId; this.newArtifactId = newArtifactId; this.newVersion = newVersion; this.versionPattern = versionPattern; + this.changePropertyVersionNames = changePropertyVersionNames; } @Override @@ -156,8 +163,21 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { Optional versionTag = t.getChild("version"); if (versionTag.isPresent()) { - String resolvedNewVersion = resolveSemverVersion(ctx, newGroupId, newArtifactId, versionTag.get().getValue().orElse(null)); - t = (Xml.Tag) new ChangeTagValueVisitor<>(versionTag.get(), resolvedNewVersion).visitNonNull(t, 0, getCursor().getParentOrThrow()); + String version = versionTag.get().getValue().orElse(null); + String resolvedNewVersion = resolveSemverVersion(ctx, newGroupId, newArtifactId, version); + if (Objects.requireNonNull(version).contains("$")) { + String propertyVariable = version.substring(2, version.length() - 1); + String newPropertyVariable = propertyVariable; + if (Boolean.TRUE.equals(changePropertyVersionNames)){ + newPropertyVariable = newArtifactId + ".version"; + doAfterVisit(new RenamePropertyKey(propertyVariable, newPropertyVariable).getVisitor()); + t = changeChildTagValue(t, "version", "${"+newPropertyVariable+"}", ctx); + } + doAfterVisit(new ChangePropertyValue(newPropertyVariable, resolvedNewVersion, false, false).getVisitor()); + } else { + t = changeChildTagValue(t, "version", resolvedNewVersion, ctx); + } + } changed = true; } catch(MavenDownloadingException e) { @@ -172,8 +192,21 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { return t; } + private Xml.Tag changeChildTagValue(Xml.Tag tag, String childTagName, String newValue, ExecutionContext ctx) { + Optional childTag = tag.getChild(childTagName); + if (childTag.isPresent() && !newValue.equals(childTag.get().getValue().orElse(null))) { + tag = (Xml.Tag) new ChangeTagValueVisitor<>(childTag.get(), newValue).visitNonNull(tag, ctx); + } + return tag; + } + @SuppressWarnings("ConstantConditions") private String resolveSemverVersion(ExecutionContext ctx, String groupId, String artifactId, @Nullable String currentVersion) throws MavenDownloadingException { + if (currentVersion.contains("$")){ + String propertyVariable = currentVersion.substring(2, currentVersion.length() - 1); + currentVersion = getResolutionResult().getPom().getProperties().get(propertyVariable); + } + if (versionComparator == null) { return newVersion; } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java index c161d490a51..4980351bc11 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java @@ -1194,6 +1194,73 @@ void changeGroupIdOnWildcardArtifacts() { ); } + @Test + void removeUnusedDependencyInManagedDependency() { + rewriteRun( + spec -> spec.recipe(new ChangeDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0", + null + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + javax.activation + javax.activation-api + 1.2.0 + + + jakarta.activation + jakarta.activation-api + 2.1.0 + + + + + + javax.activation + javax.activation-api + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + jakarta.activation + jakarta.activation-api + 2.1.0 + + + + + + jakarta.activation + jakarta.activation-api + + + + """ + ) + ); + } + @Test void changeProfileDependencyGroupIdAndArtifactId() { rewriteRun( @@ -1247,4 +1314,275 @@ void changeProfileDependencyGroupIdAndArtifactId() { ) ); } + + @Test + void changePropertyVersionProfileManagedDependency() { + rewriteRun( + spec -> spec.recipe(new ChangeDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0", + null + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 1.2.0 + + + + test + + + + javax.activation + javax.activation-api + ${javax.activation.version} + + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 2.1.0 + + + + test + + + + jakarta.activation + jakarta.activation-api + ${javax.activation.version} + + + + + + + """ + ) + ); + } + + @Test + void changePropertyVersionManagedDependency() { + rewriteRun( + spec -> spec.recipe(new ChangeDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0", + null + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 1.2.0 + + + + + javax.activation + javax.activation-api + ${javax.activation.version} + + + + + + test + + + javax.activation + javax.activation-api + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 2.1.0 + + + + + jakarta.activation + jakarta.activation-api + ${javax.activation.version} + + + + + + test + + + jakarta.activation + jakarta.activation-api + + + + + + """ + ) + ); + } + + @Test + void changePropertyVersionProfileDependency() { + rewriteRun( + spec -> spec.recipe(new ChangeDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0", + null + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 1.2.0 + + + + test + + + javax.activation + javax.activation-api + ${javax.activation.version} + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 2.1.0 + + + + test + + + jakarta.activation + jakarta.activation-api + ${javax.activation.version} + + + + + + """ + ) + ); + } + + @Test + void changePropertyVersionProfileDependencyWithChangePropertyNamesFalse() { + rewriteRun( + spec -> spec.recipe(new ChangeDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0", + null, + false, + true, + false + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 1.2.0 + + + + test + + + javax.activation + javax.activation-api + ${javax.activation.version} + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 2.1.0 + + + + test + + + jakarta.activation + jakarta.activation-api + ${javax.activation.version} + + + + + + """ + ) + ); + } } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactIdTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactIdTest.java index b1458dda26d..05a5e49ea19 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactIdTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeManagedDependencyGroupIdAndArtifactIdTest.java @@ -177,6 +177,61 @@ void latestPatchMangedDependency() { ); } + @Test + void changePropertyVersionManagedDependency() { + rewriteRun( + spec -> spec.recipe(new ChangeManagedDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0" + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 1.2.0 + + + + + javax.activation + javax.activation-api + ${javax.activation.version} + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 2.1.0 + + + + + jakarta.activation + jakarta.activation-api + ${javax.activation.version} + + + + + """ + ) + ); + } + @Test void changeProfileManagedDependencyGroupIdAndArtifactId() { rewriteRun( @@ -233,4 +288,136 @@ void changeProfileManagedDependencyGroupIdAndArtifactId() { ) ); } + + @Test + void changePropertyVersionProfileManagedDependency() { + rewriteRun( + spec -> spec.recipe(new ChangeManagedDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0" + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 1.2.0 + + + + test + + + + javax.activation + javax.activation-api + ${javax.activation.version} + + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 2.1.0 + + + + test + + + + jakarta.activation + jakarta.activation-api + ${javax.activation.version} + + + + + + + """ + ) + ); + } + + @Test + void changePropertyVersionProfileManagedDependencyWithChangePropertyVersionName() { + rewriteRun( + spec -> spec.recipe(new ChangeManagedDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "2.1.0", + null, + false + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 1.2.0 + + + + test + + + + javax.activation + javax.activation-api + ${javax.activation.version} + + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 2.1.0 + + + + test + + + + jakarta.activation + jakarta.activation-api + ${javax.activation.version} + + + + + + + """ + ) + ); + } }