Skip to content

Commit a742518

Browse files
jevanlingentimtebeekgithub-actions[bot]
authored
Add unlessUsing property to RemoveDependency recipe (#129)
* Start implementing `unlessUsing` property * Change test to use a Java source file too; add TODOs * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Implement `unlessUsing` property * Nullable options should not be required in Yaml * Adopt UsesType instead of looking for method patterns, to match AddDependency * Reduce warnings --------- Co-authored-by: Tim te Beek <tim@moderne.io> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 49462b2 commit a742518

4 files changed

Lines changed: 206 additions & 39 deletions

File tree

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
insert_final_newline = true
5+
trim_trailing_whitespace = true
6+
7+
[src/test*/java/**.java]
8+
indent_size = 4
9+
ij_continuation_indent_size = 2

src/main/java/org/openrewrite/java/dependencies/RemoveDependency.java

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,46 @@
1818
import lombok.EqualsAndHashCode;
1919
import lombok.Value;
2020
import org.jspecify.annotations.Nullable;
21-
import org.openrewrite.Option;
22-
import org.openrewrite.Recipe;
23-
24-
import java.util.Arrays;
25-
import java.util.List;
21+
import org.openrewrite.*;
22+
import org.openrewrite.java.search.UsesType;
2623

24+
import java.util.concurrent.atomic.AtomicBoolean;
2725

2826
@Value
2927
@EqualsAndHashCode(callSuper = false)
30-
public class RemoveDependency extends Recipe {
28+
public class RemoveDependency extends ScanningRecipe<AtomicBoolean> {
3129
@Option(displayName = "Group ID",
32-
description = "The first part of a dependency coordinate `com.google.guava:guava:VERSION`. This can be a glob expression.",
33-
example = "com.fasterxml.jackson*")
30+
description = "The first part of a dependency coordinate `com.google.guava:guava:VERSION`. This can be a glob expression.",
31+
example = "com.fasterxml.jackson*")
3432
String groupId;
3533

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

39+
@Option(displayName = "Unless using",
40+
description = "Do not remove if type is in use. Supports glob expressions.",
41+
example = "org.aspectj.lang.*",
42+
required = false)
43+
@Nullable
44+
String unlessUsing;
45+
4146
// Gradle only parameter
42-
@Option(displayName = "The dependency configuration", description = "The dependency configuration to remove from.", example = "api", required = false)
47+
@Option(displayName = "The dependency configuration",
48+
description = "The dependency configuration to remove from.",
49+
example = "api",
50+
required = false)
4351
@Nullable
4452
String configuration;
4553

4654
// Maven only parameter
4755
@Option(displayName = "Scope",
48-
description = "Only remove dependencies if they are in this scope. If 'runtime', this will" +
49-
"also remove dependencies in the 'compile' scope because 'compile' dependencies are part of the runtime dependency set",
50-
valid = {"compile", "test", "runtime", "provided"},
51-
example = "compile",
52-
required = false)
56+
description = "Only remove dependencies if they are in this scope. If 'runtime', this will" +
57+
"also remove dependencies in the 'compile' scope because 'compile' dependencies are part of the runtime dependency set",
58+
valid = {"compile", "test", "runtime", "provided"},
59+
example = "compile",
60+
required = false)
5361
@Nullable
5462
String scope;
5563

@@ -64,25 +72,70 @@ public String getDescription() {
6472
"For Maven project, removes a single dependency from the <dependencies> section of the pom.xml.";
6573
}
6674

67-
org.openrewrite.gradle.@Nullable RemoveDependency removeGradleDependency;
75+
@Override
76+
public AtomicBoolean getInitialValue(ExecutionContext ctx) {
77+
return new AtomicBoolean(false);
78+
}
6879

69-
org.openrewrite.maven.@Nullable RemoveDependency removeMavenDependency;
80+
org.openrewrite.gradle.RemoveDependency removeGradleDependency;
81+
org.openrewrite.maven.RemoveDependency removeMavenDependency;
7082

7183
public RemoveDependency(
72-
String groupId,
73-
String artifactId,
74-
@Nullable String configuration,
75-
@Nullable String scope) {
84+
String groupId,
85+
String artifactId,
86+
@Nullable String unlessUsing,
87+
@Nullable String configuration,
88+
@Nullable String scope) {
7689
this.groupId = groupId;
7790
this.artifactId = artifactId;
91+
this.unlessUsing = unlessUsing;
7892
this.configuration = configuration;
7993
this.scope = scope;
8094
removeGradleDependency = new org.openrewrite.gradle.RemoveDependency(groupId, artifactId, configuration);
8195
removeMavenDependency = new org.openrewrite.maven.RemoveDependency(groupId, artifactId, scope);
8296
}
8397

8498
@Override
85-
public List<Recipe> getRecipeList() {
86-
return Arrays.asList(removeGradleDependency, removeMavenDependency);
99+
public TreeVisitor<?, ExecutionContext> getScanner(AtomicBoolean usageFound) {
100+
if (unlessUsing == null) {
101+
return TreeVisitor.noop();
102+
}
103+
UsesType<ExecutionContext> usesType = new UsesType<>(unlessUsing, true);
104+
return new TreeVisitor<Tree, ExecutionContext>() {
105+
@Override
106+
public Tree preVisit(Tree tree, ExecutionContext ctx) {
107+
stopAfterPreVisit();
108+
if (!usageFound.get()) {
109+
usageFound.set(tree != usesType.visit(tree, ctx));
110+
}
111+
return tree;
112+
}
113+
};
114+
}
115+
116+
@Override
117+
public TreeVisitor<?, ExecutionContext> getVisitor(AtomicBoolean usageFound) {
118+
if (usageFound.get()) {
119+
return TreeVisitor.noop();
120+
}
121+
122+
return new TreeVisitor<Tree, ExecutionContext>() {
123+
final TreeVisitor<?, ExecutionContext> gradleRemoveDep = removeGradleDependency.getVisitor();
124+
final TreeVisitor<?, ExecutionContext> mavenRemoveDep = removeMavenDependency.getVisitor();
125+
126+
@Override
127+
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
128+
if (tree instanceof SourceFile) {
129+
SourceFile sf = (SourceFile) tree;
130+
if (gradleRemoveDep.isAcceptable(sf, ctx)) {
131+
return gradleRemoveDep.visitNonNull(tree, ctx);
132+
}
133+
if (mavenRemoveDep.isAcceptable(sf, ctx)) {
134+
return mavenRemoveDep.visitNonNull(tree, ctx);
135+
}
136+
}
137+
return tree;
138+
}
139+
};
87140
}
88141
}

src/test/java/org/openrewrite/.editorconfig

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/test/java/org/openrewrite/java/dependencies/RemoveDependencyTest.java

Lines changed: 120 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717

1818
import org.junit.jupiter.api.Test;
1919
import org.openrewrite.DocumentExample;
20+
import org.openrewrite.Issue;
21+
import org.openrewrite.java.JavaParser;
2022
import org.openrewrite.test.RewriteTest;
2123

2224
import static org.openrewrite.gradle.Assertions.buildGradle;
2325
import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi;
26+
import static org.openrewrite.java.Assertions.*;
2427
import static org.openrewrite.maven.Assertions.pomXml;
2528

2629
class RemoveDependencyTest implements RewriteTest {
@@ -30,18 +33,18 @@ class RemoveDependencyTest implements RewriteTest {
3033
void removeGradleDependencyUsingStringNotationWithExclusion() {
3134
rewriteRun(
3235
spec -> spec.beforeRecipe(withToolingApi())
33-
.recipe(new RemoveDependency("org.springframework.boot", "spring-boot*", null, null)),
36+
.recipe(new RemoveDependency("org.springframework.boot", "spring-boot*", null, null, null)),
3437
//language=groovy
3538
buildGradle(
3639
"""
3740
plugins {
3841
id 'java-library'
3942
}
40-
43+
4144
repositories {
4245
mavenCentral()
4346
}
44-
47+
4548
dependencies {
4649
implementation("org.springframework.boot:spring-boot-starter-web:2.7.0") {
4750
exclude group: "junit"
@@ -53,11 +56,11 @@ void removeGradleDependencyUsingStringNotationWithExclusion() {
5356
plugins {
5457
id 'java-library'
5558
}
56-
59+
5760
repositories {
5861
mavenCentral()
5962
}
60-
63+
6164
dependencies {
6265
testImplementation "org.junit.vintage:junit-vintage-engine:5.6.2"
6366
}
@@ -70,17 +73,17 @@ void removeGradleDependencyUsingStringNotationWithExclusion() {
7073
@Test
7174
void removeMavenDependency() {
7275
rewriteRun(
73-
spec -> spec.recipe(new RemoveDependency("junit", "junit", null, null)),
76+
spec -> spec.recipe(new RemoveDependency("junit", "junit", null, null, null)),
7477
//language=xml
7578
pomXml(
7679
"""
7780
<project>
7881
<modelVersion>4.0.0</modelVersion>
79-
82+
8083
<groupId>com.mycompany.app</groupId>
8184
<artifactId>my-app</artifactId>
8285
<version>1</version>
83-
86+
8487
<dependencies>
8588
<dependency>
8689
<groupId>com.google.guava</groupId>
@@ -99,11 +102,11 @@ void removeMavenDependency() {
99102
"""
100103
<project>
101104
<modelVersion>4.0.0</modelVersion>
102-
105+
103106
<groupId>com.mycompany.app</groupId>
104107
<artifactId>my-app</artifactId>
105108
<version>1</version>
106-
109+
107110
<dependencies>
108111
<dependency>
109112
<groupId>com.google.guava</groupId>
@@ -116,4 +119,111 @@ void removeMavenDependency() {
116119
)
117120
);
118121
}
122+
123+
@Issue("https://github.com/openrewrite/rewrite-java-dependencies/issues/11")
124+
@Test
125+
void doNotRemoveIfInUse() {
126+
rewriteRun(
127+
spec -> spec
128+
.parser(JavaParser.fromJavaVersion().dependsOn(
129+
//language=java
130+
"""
131+
package org.aspectj.lang.annotation;
132+
133+
import java.lang.annotation.Target;
134+
import java.lang.annotation.ElementType;
135+
import java.lang.annotation.Retention;
136+
import java.lang.annotation.RetentionPolicy;
137+
138+
@Retention(RetentionPolicy.RUNTIME)
139+
@Target(ElementType.TYPE)
140+
public @interface Aspect {
141+
}
142+
"""
143+
))
144+
.recipe(new RemoveDependency("org.aspectj", "aspectjrt", "org.aspectj.lang.annotation.*", null, null)),
145+
mavenProject("example",
146+
//language=java
147+
srcMainJava(
148+
java(
149+
"""
150+
import org.aspectj.lang.annotation.Aspect;
151+
@Aspect
152+
class MyLoggingInterceptor {
153+
}
154+
"""
155+
)
156+
),
157+
//language=xml
158+
pomXml(
159+
"""
160+
<project>
161+
<modelVersion>4.0.0</modelVersion>
162+
163+
<groupId>com.mycompany.app</groupId>
164+
<artifactId>my-app</artifactId>
165+
<version>1</version>
166+
167+
<dependencies>
168+
<dependency>
169+
<groupId>org.aspectj</groupId>
170+
<artifactId>aspectjrt</artifactId>
171+
<version>1.9.22.1</version>
172+
</dependency>
173+
</dependencies>
174+
</project>
175+
"""
176+
)
177+
)
178+
);
179+
}
180+
181+
@Issue("https://github.com/openrewrite/rewrite-java-dependencies/issues/11")
182+
@Test
183+
void doRemoveIfNotInUse() {
184+
rewriteRun(
185+
spec -> spec.recipe(new RemoveDependency("org.aspectj", "aspectjrt", "java.lang.String", null, null)),
186+
mavenProject("example",
187+
//language=java
188+
srcMainJava(
189+
java(
190+
"""
191+
class MyLoggingInterceptor {
192+
// Not using String anywhere here; the dependency should be removed
193+
}
194+
"""
195+
)
196+
),
197+
//language=xml
198+
pomXml(
199+
"""
200+
<project>
201+
<modelVersion>4.0.0</modelVersion>
202+
203+
<groupId>com.mycompany.app</groupId>
204+
<artifactId>my-app</artifactId>
205+
<version>1</version>
206+
207+
<dependencies>
208+
<dependency>
209+
<groupId>org.aspectj</groupId>
210+
<artifactId>aspectjrt</artifactId>
211+
<version>1.9.22.1</version>
212+
</dependency>
213+
</dependencies>
214+
</project>
215+
""",
216+
"""
217+
<project>
218+
<modelVersion>4.0.0</modelVersion>
219+
220+
<groupId>com.mycompany.app</groupId>
221+
<artifactId>my-app</artifactId>
222+
<version>1</version>
223+
</project>
224+
"""
225+
)
226+
)
227+
);
228+
}
119229
}

0 commit comments

Comments
 (0)