All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openrewrite.maven.ChangeManagedDependencyGroupIdAndArtifactId Maven / Gradle / Ivy

There is a newer version: 8.40.3
Show newest version
/*
 * Copyright 2022 the original author or authors.
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* https://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openrewrite.maven; import com.fasterxml.jackson.annotation.JsonCreator; import lombok.EqualsAndHashCode; import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.maven.table.MavenMetadataFailures; import org.openrewrite.maven.tree.MavenMetadata; import org.openrewrite.semver.Semver; import org.openrewrite.semver.VersionComparator; import org.openrewrite.xml.ChangeTagValueVisitor; import org.openrewrite.xml.tree.Xml; import java.util.*; import static org.openrewrite.Validated.test; import static org.openrewrite.internal.StringUtils.isBlank; @Value @EqualsAndHashCode(callSuper = false) public class ChangeManagedDependencyGroupIdAndArtifactId extends Recipe { @EqualsAndHashCode.Exclude MavenMetadataFailures metadataFailures = new MavenMetadataFailures(this); // there are several implicitly defined version properties that we should never attempt to update private static final Set implicitlyDefinedVersionProperties = new HashSet<>(Arrays.asList( "${version}", "${project.version}", "${pom.version}", "${project.parent.version}" )); @Option(displayName = "Old groupId", description = "The old groupId to replace. The groupId is the first part of a managed dependency coordinate `com.google.guava:guava:VERSION`.", example = "org.openrewrite.recipe") String oldGroupId; @Option(displayName = "Old artifactId", description = "The old artifactId to replace. The artifactId is the second part of a managed dependency coordinate `com.google.guava:guava:VERSION`.", example = "rewrite-testing-frameworks") String oldArtifactId; @Option(displayName = "New groupId", description = "The new groupId to use.", example = "corp.internal.openrewrite.recipe") String newGroupId; @Option(displayName = "New artifactId", description = "The new artifactId to use.", example = "rewrite-testing-frameworks") String newArtifactId; @Option(displayName = "New version", description = "The new version to use.", example = "2.0.0", required = false) @Nullable String newVersion; @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", example = "-jre", required = false) @Nullable String versionPattern; 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; } @JsonCreator public ChangeManagedDependencyGroupIdAndArtifactId(String oldGroupId, String oldArtifactId, String newGroupId, String newArtifactId, @Nullable String newVersion, @Nullable String versionPattern) { this.oldGroupId = oldGroupId; this.oldArtifactId = oldArtifactId; this.newGroupId = newGroupId; this.newArtifactId = newArtifactId; this.newVersion = newVersion; this.versionPattern = versionPattern; } @Override public Validated validate() { Validated validated = super.validate(); if (newVersion != null) { validated = validated.and(Semver.validate(newVersion, versionPattern)); } validated = validated.and(test( "coordinates", "newGroupId OR newArtifactId must be different from before", this, r -> { boolean sameGroupId = isBlank(r.newGroupId) || Objects.equals(r.oldGroupId, r.newGroupId); boolean sameArtifactId = isBlank(r.newArtifactId) || Objects.equals(r.oldArtifactId, r.newArtifactId); return !(sameGroupId && sameArtifactId); } )); return validated; } @Override public String getDisplayName() { return "Change Maven managed dependency groupId, artifactId and optionally the version"; } @Override public String getDescription() { return "Change the groupId, artifactId and optionally the version of a specified Maven managed dependency."; } @Override public TreeVisitor getVisitor() { return new MavenIsoVisitor() { @Nullable final VersionComparator versionComparator = newVersion != null ? Semver.validate(newVersion, versionPattern).getValue() : null; @Nullable private Collection availableVersions; @Override public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { Xml.Tag t = super.visitTag(tag, ctx); if (isManagedDependencyTag(oldGroupId, oldArtifactId)) { Optional groupIdTag = t.getChild("groupId"); boolean changed = false; if (groupIdTag.isPresent() && !newGroupId.equals(groupIdTag.get().getValue().orElse(null))) { doAfterVisit(new ChangeTagValueVisitor<>(groupIdTag.get(), newGroupId)); changed = true; } Optional artifactIdTag = t.getChild("artifactId"); if (artifactIdTag.isPresent() && !newArtifactId.equals(artifactIdTag.get().getValue().orElse(null))) { doAfterVisit(new ChangeTagValueVisitor<>(artifactIdTag.get(), newArtifactId)); changed = true; } if (newVersion != null) { try { 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()); } changed = true; } catch(MavenDownloadingException e) { return e.warn(t); } } if (changed) { maybeUpdateModel(); doAfterVisit(new RemoveRedundantDependencyVersions(null, null, (RemoveRedundantDependencyVersions.Comparator) null, null).getVisitor()); } } return t; } @SuppressWarnings("ConstantConditions") private String resolveSemverVersion(ExecutionContext ctx, String groupId, String artifactId, @Nullable String currentVersion) throws MavenDownloadingException { if (versionComparator == null) { return newVersion; } 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 : Collections.max(availableVersions, versionComparator); } }; } }