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 15e730d75e..0c66b22567 100755 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java @@ -28,6 +28,7 @@ import org.openrewrite.xml.RemoveContentVisitor; import org.openrewrite.xml.tree.Xml; +import java.nio.file.Path; import java.util.*; import static java.util.Collections.max; @@ -37,7 +38,7 @@ @Value @EqualsAndHashCode(callSuper = false) -public class ChangeDependencyGroupIdAndArtifactId extends Recipe { +public class ChangeDependencyGroupIdAndArtifactId extends ScanningRecipe { transient MavenMetadataFailures metadataFailures = new MavenMetadataFailures(this); @Option(displayName = "Old groupId", @@ -143,25 +144,19 @@ public Validated validate() { } @Override - public TreeVisitor getVisitor() { + public Accumulator getInitialValue(ExecutionContext ctx) { + return new Accumulator(); + } + + @Override + public TreeVisitor getScanner(Accumulator acc) { return new MavenVisitor() { - @Nullable - final VersionComparator versionComparator = newVersion != null ? Semver.validate(newVersion, versionPattern).getValue() : null; - @Nullable - private Collection availableVersions; + final @Nullable VersionComparator versionComparator = newVersion != null ? Semver.validate(newVersion, versionPattern).getValue() : null; private boolean isNewDependencyPresent; @Override public Xml visitDocument(Xml.Document document, ExecutionContext ctx) { isNewDependencyPresent = checkIfNewDependencyPresents(newGroupId, newArtifactId, newVersion); - // Any managed dependency change is unlikely to use the same version, so only update selectively. - if ((changeManagedDependency == null || changeManagedDependency) && newVersion != null || versionPattern != null) { - doAfterVisit(new ChangeManagedDependencyGroupIdAndArtifactId( - oldGroupId, oldArtifactId, - Optional.ofNullable(newGroupId).orElse(oldGroupId), - Optional.ofNullable(newArtifactId).orElse(oldArtifactId), - newVersion, versionPattern).getVisitor()); - } return super.visitDocument(document, ctx); } @@ -170,58 +165,59 @@ public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { Xml.Tag t = (Xml.Tag) super.visitTag(tag, ctx); boolean isOldDependencyTag = isDependencyTag(oldGroupId, oldArtifactId); if (isOldDependencyTag && isNewDependencyPresent) { - doAfterVisit(new RemoveContentVisitor<>(tag, true, true)); - maybeUpdateModel(); + acc.isNewDependencyPresent = true; return t; } if (isOldDependencyTag || isPluginDependencyTag(oldGroupId, oldArtifactId)) { - String groupId = newGroupId; - if (groupId != null) { - t = changeChildTagValue(t, "groupId", groupId, ctx); - } else { - groupId = t.getChildValue("groupId").orElseThrow(NoSuchElementException::new); + Optional groupIdFromTag = t.getChildValue("groupId"); + Optional artifactIdFromTag = t.getChildValue("artifactId"); + if (!groupIdFromTag.isPresent() || !artifactIdFromTag.isPresent()) { + return t; } - String artifactId = newArtifactId; - if (artifactId != null) { - t = changeChildTagValue(t, "artifactId", artifactId, ctx); - } else { - artifactId = t.getChildValue("artifactId").orElseThrow(NoSuchElementException::new); + + String groupId = groupIdFromTag.get(); + if (newGroupId != null) { + storeParentPomProperty(groupId, newGroupId); + groupId = newGroupId; + acc.changeGroupId = groupId; + } + + String artifactId = artifactIdFromTag.get(); + if (newArtifactId != null) { + storeParentPomProperty(artifactId, newArtifactId); + artifactId = newArtifactId; + acc.changeArtifactId = artifactId; } - String currentVersion = t.getChildValue("version").orElse(null); + if (newVersion != null) { try { - String resolvedNewVersion = resolveSemverVersion(ctx, groupId, artifactId, currentVersion); - Optional scopeTag = t.getChild("scope"); - Scope scope = scopeTag.map(xml -> Scope.fromName(xml.getValue().orElse("compile"))).orElse(Scope.Compile); + Optional currentVersion = t.getChildValue("version"); + String resolvedNewVersion = resolveSemverVersion(groupId, artifactId, currentVersion.orElse(newVersion), ctx); + Scope scope = t.getChild("scope").map(xml -> Scope.fromName(xml.getValue().orElse(null))).orElse(Scope.Compile); Optional versionTag = t.getChild("version"); boolean configuredToOverrideManageVersion = overrideManagedVersion != null && overrideManagedVersion; // False by default boolean configuredToChangeManagedDependency = changeManagedDependency == null || changeManagedDependency; // True by default - boolean versionTagPresent = versionTag.isPresent(); boolean oldDependencyManaged = isDependencyManaged(scope, oldGroupId, oldArtifactId); boolean newDependencyManaged = isDependencyManaged(scope, groupId, artifactId); - if (versionTagPresent) { + if (versionTag.isPresent()) { // If the previous dependency had a version but the new artifact is managed, removed the version tag. if (!configuredToOverrideManageVersion && newDependencyManaged || (oldDependencyManaged && configuredToChangeManagedDependency)) { - t = (Xml.Tag) new RemoveContentVisitor<>(versionTag.get(), false, true).visit(t, ctx); + acc.removeVersionTag = true; } else { // Otherwise, change the version to the new value. - t = changeChildTagValue(t, "version", resolvedNewVersion, ctx); + storeParentPomProperty(currentVersion.orElse(null), resolvedNewVersion); + acc.changeVersion = resolvedNewVersion; } } 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()); + // If the version is not present, add the version if we are explicitly overriding a managed version or if no managed version exists. + acc.createVersion = resolvedNewVersion; } } catch (MavenDownloadingException e) { return e.warn(tag); } } - if (t != tag) { - maybeUpdateModel(); - } } //noinspection ConstantConditions @@ -249,23 +245,122 @@ private boolean isDependencyManaged(Scope scope, String groupId, String artifact } @SuppressWarnings("ConstantConditions") - private String resolveSemverVersion(ExecutionContext ctx, String groupId, String artifactId, @Nullable String currentVersion) throws MavenDownloadingException { - if (versionComparator == null) { - return newVersion; + private String resolveSemverVersion(String groupId, String artifactId, String version, ExecutionContext ctx) throws MavenDownloadingException { + List availableVersions = new ArrayList<>(); + MavenMetadata mavenMetadata = metadataFailures.insertRows(ctx, () -> downloadMetadata(groupId, artifactId, ctx)); + for (String v : mavenMetadata.getVersioning().getVersions()) { + if (versionComparator.isValid(version, v)) { + availableVersions.add(v); + } } - String finalCurrentVersion = currentVersion != null ? currentVersion : newVersion; - if (availableVersions == null) { - availableVersions = new ArrayList<>(); - MavenMetadata mavenMetadata = metadataFailures.insertRows(ctx, () -> downloadMetadata(groupId, artifactId, ctx)); - for (String v : mavenMetadata.getVersioning().getVersions()) { - if (versionComparator.isValid(finalCurrentVersion, v)) { - availableVersions.add(v); + return availableVersions.isEmpty() ? newVersion : max(availableVersions, versionComparator); + } + + private void storeParentPomProperty(@Nullable String currentValue, String newValue) { + if (isProperty(currentValue)) { + String name = currentValue.substring(2, currentValue.length() - 1).trim(); + if (!getResolutionResult().getPom().getRequested().getProperties().containsKey(name)) { + storeParentPomProperty(getResolutionResult(), name, newValue); + } + } + } + + private void storeParentPomProperty(MavenResolutionResult resolutionResult, String name, String value) { + Pom pom = resolutionResult.getPom().getRequested(); + if (pom.getSourcePath() != null && pom.getProperties().containsKey(name)) { + acc.pomProperties.add(new PomProperty(pom.getSourcePath(), name, value)); + } else if (resolutionResult.getParent() != null) { + storeParentPomProperty(resolutionResult.getParent(), name, value); + } + } + }; + } + + @Override + public TreeVisitor getVisitor(Accumulator acc) { + return new MavenVisitor() { + @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) { + doAfterVisit(new ChangeManagedDependencyGroupIdAndArtifactId( + oldGroupId, oldArtifactId, + Optional.ofNullable(newGroupId).orElse(oldGroupId), + Optional.ofNullable(newArtifactId).orElse(oldArtifactId), + newVersion, versionPattern).getVisitor()); + } + return super.visitDocument(document, ctx); + } + + @Override + public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { + Xml.Tag t = (Xml.Tag) super.visitTag(tag, ctx); + if (isPropertyTag()) { + Path sourcePath = getResolutionResult().getPom().getRequested().getSourcePath(); + for (PomProperty prop : acc.pomProperties) { + if (prop.filePath.equals(sourcePath)) { + doAfterVisit(new ChangePropertyValue(prop.name, prop.value, false, false).getVisitor()); } } + return t; + } + boolean isOldDependencyTag = isDependencyTag(oldGroupId, oldArtifactId); + if (isOldDependencyTag && acc.isNewDependencyPresent) { + doAfterVisit(new RemoveContentVisitor<>(t, true, true)); + maybeUpdateModel(); + return t; } - return availableVersions.isEmpty() ? newVersion : max(availableVersions, versionComparator); + if (isOldDependencyTag || isPluginDependencyTag(oldGroupId, oldArtifactId)) { + if (acc.changeGroupId != null) { + t = changeChildTagValue(t, "groupId", newGroupId, ctx); + } + if (acc.changeArtifactId != null) { + t = changeChildTagValue(t, "artifactId", newArtifactId, ctx); + } + + if (acc.createVersion != null) { + Xml.Tag newVersionTag = Xml.Tag.build("" + acc.createVersion + ""); + t = (Xml.Tag) new AddToTagVisitor(t, newVersionTag, new MavenTagInsertionComparator(t.getChildren())).visitNonNull(t, ctx, getCursor().getParent()); + } else if (acc.changeVersion != null) { + t = changeChildTagValue(t, "version", acc.changeVersion, ctx); + } else if (acc.removeVersionTag) { + t = (Xml.Tag) new RemoveContentVisitor<>(t.getChild("version").get(), false, true).visitNonNull(t, ctx); + } + + if (t != tag) { + maybeUpdateModel(); + } + } + + return t; } }; } + + public static class Accumulator { + Set pomProperties = new HashSet<>(); + boolean isNewDependencyPresent; + + @Nullable + String changeGroupId; + + @Nullable + String changeArtifactId; + + boolean removeVersionTag; + + @Nullable + String createVersion; + + @Nullable + String changeVersion; + } + + @Value + public static class PomProperty { + Path filePath; + String name; + String value; + } } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenVisitor.java b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenVisitor.java index 166831c4b9..53ee6fd632 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenVisitor.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenVisitor.java @@ -15,6 +15,7 @@ */ package org.openrewrite.maven; +import org.jetbrains.annotations.Contract; import org.jspecify.annotations.Nullable; import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; @@ -281,11 +282,21 @@ private boolean isTag(String name) { return getCursor().getValue() instanceof Xml.Tag && name.equals(getCursor().getValue().getName()); } + /** + * Updates the value of a given child tag within an XML tag, if the new value differs from the current one. + *

+ * If the current value of the tag is a property (e.g. {@code ${some.property}}), and the property is defined + * in the same POM, the method updates the property instead of directly modifying the tag value. + * This method does not update properties defined in a parent POM. + * + * @param tag The XML tag that contains the child tag. + * @param childTagName The name of the child tag whose value should be changed. + * @param newValue The new value to assign to the child tag. If {@code null} or equal to the current value, + * no change is made. + * @param p The visitor context. + * @return The potentially updated tag. + */ protected Xml.Tag changeChildTagValue(Xml.Tag tag, String childTagName, @Nullable String newValue, P p) { - return changeChildTagValue(tag, childTagName, newValue, false, p); - } - - protected Xml.Tag changeChildTagValue(Xml.Tag tag, String childTagName, @Nullable String newValue, @Nullable Boolean addPropertyIfMissing, P p) { Optional childTag = tag.getChild(childTagName); if (childTag.isPresent()) { String oldValue = childTag.get().getValue().orElse(null); @@ -293,7 +304,7 @@ protected Xml.Tag changeChildTagValue(Xml.Tag tag, String childTagName, @Nullabl if (isProperty(oldValue)) { String propertyName = oldValue.substring(2, oldValue.length() - 1); if (getResolutionResult().getPom().getRequested().getProperties().containsKey(propertyName)) { - doAfterVisit((TreeVisitor) new ChangePropertyValue(propertyName, newValue, addPropertyIfMissing, false).getVisitor()); + doAfterVisit((TreeVisitor) new ChangePropertyValue(propertyName, newValue, false, false).getVisitor()); } } else { tag = (Xml.Tag) new ChangeTagValueVisitor<>(childTag.get(), newValue).visitNonNull(tag, p); @@ -303,6 +314,7 @@ protected Xml.Tag changeChildTagValue(Xml.Tag tag, String childTagName, @Nullabl return tag; } + @Contract("null -> false") protected boolean isProperty(@Nullable String value) { return value != null && value.startsWith("${") && !IMPLICITLY_DEFINED_VERSION_PROPERTIES.contains(value); } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeDependencyVersion.java b/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeDependencyVersion.java index 83be12577c..78457c27f2 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeDependencyVersion.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeDependencyVersion.java @@ -32,7 +32,6 @@ import java.nio.file.Path; import java.util.*; -import static java.util.Collections.emptyList; import static java.util.Objects.requireNonNull; import static org.openrewrite.internal.StringUtils.matchesGlob; @@ -194,24 +193,17 @@ private void storeParentPomProperty(@Nullable MavenResolutionResult currentMaven @Override public TreeVisitor getVisitor(Accumulator accumulator) { return new MavenIsoVisitor() { - private final VersionComparator versionComparator = - requireNonNull(Semver.validate(newVersion, versionPattern).getValue()); + private final VersionComparator versionComparator = requireNonNull(Semver.validate(newVersion, versionPattern).getValue()); @Override public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { Xml.Tag t = super.visitTag(tag, ctx); try { if (isPropertyTag()) { - Path pomSourcePath = getResolutionResult().getPom().getRequested().getSourcePath(); - for (PomProperty pomProperty : accumulator.pomProperties) { - if (pomProperty.pomFilePath.equals(pomSourcePath) && - pomProperty.propertyName.equals(tag.getName())) { - Optional value = tag.getValue(); - if (!value.isPresent() || !value.get().equals(pomProperty.propertyValue)) { - doAfterVisit(new ChangeTagValueVisitor<>(tag, pomProperty.propertyValue)); - maybeUpdateModel(); - } - break; + Path sourcePath = getResolutionResult().getPom().getRequested().getSourcePath(); + for (PomProperty prop : accumulator.pomProperties) { + if (prop.filePath.equals(sourcePath)) { + doAfterVisit(new ChangePropertyValue(prop.name, prop.value, false, false).getVisitor()); } } } else if (isDependencyTag(groupId, artifactId)) { @@ -249,7 +241,7 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { if (isManagedDependencyImportTag(groupId, artifactId)) { TreeVisitor upgradeManagedDependency = upgradeManagedDependency(tag, ctx, t); if (upgradeManagedDependency != null) { - retainVersions(); + RetainVersions.plan(this, retainVersions).forEach(this::doAfterVisit); doAfterVisit(new RemoveRedundantDependencyVersions(null, null, null, retainVersions).getVisitor()); doAfterVisit(upgradeManagedDependency); maybeUpdateModel(); @@ -261,11 +253,6 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { } return t; } - - private void retainVersions() { - RetainVersions.plan(this, retainVersions == null ? emptyList() : retainVersions) - .forEach(it -> doAfterVisit(it.getVisitor())); - } } private Xml.Tag upgradeDependency(ExecutionContext ctx, Xml.Tag t) throws MavenDownloadingException { @@ -276,7 +263,7 @@ private Xml.Tag upgradeDependency(ExecutionContext ctx, Xml.Tag t) throws MavenD String newerVersion = findNewerVersion(d.getGroupId(), d.getArtifactId(), d.getVersion(), ctx); if (newerVersion != null) { if (t.getChild("version").isPresent()) { - t = changeChildTagValue(t, "version", newerVersion, overrideManagedVersion, ctx); + t = changeChildTagValue(t, "version", newerVersion, ctx); } else if (Boolean.TRUE.equals(overrideManagedVersion)) { ResolvedManagedDependency dm = findManagedDependency(t); // if a managed dependency is expressed as a property, change the property value @@ -337,7 +324,7 @@ private Xml.Tag upgradePluginDependency(ExecutionContext ctx, Xml.Tag t) throws if (groupId != null && artifactId != null && version != null) { String newerVersion = findNewerVersion(groupId, artifactId, resolveVersion(version), ctx); if (newerVersion != null) { - t = changeChildTagValue(t, "version", newerVersion, overrideManagedVersion, ctx); + t = changeChildTagValue(t, "version", newerVersion, ctx); } } return t; @@ -385,8 +372,8 @@ public static class Accumulator { @Value public static class PomProperty { - Path pomFilePath; - String propertyName; - String propertyValue; + Path filePath; + String name; + String value; } } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/RetainVersions.java b/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/RetainVersions.java index 1e99e02dec..f34bbc4a4b 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/RetainVersions.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/RetainVersions.java @@ -15,7 +15,10 @@ */ package org.openrewrite.maven.utilities; -import org.openrewrite.Recipe; +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.TreeVisitor; import org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId; import org.openrewrite.maven.MavenVisitor; import org.openrewrite.maven.search.FindDependency; @@ -31,51 +34,51 @@ public class RetainVersions { /** - * Returns a list of recipes which can be applied to add explicit versions + * Returns a list of visitors which can be applied to add explicit versions * for dependencies matching the GAVs in param `retainVersions` */ - public static List plan(MavenVisitor visitor, List retainVersions) { - List recipes = new ArrayList<>(); - for (String gav : retainVersions) { - String[] split = gav.split(":"); - String requestedRetainedGroupId = split[0]; - String requestedRetainedArtifactId = split[1]; - String requestedRetainedVersion = split.length == 3 ? split[2] : null; - Set existingDependencies = FindDependency.find( - visitor.getCursor().firstEnclosingOrThrow(Xml.Document.class), - requestedRetainedGroupId, requestedRetainedArtifactId); + public static List> plan(MavenVisitor visitor, @Nullable List retainVersions) { + List> visitors = new ArrayList<>(); + if (retainVersions != null) { + for (String gav : retainVersions) { + String[] split = gav.split(":"); + String requestedRetainedGroupId = split[0]; + String requestedRetainedArtifactId = split[1]; + String requestedRetainedVersion = split.length == 3 ? split[2] : null; + Set existingDependencies = FindDependency.find( + visitor.getCursor().firstEnclosingOrThrow(Xml.Document.class), + requestedRetainedGroupId, requestedRetainedArtifactId); - // optimization for glob GAVs: more efficient to use one CDGIAAI recipe if they all will have the same version anyway - if (requestedRetainedVersion != null && noneMatch(existingDependencies, it -> it.getChild("version").isPresent())) { - recipes.add(new ChangeDependencyGroupIdAndArtifactId(requestedRetainedGroupId, requestedRetainedArtifactId, null, null, - requestedRetainedVersion, null, true, true)); - continue; - } + // optimization for glob GAVs: more efficient to use one CDGIAAI recipe if they all will have the same version anyway + if (requestedRetainedVersion != null && noneMatch(existingDependencies, it -> it.getChild("version").isPresent())) { + visitors.add(changeDependencyGroupIdAndArtifactId(visitor, requestedRetainedGroupId, requestedRetainedArtifactId, requestedRetainedVersion)); + continue; + } - for (Xml.Tag existingDependency : existingDependencies) { - String retainedGroupId = existingDependency.getChildValue("groupId") - .orElseThrow(() -> new IllegalStateException("Dependency tag must have groupId")); - String retainedArtifactId = existingDependency.getChildValue("artifactId") - .orElseThrow(() -> new IllegalStateException("Dependency tag must have artifactId")); - String retainedVersion = requestedRetainedVersion; + for (Xml.Tag existingDependency : existingDependencies) { + String retainedGroupId = existingDependency.getChildValue("groupId") + .orElseThrow(() -> new IllegalStateException("Dependency tag must have groupId")); + String retainedArtifactId = existingDependency.getChildValue("artifactId") + .orElseThrow(() -> new IllegalStateException("Dependency tag must have artifactId")); + String retainedVersion = requestedRetainedVersion; - if (retainedVersion == null) { - if (existingDependency.getChildValue("version").isPresent()) { - continue; - } else { - ResolvedManagedDependency managedDependency = visitor.findManagedDependency( - retainedGroupId, retainedArtifactId); - retainedVersion = Objects.requireNonNull(managedDependency, String.format( - "'%s' from 'retainVersions' did not have a version specified and was not in the project's dependency management", - gav)).getVersion(); + if (retainedVersion == null) { + if (existingDependency.getChildValue("version").isPresent()) { + continue; + } else { + ResolvedManagedDependency managedDependency = visitor.findManagedDependency( + retainedGroupId, retainedArtifactId); + retainedVersion = Objects.requireNonNull(managedDependency, String.format( + "'%s' from 'retainVersions' did not have a version specified and was not in the project's dependency management", + gav)).getVersion(); + } } + visitors.add(changeDependencyGroupIdAndArtifactId(visitor, retainedGroupId, retainedArtifactId, retainedVersion)); } - recipes.add(new ChangeDependencyGroupIdAndArtifactId(retainedGroupId, retainedArtifactId, null, null, - retainedVersion, null, true, true)); } } - return recipes; + return visitors; } private static boolean noneMatch(Set existingDependencies, Predicate predicate) { @@ -86,4 +89,13 @@ private static boolean noneMatch(Set existingDependencies, Predicate p } return true; } + + private static TreeVisitor changeDependencyGroupIdAndArtifactId(MavenVisitor visitor, String oldGroupId, String oldArtifactId, String newVersion) { + ChangeDependencyGroupIdAndArtifactId recipe = + new ChangeDependencyGroupIdAndArtifactId(oldGroupId, oldArtifactId, null, null, newVersion, null, true, true); + InMemoryExecutionContext ctx = new InMemoryExecutionContext(); + ChangeDependencyGroupIdAndArtifactId.Accumulator accumulator = recipe.getInitialValue(ctx); + recipe.getScanner(accumulator).visit(visitor.getCursor().firstEnclosingOrThrow(Xml.Document.class), ctx); + return recipe.getVisitor(accumulator); + } } 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 381e7f95fc..082665d775 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java @@ -1628,55 +1628,53 @@ void changePluginDependencyGroupIdAndArtifactId() { )), pomXml( """ - - 4.0.0 - com.mycompany.app - my-app - 1 - - - - - com.mycompany.myplugin - my-plugin - 1.0.0 - - - javax.activation - javax.activation-api - 1.2.0 - - - - - - - """, - """ - - 4.0.0 - com.mycompany.app - my-app - 1 - - - - - com.mycompany.myplugin - my-plugin - 1.0.0 - - - jakarta.activation - jakarta.activation-api - 1.2.0 - - - - - - + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + com.mycompany.myplugin + my-plugin + 1.0.0 + + + javax.activation + javax.activation-api + 1.2.0 + + + + + + + """, """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + com.mycompany.myplugin + my-plugin + 1.0.0 + + + jakarta.activation + jakarta.activation-api + 1.2.0 + + + + + + + """ ) ); } @@ -1732,4 +1730,75 @@ void changeDependencyGroupIdAndArtifactIdWithVersionProperty() { ) ); } + + @Test + void changeVersionPropertyInParentPom() { + rewriteRun( + spec -> spec.recipe(new ChangeDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + "1.2.x", + null + )), + //language=xml + pomXml( + """ + + com.mycompany.app + parent-project + 1 + + javax.activation + javax.activation-api + 1.2.0 + + + sub-project + + + """, + """ + + com.mycompany.app + parent-project + 1 + + jakarta.activation + jakarta.activation-api + 1.2.2 + + + sub-project + + + """ + ), + //language=xml + pomXml( + """ + + com.mycompany.app + sub-project + 1 + + com.mycompany.app + parent-project + 1 + ../pom.xml + + + + ${activation.api.groupId} + ${activation.api.artifact} + ${activation.api.version} + + + + """, + spec -> spec.path("sub-project/pom.xml") + ) + ); + } }