Skip to content

Commit

Permalink
Workshop
Browse files Browse the repository at this point in the history
  • Loading branch information
sambsnyd committed Dec 12, 2023
1 parent c083a29 commit e7703ba
Show file tree
Hide file tree
Showing 13 changed files with 570 additions and 28 deletions.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ dependencies {
implementation(platform("org.openrewrite:rewrite-bom:${latest}"))

implementation("org.openrewrite:rewrite-java")
implementation("org.openrewrite:rewrite-yaml")
implementation("org.assertj:assertj-core:3.24.2")
runtimeOnly("org.openrewrite:rewrite-java-17")
// Need to have a slf4j binding to see any output enabled from the parser.
runtimeOnly("ch.qos.logback:logback-classic:1.2.+")
Expand Down
90 changes: 90 additions & 0 deletions src/main/java/com/yourorg/AppendToReleaseNotes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.yourorg;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.*;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.text.PlainText;
import org.openrewrite.text.PlainTextParser;
import org.openrewrite.text.PlainTextVisitor;
import org.openrewrite.yaml.tree.Yaml;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;

@Value
@EqualsAndHashCode(callSuper = true)
public class AppendToReleaseNotes extends ScanningRecipe<AppendToReleaseNotes.Accumulator> {


@Override
public String getDisplayName() {
return "Append to release notes";
}

@Override
public String getDescription() {
return "Adds the specified line to RELEASE.md.";
}

@Option(displayName = "Message",
description = "Message to append to the bottom of RELEASE.md.")
String message;


public static class Accumulator {
boolean found;
}

@Override
public Accumulator getInitialValue(ExecutionContext ctx) {
return new Accumulator();
}

@Override
public TreeVisitor<?, ExecutionContext> getScanner(Accumulator acc) {
return new TreeVisitor<Tree, ExecutionContext>() {
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext executionContext) {
if(tree instanceof SourceFile) {
Path sourcePath = ((SourceFile) tree).getSourcePath();
acc.found |= "RELEASE.md".equals(sourcePath.toString());
}
return tree;
}
};
}

@Override
public Collection<? extends SourceFile> generate(Accumulator acc, ExecutionContext ctx) {
if(acc.found) {
return Collections.emptyList();
}
return PlainTextParser.builder().build()
.parse("")
.map(it -> (SourceFile) it.withSourcePath(Paths.get("RELEASE.md")))
.collect(Collectors.toList());
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor(Accumulator acc) {
return new PlainTextVisitor<ExecutionContext>() {
@Override
public PlainText visitText(PlainText text, ExecutionContext executionContext) {
PlainText t = super.visitText(text, executionContext);
if(!"RELEASE.md".equals(t.getSourcePath().toString())) {
return t;
}
if(t.getText().contains(message)) {
return t;
}
return t.withText(t.getText() + "\n" + message);
}
};
}
}
71 changes: 71 additions & 0 deletions src/main/java/com/yourorg/AssertEqualsToAssertThat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.yourorg;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.*;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;

import java.util.List;

@Value
@EqualsAndHashCode(callSuper = true)
public class AssertEqualsToAssertThat extends Recipe {
@Override
public String getDisplayName() {
// language=markdown
return "JUnit `assertEquals()` to Assertj `assertThat()`";
}

@Override
public String getDescription() {
return "Use AssertJ assertThat instead of JUnit assertEquals().";
}

private static MethodMatcher MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertEquals(..)");

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", null),
new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
J.MethodInvocation m = super.visitMethodInvocation(method, executionContext);
if(!MATCHER.matches(m)) {
return m;
}
List<Expression> arguments = m.getArguments();
maybeAddImport("org.assertj.core.api.Assertions");
maybeRemoveImport("org.junit.jupiter.api.Assertions");
if(arguments.size() == 2) {
Expression expected = arguments.get(0);
Expression actual = arguments.get(1);

m = JavaTemplate.builder("Assertions.assertThat(#{any()}).isEqualTo(#{any()})")
.imports("org.assertj.core.api.Assertions")
.javaParser(JavaParser.fromJavaVersion()
.classpath("assertj-core"))
.build()
.apply(getCursor(), m.getCoordinates().replace(), actual, expected);
} else if(arguments.size() == 3) {
Expression expected = arguments.get(0);
Expression actual = arguments.get(1);
Expression description = arguments.get(2);

m = JavaTemplate.builder("Assertions.assertThat(#{any()}).as(#{any()}).isEqualTo(#{any()})")
.imports("org.assertj.core.api.Assertions")
.javaParser(JavaParser.fromJavaVersion()
.classpath("assertj-core"))
.build()
.apply(getCursor(), m.getCoordinates().replace(), actual, description, expected);
}
return m;
}
});
}
}
55 changes: 55 additions & 0 deletions src/main/java/com/yourorg/ClassHierarchy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.yourorg;

import com.yourorg.table.ClassHierarchyReport;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;


