Skip to content

Commit 49e4463

Browse files
authored
Add DependencyPluginGoalResolveSources recipe for Maven (#5338)
* Add `DependencyPluginGoalResolveSources` recipe for Maven * Rename test class to match * Add a test for missing plugin version * Match managed dependency version through `MavenResolutionResult` * Add `DependencyPluginGoalResolveSources` to Maven best practices
1 parent 227c1c9 commit 49e4463

4 files changed

Lines changed: 352 additions & 5 deletions

File tree

rewrite-maven/src/main/java/org/openrewrite/maven/MavenVisitor.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,16 @@ public boolean isDependencyLikeTag() {
415415
}
416416

417417
private static @Nullable Plugin findPlugin(Xml.Tag tag, List<Plugin> plugins) {
418+
String tagGroupId = tag.getChildValue("groupId").orElse(PLUGIN_DEFAULT_GROUPID);
419+
String tagArtifactId = tag.getChildValue("artifactId").orElse(null);
420+
String tagVersion = tag.getChildValue("version").orElse(null);
418421
for (Plugin resolvedPlugin : plugins) {
419-
String reqGroup = resolvedPlugin.getGroupId();
420-
String reqVersion = resolvedPlugin.getVersion();
421-
if (reqGroup.equals(tag.getChildValue("groupId").orElse(PLUGIN_DEFAULT_GROUPID)) &&
422-
resolvedPlugin.getArtifactId().equals(tag.getChildValue("artifactId").orElse(null)) &&
423-
(reqVersion == null || reqVersion.equals(tag.getChildValue("version").orElse(null)))) {
422+
String resGroup = resolvedPlugin.getGroupId();
423+
String resArtifactId = resolvedPlugin.getArtifactId();
424+
String resVersion = resolvedPlugin.getVersion();
425+
if (resGroup.equals(tagGroupId) &&
426+
resArtifactId.equals(tagArtifactId) &&
427+
(resVersion == null || tagVersion == null || resVersion.equals(tagVersion))) {
424428
return resolvedPlugin;
425429
}
426430
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2025 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.maven.plugin;
17+
18+
import org.openrewrite.Cursor;
19+
import org.openrewrite.ExecutionContext;
20+
import org.openrewrite.Recipe;
21+
import org.openrewrite.TreeVisitor;
22+
import org.openrewrite.maven.MavenVisitor;
23+
import org.openrewrite.maven.tree.Plugin;
24+
import org.openrewrite.semver.Semver;
25+
import org.openrewrite.semver.VersionComparator;
26+
import org.openrewrite.xml.XPathMatcher;
27+
import org.openrewrite.xml.tree.Xml;
28+
29+
import static java.util.Objects.requireNonNull;
30+
31+
@SuppressWarnings("ALL")
32+
public class DependencyPluginGoalResolveSources extends Recipe {
33+
@Override
34+
public String getDisplayName() {
35+
return "Migrate to `maven-dependency-plugin` goal `resolve-sources`";
36+
}
37+
38+
@Override
39+
public String getDescription() {
40+
return "Migrate from `sources` to `resolve-sources` for the `maven-dependency-plugin`.";
41+
}
42+
43+
private static final XPathMatcher xPathMatcher = new XPathMatcher("//plugin[artifactId='maven-dependency-plugin']/executions/execution/goals[goal='sources']/goal");
44+
private static final String minimumVersion = "3.7.0";
45+
46+
@Override
47+
public TreeVisitor<?, ExecutionContext> getVisitor() {
48+
VersionComparator comparator = requireNonNull(Semver.validate(minimumVersion, null).getValue());
49+
return new MavenVisitor<ExecutionContext>() {
50+
@Override
51+
public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
52+
Xml.Tag t = (Xml.Tag) super.visitTag(tag, ctx);
53+
if (xPathMatcher.matches(getCursor()) && isPlugInVersionInRange()) {
54+
return tag.withValue("resolve-sources");
55+
}
56+
return t;
57+
}
58+
59+
private boolean isPlugInVersionInRange() {
60+
Cursor pluginCursor = getCursor().dropParentUntil(i -> i instanceof Xml.Tag && ((Xml.Tag) i).getName().equals("plugin"));
61+
Xml.Tag pluginTag = pluginCursor.getValue();
62+
Plugin plugin = findPlugin(pluginTag);
63+
if (plugin == null || plugin.getVersion() == null) {
64+
plugin = findManagedPlugin(pluginTag);
65+
if (plugin == null || plugin.getVersion() == null) {
66+
return false;
67+
}
68+
}
69+
return comparator.compare(null, plugin.getVersion(), minimumVersion) >= 0;
70+
}
71+
};
72+
}
73+
}

rewrite-maven/src/main/resources/META-INF/rewrite/maven.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ recipeList:
2525
- org.openrewrite.maven.OrderPomElements
2626
- org.openrewrite.maven.RemoveDuplicateDependencies
2727
- org.openrewrite.maven.RemoveRedundantDependencyVersions
28+
- org.openrewrite.maven.plugin.DependencyPluginGoalResolveSources
2829
---
2930
type: specs.openrewrite.org/v1beta/recipe
3031
name: org.openrewrite.maven.cleanup.PrefixlessExpressions
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
/*
2+
* Copyright 2025 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.maven.plugin;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.openrewrite.DocumentExample;
20+
import org.openrewrite.test.RecipeSpec;
21+
import org.openrewrite.test.RewriteTest;
22+
23+
import static org.openrewrite.java.Assertions.mavenProject;
24+
import static org.openrewrite.maven.Assertions.pomXml;
25+
26+
class DependencyPluginGoalResolveSourcesTest implements RewriteTest {
27+
28+
@Override
29+
public void defaults(RecipeSpec spec) {
30+
spec.recipe(new DependencyPluginGoalResolveSources());
31+
}
32+
33+
@DocumentExample
34+
@Test
35+
void sourcesToResolveSources() {
36+
rewriteRun(
37+
mavenProject("foo",
38+
//language=xml
39+
pomXml(
40+
"""
41+
<project>
42+
<modelVersion>4.0.0</modelVersion>
43+
<groupId>com.mycompany.app</groupId>
44+
<artifactId>my-app</artifactId>
45+
<version>1</version>
46+
<build>
47+
<plugins>
48+
<plugin>
49+
<groupId>org.apache.maven.plugins</groupId>
50+
<artifactId>maven-dependency-plugin</artifactId>
51+
<version>3.8.0</version>
52+
<executions>
53+
<execution>
54+
<goals>
55+
<goal>sources</goal>
56+
</goals>
57+
</execution>
58+
</executions>
59+
</plugin>
60+
</plugins>
61+
</build>
62+
</project>
63+
""",
64+
65+
"""
66+
<project>
67+
<modelVersion>4.0.0</modelVersion>
68+
<groupId>com.mycompany.app</groupId>
69+
<artifactId>my-app</artifactId>
70+
<version>1</version>
71+
<build>
72+
<plugins>
73+
<plugin>
74+
<groupId>org.apache.maven.plugins</groupId>
75+
<artifactId>maven-dependency-plugin</artifactId>
76+
<version>3.8.0</version>
77+
<executions>
78+
<execution>
79+
<goals>
80+
<goal>resolve-sources</goal>
81+
</goals>
82+
</execution>
83+
</executions>
84+
</plugin>
85+
</plugins>
86+
</build>
87+
</project>
88+
"""
89+
))
90+
);
91+
}
92+
93+
94+
@Test
95+
void managedDependencyVersion() {
96+
rewriteRun(
97+
mavenProject("foo",
98+
//language=xml
99+
pomXml(
100+
"""
101+
<project>
102+
<modelVersion>4.0.0</modelVersion>
103+
<groupId>com.mycompany.app</groupId>
104+
<artifactId>my-app</artifactId>
105+
<version>1</version>
106+
<build>
107+
<pluginManagement>
108+
<plugins>
109+
<plugin>
110+
<groupId>org.apache.maven.plugins</groupId>
111+
<artifactId>maven-dependency-plugin</artifactId>
112+
<version>3.8.0</version>
113+
</plugin>
114+
</plugins>
115+
</pluginManagement>
116+
<plugins>
117+
<plugin>
118+
<groupId>org.apache.maven.plugins</groupId>
119+
<artifactId>maven-dependency-plugin</artifactId>
120+
<executions>
121+
<execution>
122+
<goals>
123+
<goal>sources</goal>
124+
</goals>
125+
</execution>
126+
</executions>
127+
</plugin>
128+
</plugins>
129+
</build>
130+
</project>
131+
""",
132+
133+
"""
134+
<project>
135+
<modelVersion>4.0.0</modelVersion>
136+
<groupId>com.mycompany.app</groupId>
137+
<artifactId>my-app</artifactId>
138+
<version>1</version>
139+
<build>
140+
<pluginManagement>
141+
<plugins>
142+
<plugin>
143+
<groupId>org.apache.maven.plugins</groupId>
144+
<artifactId>maven-dependency-plugin</artifactId>
145+
<version>3.8.0</version>
146+
</plugin>
147+
</plugins>
148+
</pluginManagement>
149+
<plugins>
150+
<plugin>
151+
<groupId>org.apache.maven.plugins</groupId>
152+
<artifactId>maven-dependency-plugin</artifactId>
153+
<executions>
154+
<execution>
155+
<goals>
156+
<goal>resolve-sources</goal>
157+
</goals>
158+
</execution>
159+
</executions>
160+
</plugin>
161+
</plugins>
162+
</build>
163+
</project>
164+
"""
165+
))
166+
);
167+
}
168+
169+
@Test
170+
void noChangeForOlderVersions() {
171+
rewriteRun(
172+
mavenProject("foo",
173+
//language=xml
174+
pomXml(
175+
"""
176+
<project>
177+
<modelVersion>4.0.0</modelVersion>
178+
<groupId>com.mycompany.app</groupId>
179+
<artifactId>my-app</artifactId>
180+
<version>1</version>
181+
<build>
182+
<plugins>
183+
<plugin>
184+
<groupId>org.apache.maven.plugins</groupId>
185+
<artifactId>maven-dependency-plugin</artifactId>
186+
<version>3.6.9</version>
187+
<executions>
188+
<execution>
189+
<goals>
190+
<goal>sources</goal>
191+
</goals>
192+
</execution>
193+
</executions>
194+
</plugin>
195+
</plugins>
196+
</build>
197+
</project>
198+
"""
199+
))
200+
);
201+
}
202+
203+
@Test
204+
void noChangeForMissingVersion() {
205+
rewriteRun(
206+
mavenProject("foo",
207+
//language=xml
208+
pomXml(
209+
"""
210+
<project>
211+
<modelVersion>4.0.0</modelVersion>
212+
<groupId>com.mycompany.app</groupId>
213+
<artifactId>my-app</artifactId>
214+
<version>1</version>
215+
<build>
216+
<plugins>
217+
<plugin>
218+
<groupId>org.apache.maven.plugins</groupId>
219+
<artifactId>maven-dependency-plugin</artifactId>
220+
<executions>
221+
<execution>
222+
<goals>
223+
<goal>sources</goal>
224+
</goals>
225+
</execution>
226+
</executions>
227+
</plugin>
228+
</plugins>
229+
</build>
230+
</project>
231+
"""
232+
))
233+
);
234+
}
235+
236+
@Test
237+
void noChangesForResolveSources() {
238+
rewriteRun(
239+
mavenProject("foo",
240+
//language=xml
241+
pomXml(
242+
"""
243+
<project>
244+
<modelVersion>4.0.0</modelVersion>
245+
<groupId>com.mycompany.app</groupId>
246+
<artifactId>my-app</artifactId>
247+
<version>1</version>
248+
<build>
249+
<plugins>
250+
<plugin>
251+
<groupId>org.apache.maven.plugins</groupId>
252+
<artifactId>maven-dependency-plugin</artifactId>
253+
<version>3.7.0</version>
254+
<executions>
255+
<execution>
256+
<goals>
257+
<goal>resolve-sources</goal>
258+
</goals>
259+
</execution>
260+
</executions>
261+
</plugin>
262+
</plugins>
263+
</build>
264+
</project>
265+
"""
266+
))
267+
);
268+
}
269+
}

0 commit comments

Comments
 (0)