Skip to content

Commit

Permalink
Add unlessUsing property to RemoveDependency recipe (#129)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people authored Nov 13, 2024
1 parent 49462b2 commit a742518
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 39 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
insert_final_newline = true
trim_trailing_whitespace = true

[src/test*/java/**.java]
indent_size = 4
ij_continuation_indent_size = 2
101 changes: 77 additions & 24 deletions src/main/java/org/openrewrite/java/dependencies/RemoveDependency.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,46 @@
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.Option;
import org.openrewrite.Recipe;

import java.util.Arrays;
import java.util.List;
import org.openrewrite.*;
import org.openrewrite.java.search.UsesType;

import java.util.concurrent.atomic.AtomicBoolean;

@Value
@EqualsAndHashCode(callSuper = false)
public class RemoveDependency extends Recipe {
public class RemoveDependency extends ScanningRecipe<AtomicBoolean> {
@Option(displayName = "Group ID",
description = "The first part of a dependency coordinate `com.google.guava:guava:VERSION`. This can be a glob expression.",
example = "com.fasterxml.jackson*")
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 ID",
description = "The second part of a dependency coordinate `com.google.guava:guava:VERSION`. This can be a glob expression.",
example = "jackson-module*")
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 = "Unless using",
description = "Do not remove if type is in use. Supports glob expressions.",
example = "org.aspectj.lang.*",
required = false)
@Nullable
String unlessUsing;

// Gradle only parameter
@Option(displayName = "The dependency configuration", description = "The dependency configuration to remove from.", example = "api", required = false)
@Option(displayName = "The dependency configuration",
description = "The dependency configuration to remove from.",
example = "api",
required = false)
@Nullable
String configuration;

// Maven only parameter
@Option(displayName = "Scope",
description = "Only remove dependencies if they are in this scope. If 'runtime', this will" +
"also remove dependencies in the 'compile' scope because 'compile' dependencies are part of the runtime dependency set",
valid = {"compile", "test", "runtime", "provided"},
example = "compile",
required = false)
description = "Only remove dependencies if they are in this scope. If 'runtime', this will" +
"also remove dependencies in the 'compile' scope because 'compile' dependencies are part of the runtime dependency set",
valid = {"compile", "test", "runtime", "provided"},
example = "compile",
required = false)
@Nullable
String scope;

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

org.openrewrite.gradle.@Nullable RemoveDependency removeGradleDependency;
@Override
public AtomicBoolean getInitialValue(ExecutionContext ctx) {
return new AtomicBoolean(false);
}

org.openrewrite.maven.@Nullable RemoveDependency removeMavenDependency;
org.openrewrite.gradle.RemoveDependency removeGradleDependency;
org.openrewrite.maven.RemoveDependency removeMavenDependency;

public RemoveDependency(
String groupId,
String artifactId,
@Nullable String configuration,
@Nullable String scope) {
String groupId,
String artifactId,
@Nullable String unlessUsing,
@Nullable String configuration,
@Nullable String scope) {
this.groupId = groupId;
this.artifactId = artifactId;
this.unlessUsing = unlessUsing;
this.configuration = configuration;
this.scope = scope;
removeGradleDependency = new org.openrewrite.gradle.RemoveDependency(groupId, artifactId, configuration);
removeMavenDependency = new org.openrewrite.maven.RemoveDependency(groupId, artifactId, scope);
}

@Override
public List<Recipe> getRecipeList() {
return Arrays.asList(removeGradleDependency, removeMavenDependency);
public TreeVisitor<?, ExecutionContext> getScanner(AtomicBoolean usageFound) {
if (unlessUsing == null) {
return TreeVisitor.noop();
}
UsesType<ExecutionContext> usesType = new UsesType<>(unlessUsing, true);
return new TreeVisitor<Tree, ExecutionContext>() {
@Override
public Tree preVisit(Tree tree, ExecutionContext ctx) {
stopAfterPreVisit();
if (!usageFound.get()) {
usageFound.set(tree != usesType.visit(tree, ctx));
}
return tree;
}
};
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor(AtomicBoolean usageFound) {
if (usageFound.get()) {
return TreeVisitor.noop();
}

return new TreeVisitor<Tree, ExecutionContext>() {
final TreeVisitor<?, ExecutionContext> gradleRemoveDep = removeGradleDependency.getVisitor();
final TreeVisitor<?, ExecutionContext> mavenRemoveDep = removeMavenDependency.getVisitor();

@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
if (tree instanceof SourceFile) {
SourceFile sf = (SourceFile) tree;
if (gradleRemoveDep.isAcceptable(sf, ctx)) {
return gradleRemoveDep.visitNonNull(tree, ctx);
}
if (mavenRemoveDep.isAcceptable(sf, ctx)) {
return mavenRemoveDep.visitNonNull(tree, ctx);
}
}
return tree;
}
};
}
}
5 changes: 0 additions & 5 deletions src/test/java/org/openrewrite/.editorconfig

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.Issue;
import org.openrewrite.java.JavaParser;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.gradle.Assertions.buildGradle;
import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi;
import static org.openrewrite.java.Assertions.*;
import static org.openrewrite.maven.Assertions.pomXml;

class RemoveDependencyTest implements RewriteTest {
Expand All @@ -30,18 +33,18 @@ class RemoveDependencyTest implements RewriteTest {
void removeGradleDependencyUsingStringNotationWithExclusion() {
rewriteRun(
spec -> spec.beforeRecipe(withToolingApi())
.recipe(new RemoveDependency("org.springframework.boot", "spring-boot*", null, null)),
.recipe(new RemoveDependency("org.springframework.boot", "spring-boot*", null, null, null)),
//language=groovy
buildGradle(
"""
plugins {
id 'java-library'
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web:2.7.0") {
exclude group: "junit"
Expand All @@ -53,11 +56,11 @@ void removeGradleDependencyUsingStringNotationWithExclusion() {
plugins {
id 'java-library'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation "org.junit.vintage:junit-vintage-engine:5.6.2"
}
Expand All @@ -70,17 +73,17 @@ void removeGradleDependencyUsingStringNotationWithExclusion() {
@Test
void removeMavenDependency() {
rewriteRun(
spec -> spec.recipe(new RemoveDependency("junit", "junit", null, null)),
spec -> spec.recipe(new RemoveDependency("junit", "junit", null, null, null)),
//language=xml
pomXml(
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
Expand All @@ -99,11 +102,11 @@ void removeMavenDependency() {
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
Expand All @@ -116,4 +119,111 @@ void removeMavenDependency() {
)
);
}

@Issue("https://github.com/openrewrite/rewrite-java-dependencies/issues/11")
@Test
void doNotRemoveIfInUse() {
rewriteRun(
spec -> spec
.parser(JavaParser.fromJavaVersion().dependsOn(
//language=java
"""
package org.aspectj.lang.annotation;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
}
"""
))
.recipe(new RemoveDependency("org.aspectj", "aspectjrt", "org.aspectj.lang.annotation.*", null, null)),
mavenProject("example",
//language=java
srcMainJava(
java(
"""
import org.aspectj.lang.annotation.Aspect;
@Aspect
class MyLoggingInterceptor {
}
"""
)
),
//language=xml
pomXml(
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.22.1</version>
</dependency>
</dependencies>
</project>
"""
)
)
);
}

@Issue("https://github.com/openrewrite/rewrite-java-dependencies/issues/11")
@Test
void doRemoveIfNotInUse() {
rewriteRun(
spec -> spec.recipe(new RemoveDependency("org.aspectj", "aspectjrt", "java.lang.String", null, null)),
mavenProject("example",
//language=java
srcMainJava(
java(
"""
class MyLoggingInterceptor {
// Not using String anywhere here; the dependency should be removed
}
"""
)
),
//language=xml
pomXml(
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.22.1</version>
</dependency>
</dependencies>
</project>
""",
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
"""
)
)
);
}
}

0 comments on commit a742518

Please sign in to comment.