Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move markers from gradle tooling model into rewrite-gradle, use org.openrewrite.gradle.toolingapi.Assertions#withToolingApi #4023

Merged
merged 2 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion rewrite-gradle/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ dependencies {
api("org.jetbrains:annotations:latest.release")
compileOnly(project(":rewrite-test"))
implementation(project(":rewrite-properties"))
implementation("org.openrewrite.gradle.tooling:model:$rewriteVersion")

compileOnly("org.codehaus.groovy:groovy:latest.release")
compileOnly(gradleApi())
Expand All @@ -59,6 +58,9 @@ dependencies {
// because gradle-api fatjars this implementation already
exclude("ch.qos.logback", "logback-classic")
}

testImplementation("org.openrewrite.gradle.tooling:model:latest.release")

testImplementation("com.squareup.okhttp3:mockwebserver:4.+")

testRuntimeOnly("org.codehaus.groovy:groovy:latest.release")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import org.openrewrite.maven.internal.MavenPomDownloader;
import org.openrewrite.maven.table.MavenMetadataFailures;
import org.openrewrite.maven.tree.*;
import org.openrewrite.semver.*;
import org.openrewrite.tree.ParseError;

import java.util.*;
Expand Down Expand Up @@ -188,8 +187,8 @@ static G.CompilationUnit addDependency(
}),
newRequested));
if (newGdc.isCanBeResolved() && resolvedGav != null) {
newGdc = newGdc.withResolved(ListUtils.concat(
ListUtils.map(gdc.getResolved(), resolved -> {
newGdc = newGdc.withDirectResolved(ListUtils.concat(
ListUtils.map(gdc.getDirectResolved(), resolved -> {
// Remove any existing dependency with the same group and artifact id
if (Objects.equals(resolved.getGroupId(), resolvedGav.getGroupId()) && Objects.equals(resolved.getArtifactId(), resolvedGav.getArtifactId())) {
return null;
Expand Down Expand Up @@ -231,8 +230,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
resolvedVersion = version;
} else {
try {
resolvedVersion = resolveDependencyVersion(groupId, artifactId, "0", version, versionPattern, gp.getMavenRepositories(), metadataFailures, ctx)
.orElse(null);
resolvedVersion = new DependencyVersionSelector(metadataFailures, gp)
.select(new GroupArtifact(groupId, artifactId), configuration, version, versionPattern, ctx);
} catch (MavenDownloadingException e) {
return e.warn(m);
}
Expand Down Expand Up @@ -365,42 +364,4 @@ private DependencyStyle autodetectDependencyStyle(List<Statement> statements) {

return string >= map ? DependencyStyle.String : DependencyStyle.Map;
}

public static Optional<String> resolveDependencyVersion(String groupId, String artifactId, String currentVersion, @Nullable String newVersion, @Nullable String versionPattern,
List<MavenRepository> repositories, @Nullable MavenMetadataFailures metadataFailures, ExecutionContext ctx) throws MavenDownloadingException {
VersionComparator versionComparator = StringUtils.isBlank(newVersion) ?
new LatestRelease(versionPattern) :
requireNonNull(Semver.validate(newVersion, versionPattern).getValue());

Optional<String> version;
if (versionComparator instanceof ExactVersion) {
version = versionComparator.upgrade(currentVersion, singletonList(newVersion));
} else if (versionComparator instanceof LatestPatch && !versionComparator.isValid(currentVersion, currentVersion)) {
// in the case of "latest.patch", a new version can only be derived if the
// current version is a semantic version
return Optional.empty();
} else {
version = findNewerVersion(groupId, artifactId, currentVersion, versionComparator, repositories, metadataFailures, ctx);
}
return version;
}

private static Optional<String> findNewerVersion(String groupId, String artifactId, String version, VersionComparator versionComparator,
List<MavenRepository> repositories, @Nullable MavenMetadataFailures metadataFailures, ExecutionContext ctx) throws MavenDownloadingException {
try {
MavenMetadata mavenMetadata = metadataFailures == null ?
downloadMetadata(groupId, artifactId, repositories, ctx) :
metadataFailures.insertRows(ctx, () -> downloadMetadata(groupId, artifactId, repositories, ctx));
return versionComparator.upgrade(version, mavenMetadata.getVersioning().getVersions());
} catch (IllegalStateException e) {
// this can happen when we encounter exotic versions
return Optional.empty();
}
}

private static MavenMetadata downloadMetadata(String groupId, String artifactId, List<MavenRepository> repositories, ExecutionContext ctx) throws MavenDownloadingException {
return new MavenPomDownloader(ctx)
.downloadMetadata(new GroupArtifact(groupId, artifactId), null,
repositories);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.gradle;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.*;
import org.openrewrite.gradle.marker.GradleDependencyConfiguration;
import org.openrewrite.gradle.marker.GradleProject;
import org.openrewrite.gradle.search.FindGradleProject;
import org.openrewrite.groovy.GroovyVisitor;
import org.openrewrite.groovy.tree.G;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.tree.J;
import org.openrewrite.marker.Markup;
import org.openrewrite.maven.MavenDownloadingException;
import org.openrewrite.maven.table.MavenMetadataFailures;
import org.openrewrite.maven.tree.GroupArtifact;
import org.openrewrite.maven.tree.ResolvedDependency;
import org.openrewrite.semver.DependencyMatcher;
import org.openrewrite.semver.Semver;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;

@Value
@EqualsAndHashCode(callSuper = false)
public class AddDirectDependencyToUpgradeTransitiveVersion extends Recipe {

@EqualsAndHashCode.Exclude
transient MavenMetadataFailures metadataFailures = new MavenMetadataFailures(this);

@Option(displayName = "Group",
description = "The first part of a dependency coordinate `com.google.guava:guava:VERSION`. This can be a glob expression.",
example = "com.fasterxml.jackson*")
String groupId;

@Option(displayName = "Artifact",
description = "The second part of a dependency coordinate `com.google.guava:guava:VERSION`. This can be a glob expression.",
example = "jackson-module*")
String artifactId;

@Option(displayName = "Version",
description = "An exact version number or node-style semver selector used to select the version number. " +
"You can also use `latest.release` for the latest available version and `latest.patch` if " +
"the current version is a valid semantic version. For more details, you can look at the documentation " +
"page of [version selectors](https://docs.openrewrite.org/reference/dependency-version-selectors). " +
"Defaults to `latest.release`.",
example = "29.X",
required = false)
@Nullable
String version;

@Option(displayName = "Version pattern",
description = "Allows version selection to be extended beyond the original Node Semver semantics. So for example," +
"Setting 'newVersion' 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;

@Override
public String getDisplayName() {
return "Upgrade transitive Gradle dependencies";
}

@Override
public String getDescription() {
return "Upgrades the version of a transitive dependency in a Gradle build file. " +
"There are many ways to do this in Gradle, so the mechanism for upgrading a " +
"transitive dependency must be considered carefully depending on your style " +
"of dependency management.";
}

@Override
public Validated<Object> validate() {
Validated<Object> validated = super.validate();
if (version != null) {
validated = validated.and(Semver.validate(version, versionPattern));
}
return validated;
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
DependencyMatcher dependencyMatcher = new DependencyMatcher(groupId, artifactId, null);
return Preconditions.check(new FindGradleProject(FindGradleProject.SearchCriteria.Marker), new GroovyVisitor<ExecutionContext>() {
GradleProject gradleProject;

@Override
public J visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) {
gradleProject = cu.getMarkers().findFirst(GradleProject.class)
.orElseThrow(() -> new IllegalStateException("Unable to find GradleProject marker."));

Map<GroupArtifact, List<GradleDependencyConfiguration>> toUpdate = new HashMap<>();

DependencyVersionSelector versionSelector = new DependencyVersionSelector(metadataFailures, gradleProject);
for (GradleDependencyConfiguration configuration : gradleProject.getConfigurations()) {
for (ResolvedDependency resolvedDependency : configuration.getResolved()) {
if (resolvedDependency.getDepth() > 0 &&
dependencyMatcher.matches(resolvedDependency.getGroupId(), resolvedDependency.getArtifactId(), resolvedDependency.getVersion())) {

try {
String selected = versionSelector.select(resolvedDependency.getGav(), configuration.getName(),
version, versionPattern, ctx);
if (!resolvedDependency.getVersion().equals(selected)) {
toUpdate.merge(new GroupArtifact(groupId, artifactId), singletonList(configuration), (existing, update) -> {
List<GradleDependencyConfiguration> all = ListUtils.concatAll(existing, update);
all.removeIf(c -> {
for (GradleDependencyConfiguration config : all) {
if (c.allExtendsFrom().contains(config)) {
return true;
}
}
return false;
});
return all;
});
}
} catch (MavenDownloadingException e) {
return Markup.warn(cu, e);
}
}
}
}

return super.visitCompilationUnit(cu, ctx);
}
});
}
}
Loading