Skip to content

Commit 5d50af2

Browse files
lkerfordgithub-actions[bot]timtebeek
authored
Adding recipe to return minimum JUnit version (#139)
* Adding recipe to return minimum JUnit version * Update src/main/java/org/openrewrite/java/dependencies/search/FindMinimumDependencyVersion.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Apply suggestions from code review * Extract a common method to find groupId/artifactId version * Separate Maven and Gradle tests into nested classes * updating the description --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek <[email protected]>
1 parent 1e6a3a2 commit 5d50af2

File tree

3 files changed

+683
-0
lines changed

3 files changed

+683
-0
lines changed

src/main/java/org/openrewrite/java/dependencies/search/FindMinimumDependencyVersion.java

+4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ public TreeVisitor<?, ExecutionContext> getVisitor(Map<GroupArtifact, ResolvedGr
125125

126126
acc.entrySet().removeIf(e -> !e.getValue().getVersion().equals(minimumVersion));
127127

128+
return applyMarkersForLocatedGavs(acc, dependenciesInUse);
129+
}
130+
131+
static TreeVisitor<?, ExecutionContext> applyMarkersForLocatedGavs(Map<GroupArtifact, ResolvedGroupArtifactVersion> acc, DependenciesInUse dependenciesInUse) {
128132
return Preconditions.check(Preconditions.or(new IsBuildGradle<>(), new FindMavenProject().getVisitor()), new TreeVisitor<Tree, ExecutionContext>() {
129133
@Override
130134
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.dependencies.search;
17+
18+
import lombok.EqualsAndHashCode;
19+
import lombok.Value;
20+
import org.jspecify.annotations.Nullable;
21+
import org.openrewrite.*;
22+
import org.openrewrite.gradle.marker.GradleDependencyConfiguration;
23+
import org.openrewrite.gradle.marker.GradleProject;
24+
import org.openrewrite.internal.StringUtils;
25+
import org.openrewrite.java.dependencies.internal.StaticVersionComparator;
26+
import org.openrewrite.java.dependencies.internal.VersionParser;
27+
import org.openrewrite.marker.Markers;
28+
import org.openrewrite.maven.table.DependenciesInUse;
29+
import org.openrewrite.maven.tree.GroupArtifact;
30+
import org.openrewrite.maven.tree.MavenResolutionResult;
31+
import org.openrewrite.maven.tree.ResolvedDependency;
32+
import org.openrewrite.maven.tree.ResolvedGroupArtifactVersion;
33+
34+
import java.util.HashMap;
35+
import java.util.List;
36+
import java.util.Map;
37+
import java.util.Objects;
38+
39+
import static org.openrewrite.java.dependencies.search.FindMinimumDependencyVersion.applyMarkersForLocatedGavs;
40+
41+
@Value
42+
@EqualsAndHashCode(callSuper = false)
43+
public class FindMinimumJUnitVersion extends ScanningRecipe<Map<GroupArtifact, ResolvedGroupArtifactVersion>> {
44+
transient DependenciesInUse dependenciesInUse = new DependenciesInUse(this);
45+
46+
@Option(displayName = "Version",
47+
description = "Determine if the provided version is the minimum JUnit version. " +
48+
"If both JUnit 4 and JUnit 5 are present, the minimum version is JUnit 4. " +
49+
"If only one version is present, that version is the minimum version.",
50+
example = "4",
51+
valid = {"4", "5"},
52+
required = false)
53+
@Nullable
54+
String minimumVersion;
55+
56+
57+
@Override
58+
public String getDisplayName() {
59+
return "Find minimum JUnit version";
60+
}
61+
62+
@Override
63+
public String getDescription() {
64+
return "A recipe to find the minimum version of JUnit dependencies. " +
65+
"This recipe is designed to return the minimum version of JUnit in a project. " +
66+
"It will search for JUnit 4 and JUnit 5 dependencies in the project. " +
67+
"If both versions are found, it will return the minimum version of JUnit 4.\n" +
68+
"If a minimumVersion is provided, the recipe will search to see if " +
69+
"the minimum version of JUnit used by the project is no lower than the minimumVersion.\n" +
70+
"For example: if the minimumVersion is 4, and the project has JUnit 4.12 and JUnit 5.7, " +
71+
"the recipe will return JUnit 4.12. If the project has only JUnit 5.7, the recipe will return JUnit 5.7.\n" +
72+
"Another example: if the minimumVersion is 5, and the project has JUnit 4.12 and JUnit 5.7, " +
73+
"the recipe will not return any results.";
74+
}
75+
76+
@Override
77+
public Map<GroupArtifact, ResolvedGroupArtifactVersion> getInitialValue(ExecutionContext ctx) {
78+
return new HashMap<>();
79+
}
80+
81+
@Override
82+
public TreeVisitor<?, ExecutionContext> getScanner(Map<GroupArtifact, ResolvedGroupArtifactVersion> acc) {
83+
return new TreeVisitor<Tree, ExecutionContext>() {
84+
@Override
85+
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
86+
if (tree == null) {
87+
return null;
88+
}
89+
VersionParser versionParser = new VersionParser();
90+
Markers m = tree.getMarkers();
91+
m.findFirst(GradleProject.class).ifPresent(gradle -> {
92+
for (GradleDependencyConfiguration conf : gradle.getConfigurations()) {
93+
collectionJUnit4(versionParser, conf.getResolved(), acc);
94+
collectionJUnit5(versionParser, conf.getResolved(), acc);
95+
}
96+
});
97+
m.findFirst(MavenResolutionResult.class).ifPresent(maven -> {
98+
for (List<ResolvedDependency> resolved : maven.getDependencies().values()) {
99+
collectionJUnit4(versionParser, resolved, acc);
100+
collectionJUnit5(versionParser, resolved, acc);
101+
}
102+
});
103+
return tree;
104+
}
105+
};
106+
}
107+
108+
private boolean isResolvedGroupArtifactVersion(ResolvedGroupArtifactVersion resolvedGroupArtifactVersion, String groupName, String artifactName) {
109+
return resolvedGroupArtifactVersion.getArtifactId().equals(artifactName) &&
110+
resolvedGroupArtifactVersion.getGroupId().equals(groupName);
111+
}
112+
113+
@Override
114+
public TreeVisitor<?, ExecutionContext> getVisitor(Map<GroupArtifact, ResolvedGroupArtifactVersion> acc) {
115+
boolean hasJUnit4 = acc.values().stream().anyMatch(resolvedGroupArtifactVersion -> isResolvedGroupArtifactVersion(resolvedGroupArtifactVersion, "junit", "junit"));
116+
boolean hasJUnit5 = acc.values().stream().anyMatch(resolvedGroupArtifactVersion -> isResolvedGroupArtifactVersion(resolvedGroupArtifactVersion, "org.junit.jupiter", "junit-jupiter-api"));
117+
if (Objects.equals(minimumVersion, "4")) {
118+
if (hasJUnit4) {
119+
acc.entrySet().removeIf(e -> !isResolvedGroupArtifactVersion(e.getValue(), "junit", "junit"));
120+
} else {
121+
return TreeVisitor.noop();
122+
}
123+
} else if (Objects.equals(minimumVersion, "5")) {
124+
if (hasJUnit4) {
125+
return TreeVisitor.noop();
126+
} else {
127+
acc.entrySet().removeIf(e -> !isResolvedGroupArtifactVersion(e.getValue(), "org.junit.jupiter", "junit-jupiter-api"));
128+
}
129+
} else {
130+
if (hasJUnit4 && hasJUnit5) {
131+
acc.entrySet().removeIf(e -> !isResolvedGroupArtifactVersion(e.getValue(), "junit", "junit"));
132+
}
133+
}
134+
135+
return applyMarkersForLocatedGavs(acc, dependenciesInUse);
136+
}
137+
138+
private void collectionJUnit4(VersionParser versionParser, List<ResolvedDependency> resolved,
139+
Map<GroupArtifact, ResolvedGroupArtifactVersion> acc) {
140+
collectVersion(versionParser, resolved, "junit", "junit", acc);
141+
}
142+
143+
private void collectionJUnit5(VersionParser versionParser, List<ResolvedDependency> resolved,
144+
Map<GroupArtifact, ResolvedGroupArtifactVersion> acc) {
145+
collectVersion(versionParser, resolved, "org.junit.jupiter", "junit-jupiter-api", acc);
146+
}
147+
148+
private static void collectVersion(VersionParser versionParser, List<ResolvedDependency> resolved, String groupIdPattern, String artifactIdPattern, Map<GroupArtifact, ResolvedGroupArtifactVersion> acc) {
149+
StaticVersionComparator versionComparator = new StaticVersionComparator();
150+
for (ResolvedDependency dep : resolved) {
151+
if (StringUtils.matchesGlob(dep.getGroupId(), groupIdPattern) &&
152+
StringUtils.matchesGlob(dep.getArtifactId(), artifactIdPattern)) {
153+
acc.merge(new GroupArtifact(dep.getGroupId(), dep.getArtifactId()),
154+
dep.getGav(), (d1, d2) -> versionComparator.compare(
155+
versionParser.transform(d1.getVersion()),
156+
versionParser.transform(d2.getVersion())) < 0 ?
157+
d1 : d2);
158+
}
159+
}
160+
}
161+
}

0 commit comments

Comments
 (0)