@Value
@EqualsAndHashCode(callSuper = true)
public class ClassHierarchy extends Recipe {

transient ClassHierarchyReport report = new ClassHierarchyReport(this);

@Override
public String getDisplayName() {
return "Class hierarchy";
}

@Override
public String getDescription() {
return "Produces a data table showing inheritance relationships between classes.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {

@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
JavaType.FullyQualified type = classDecl.getType();
if(type instanceof JavaType.Class && type.getSupertype() != null) {
JavaType.FullyQualified supertype = type.getSupertype();
report.insertRow(ctx, new ClassHierarchyReport.Row(type.getFullyQualifiedName(),
ClassHierarchyReport.Relationship.EXTENDS,
supertype.getFullyQualifiedName()));

for (JavaType.FullyQualified anInterface : type.getInterfaces()) {
report.insertRow(ctx, new ClassHierarchyReport.Row(
type.getFullyQualifiedName(),
ClassHierarchyReport.Relationship.IMPLEMENTS,
anInterface.getFullyQualifiedName()
));
}
}
return super.visitClassDeclaration(classDecl, ctx);
}
};
}
}
76 changes: 76 additions & 0 deletions src/main/java/com/yourorg/UpdateConcoursePipeline.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.yourorg;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.*;
import org.openrewrite.yaml.ChangePropertyValue;
import org.openrewrite.yaml.YamlIsoVisitor;
import org.openrewrite.yaml.tree.Yaml;

@Value
@EqualsAndHashCode(callSuper = true)
public class UpdateConcoursePipeline extends Recipe {
@Override
public String getDisplayName() {
return "Update concourse pipeline";
}

@Override
public String getDescription() {
return "Update the tag filter on concourse pipelines.";
}

@Option(displayName = "New tag filter version",
description = "tag filter version.")
String version;

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
Preconditions.or(
new FindSourceFiles("ci/pipeline*.yml").getVisitor(),
new FindSourceFiles("ci/pipeline*.yaml").getVisitor()),
new YamlIsoVisitor<ExecutionContext>() {

@Override
public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionContext ctx) {
Yaml.Mapping.Entry e = super.visitMappingEntry(entry, ctx);
if (e.getKey().getValue().equals("source")) {
Yaml.Block value = e.getValue();
if(!(value instanceof Yaml.Mapping)) {
return e;
}
Yaml.Mapping mapping = (Yaml.Mapping) value;
Yaml.Mapping.Entry uriEntry = null;
Yaml.Mapping.Entry tagFilter = null;
for (Yaml.Mapping.Entry mappingEntry : mapping.getEntries()) {
if("uri".equals(mappingEntry.getKey().getValue())) {
uriEntry = mappingEntry;
} else if("tag_filter".equals(mappingEntry.getKey().getValue())) {
tagFilter = mappingEntry;
}
}
if(uriEntry == null || tagFilter == null) {
return e;
}
if(!(uriEntry.getValue() instanceof Yaml.Scalar) || !(tagFilter.getValue() instanceof Yaml.Scalar)) {
return e;
}
Yaml.Scalar uriValue = (Yaml.Scalar) uriEntry.getValue();
if(!uriValue.getValue().contains(".git")) {
return e;
}
Yaml.Scalar tagFilterValue = (Yaml.Scalar) tagFilter.getValue();
if(version.equals(tagFilterValue.getValue())) {
return e;
}
return (Yaml.Mapping.Entry) new ChangePropertyValue("source.tag_filter", version, null, null, null)
.getVisitor()
.visitNonNull(e, ctx);
}
return e;
}
}
);
}
}
35 changes: 35 additions & 0 deletions src/main/java/com/yourorg/table/ClassHierarchyReport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.yourorg.table;

import lombok.Value;
import org.openrewrite.Column;
import org.openrewrite.DataTable;
import org.openrewrite.Recipe;

public class ClassHierarchyReport extends DataTable<ClassHierarchyReport.Row> {

public ClassHierarchyReport(Recipe recipe) {
super(recipe,
"Class hierarchy report",
"Records inheritance relationships between classes.");
}

@Value
public static class Row {
@Column(displayName = "Class name",
description = "Fully qualified name of the class.")
String className;

@Column(displayName = "Relationship",
description = "Whether the class implements a super interface or extends a superclass.")
Relationship relationship;

@Column(displayName = "Super class name",
description = "Fully qualified name of the superclass.")
String superClassName;
}

public enum Relationship {
EXTENDS,
IMPLEMENTS
}
}
13 changes: 13 additions & 0 deletions src/main/resources/META-INF/rewrite/assertjmigration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
type: specs.openrewrite.org/v1beta/recipe
name: com.desjardins.UseApacheStringUtils
displayName: Use apache string utils
description: Replace Spring string utilities with apache string utilities
recipeList:
- org.openrewrite.java.dependencies.AddDependency:
groupId: org.assertj
artifactId: assertj-core
version: 3.x
onlyIfUsing: org.junit.jupiter.api.Assertions
configuration: implementation
- com.yourorg.AssertEqualsToAssertThat
28 changes: 0 additions & 28 deletions src/main/resources/META-INF/rewrite/rewrite.yml

This file was deleted.

15 changes: 15 additions & 0 deletions src/main/resources/META-INF/rewrite/stringuitls.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
type: specs.openrewrite.org/v1beta/recipe
name: com.desjardins.UseApacheStringUtils
displayName: Use apache string utils
description: Replace Spring string utilities with apache string utilities
recipeList:
- org.openrewrite.java.dependencies.AddDependency:
groupId: org.apache.commons
artifactId: commons-lang3
version: latest.release
onlyIfUsing: org.springframework.util.StringUtils
configuration: implementation
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: org.springframework.util.StringUtils
newFullyQualifiedTypeName: org.apache.commons.lang3.StringUtils
Loading

0 comments on commit e7703ba

Please sign in to comment.