Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial recipes for Micronaut 4. #50

Merged
merged 26 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0999b6b
OpenRewrite 8.0 upgrade
knutwannheden May 5, 2023
5711d8e
Update recipes to new `JavaTemplate` API
knutwannheden May 16, 2023
f42d9d3
Add recipes for Micronaut 4.
jeremyg484 May 30, 2023
66e8e5e
Add license headers.
jeremyg484 May 30, 2023
2bdc0a6
Merge with main.
jeremyg484 Jun 1, 2023
ac91b1a
Fix missing import.
jeremyg484 Jun 1, 2023
4dc6140
Use parserClasspath to test multiple Micronaut versions.
jeremyg484 Jun 1, 2023
0fad934
Unnest recipeDependencies in build.gradle.kts
timtebeek Jun 2, 2023
0e83192
Use existing recipe for Jakarta annotaitons update.
jeremyg484 Jun 5, 2023
414f8dc
Add recipe test dependencies to repository.
jeremyg484 Jun 5, 2023
7d7c26f
Update licenseHeader.txt and copyight year on new files
timtebeek Jun 6, 2023
555e0fc
Use Preconditions.check
jeremyg484 Jun 6, 2023
1ebb9e5
Clean up Groovy compile warnings in tests.
jeremyg484 Jun 6, 2023
2d4b9f5
Refactor to unified Gradle/Maven AddDependency.
jeremyg484 Jun 6, 2023
fe5f0c3
Update Security recipes with conditional checks.
jeremyg484 Jun 6, 2023
de8812e
Add missing license header.
jeremyg484 Jun 6, 2023
cc13935
Use rewrite-migrate-java to update build to Java 17.
jeremyg484 Jun 6, 2023
32544cd
Use unified Gradle/Maven RemoveDependency.
jeremyg484 Jun 6, 2023
174ac58
Use provided from rewrite-migrate-java.
jeremyg484 Jun 6, 2023
4982765
Use provided JavaxValidationMigrationToJakartaValidation from rewrite…
jeremyg484 Jun 6, 2023
14c7f44
Typo in recipe description.
jeremyg484 Jun 6, 2023
9edcd5a
Invoke provided Jakarta migrations directly.
jeremyg484 Jun 7, 2023
afa1cdb
Invoke Jakarta migration recipes directly from tests.
jeremyg484 Jun 7, 2023
dd26d98
Inline fromRuntimeClasspath and limit package scan
timtebeek Jun 7, 2023
f506d1e
Merge branch 'Micronaut3to4_OpenRewrite8' of github.com:openrewrite/r…
timtebeek Jun 7, 2023
3349286
Similarly limit runtime classpath scanning
timtebeek Jun 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ dependencies {
implementation(platform("org.openrewrite:rewrite-bom:${rewriteVersion}"))
implementation("org.openrewrite:rewrite-java")
implementation("org.openrewrite:rewrite-maven")
implementation("org.openrewrite:rewrite-gradle")
implementation("org.openrewrite:rewrite-properties")
implementation("org.openrewrite:rewrite-yaml")
implementation("org.openrewrite.recipe:rewrite-migrate-java:2.+")
implementation("org.openrewrite.recipe:rewrite-java-dependencies:1.+")

runtimeOnly("org.openrewrite:rewrite-java-8")
runtimeOnly("org.openrewrite:rewrite-java-11")
runtimeOnly("org.openrewrite:rewrite-java-17")
runtimeOnly("org.openrewrite.recipe:rewrite-migrate-java:${rewriteVersion}")

testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-params:latest.release")
Expand All @@ -31,18 +35,34 @@ dependencies {
testImplementation("org.openrewrite:rewrite-test")
testImplementation("org.openrewrite:rewrite-java-tck")
testImplementation("org.assertj:assertj-core:latest.release")
testRuntimeOnly(gradleApi())
}

recipeDependencies {
parserClasspath("io.micronaut:micronaut-core:2.+")
parserClasspath("io.micronaut:micronaut-context:2.+")
parserClasspath("io.micronaut:micronaut-inject:2.+")
parserClasspath("io.micronaut:micronaut-validation:2.+")
parserClasspath("io.micronaut:micronaut-http:2.+")
parserClasspath("io.micronaut:micronaut-http-server:2.+")
parserClasspath("io.micronaut:micronaut-http-server-netty:2.+")
parserClasspath("io.micronaut:micronaut-http-client:2.+")
parserClasspath("io.micronaut:micronaut-http-client-core:2.+")
parserClasspath("javax.inject:javax.inject:1")
parserClasspath("jakarta.inject:jakarta.inject-api:2.+")
parserClasspath("org.reactivestreams:reactive-streams:1.0.4")

testImplementation("com.google.guava:guava:29.0-jre")

testRuntimeOnly("io.micronaut:micronaut-core:2.+")
testRuntimeOnly("io.micronaut:micronaut-inject-java:2.+")
testRuntimeOnly("io.micronaut:micronaut-http:2.+")
testRuntimeOnly("io.micronaut:micronaut-http-server:2.+")
testRuntimeOnly("io.micronaut:micronaut-http-server-netty:2.+")
testRuntimeOnly("io.micronaut:micronaut-http-client:2.+")
testRuntimeOnly("io.micronaut:micronaut-http-client-core:2.+")
testRuntimeOnly("io.micronaut:micronaut-validation:2.+")
testRuntimeOnly("jakarta.inject:jakarta.inject-api:2.+")
testRuntimeOnly("javax.validation:validation-api:2.+")
testRuntimeOnly("org.reactivestreams:reactive-streams:1.0.4")
parserClasspath("io.micronaut:micronaut-context:4.0.0-M2")
parserClasspath("io.micronaut:micronaut-websocket:4.0.0-M2")
parserClasspath("io.micronaut.validation:micronaut-validation:4.0.0-M5")
parserClasspath("io.micronaut:micronaut-retry:4.0.0-M4")
parserClasspath("io.micronaut.email:micronaut-email:2.0.0-M1")
parserClasspath("javax.annotation:javax.annotation-api:1.3.2")
parserClasspath("javax.validation:validation-api:2.0.1.Final")
parserClasspath("jakarta.validation:jakarta.validation-api:3.0.2")
parserClasspath("javax.persistence:javax.persistence-api:2.2")
parserClasspath("jakarta.persistence:jakarta.persistence-api:3.1.0")
parserClasspath("javax.mail:javax.mail-api:1.6.2")
parserClasspath("jakarta.mail:jakarta.mail-api:2.1.1")
parserClasspath("jakarta.annotation:jakarta.annotation-api:2.1.1")
}
2 changes: 1 addition & 1 deletion gradle/licenseHeader.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2021 the original author or authors.
Copyright 2023 the original author or authors.
<p>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.java.micronaut;

import org.openrewrite.*;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.dependencies.AddDependency;

import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.requireNonNull;

public class AddSnakeYamlDependencyIfNeeded extends ScanningRecipe<AddSnakeYamlDependencyIfNeeded.YamlAccumulator> {

private final List<Recipe> recipeList = new ArrayList<>();

static class YamlAccumulator {
boolean usingYamlConfig = false;
}

public AddSnakeYamlDependencyIfNeeded() {
recipeList.add(new AddDependency("org.yaml", "snakeyaml", null, null, "io.micronaut.runtime.Micronaut",
null, null, null, "runtimeOnly", "runtime", null, null, null, null));
}

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

@Override
public TreeVisitor<?, ExecutionContext> getScanner(YamlAccumulator acc) {
return new TreeVisitor<Tree, ExecutionContext>() {
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
SourceFile sourceFile = (SourceFile) requireNonNull(tree);
acc.usingYamlConfig |= sourceFile != new FindYamlConfig().getVisitor().visit(sourceFile, ctx);
return tree;
}
};
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor(YamlAccumulator acc) {
return Preconditions.check(!acc.usingYamlConfig, new TreeVisitor<Tree, ExecutionContext>() {
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext executionContext) {
if (!recipeList.isEmpty()) {
recipeList.clear();
}
return super.visit(tree, executionContext);
}
});
}

@Override
public String getDisplayName() {
return "Add `snakeyaml` dependency if needed";
}

@Override
public String getDescription() {
return "This recipe will add the `snakeyaml` dependency to a Micronaut 4 application that uses yaml configuration.";
}

@Override
public List<Recipe> getRecipeList() {
return this.recipeList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.java.micronaut;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.maven.MavenVisitor;
import org.openrewrite.xml.AddOrUpdateChild;
import org.openrewrite.xml.ChangeTagValueVisitor;
import org.openrewrite.xml.tree.Xml;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.openrewrite.xml.FilterTagChildrenVisitor.filterTagChildren;
import static org.openrewrite.xml.MapTagChildrenVisitor.mapTagChildren;

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

@Option(displayName = "Old groupId",
description = "The old groupId to replace. The groupId is the first part of a plugin coordinate 'com.google.guava:guava:VERSION'. Supports glob expressions.",
example = "org.openrewrite.recipe")
String oldGroupId;

@Option(displayName = "Old artifactId",
description = "The old artifactId to replace. The artifactId is the second part of a plugin coordinate 'com.google.guava:guava:VERSION'. Supports glob expressions.",
example = "my-deprecated-annotation-processor")
String oldArtifactId;

@Option(displayName = "New groupId",
description = "The new groupId to use. Defaults to the existing group id.",
example = "corp.internal.openrewrite.recipe",
required = false)
@Nullable
String newGroupId;

@Option(displayName = "New artifactId",
description = "The new artifactId to use. Defaults to the existing artifact id.",
example = "my-new-annotation-processor",
required = false)
@Nullable
String newArtifactId;

@Option(displayName = "New version",
description = "An exact version string for the annotation processor path.",
example = "${micronaut.validation}",
required = false)
@Nullable
String newVersion;

@Option(displayName = "Exclusions",
description = "A list of exclusions to apply to the annotation processor path in the format groupId:artifactId",
example = "io.micronaut:micronaut-inject",
required = false)
@Nullable
List<String> exclusions;

@Override
public String getDisplayName() {
return "Change Maven annotation processor path";
}

@Override
public String getDescription() {
return "Change the groupId, artifactId, and version of a Maven annotation processor path.";
}

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

@Override
public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) {
Xml.Tag plugin = (Xml.Tag) super.visitTag(tag, ctx);
if (isPluginTag("org.apache.maven.plugins", "maven-compiler-plugin")) {
plugin = maybeUpdatePlugin(plugin, ctx);
if (plugin != tag) {
maybeUpdateModel();
}
}
return plugin;
}

private Xml.Tag maybeUpdatePlugin(Xml.Tag plugin, ExecutionContext ctx) {
return mapTagChildren(plugin, childTag -> "configuration".equals(childTag.getName()) ? maybeUpdateConfiguration(childTag, ctx) : childTag);
}

private Xml.Tag maybeUpdateConfiguration(Xml.Tag configuration, ExecutionContext ctx) {
return mapTagChildren(configuration, childTag -> "annotationProcessorPaths".equals(childTag.getName()) ? maybeUpdateAnnotationProcessorPaths(childTag, ctx) : childTag);
}

private Xml.Tag maybeUpdateAnnotationProcessorPaths(Xml.Tag annotationProcessorPaths, ExecutionContext ctx) {
return mapTagChildren(annotationProcessorPaths, childTag -> {
if ("path".equals(childTag.getName()) && isPathMatch(childTag)) {
Xml.Tag path = childTag;
if (newGroupId != null) {
path = changeChildTagValue(path, "groupId", newGroupId, ctx);
}
if (newArtifactId != null) {
path = changeChildTagValue(path, "artifactId", newArtifactId, ctx);
}
if (newVersion != null) {
path = changeChildTagValue(path, "version", newVersion, ctx);
}
if (exclusions == null) {
path = filterTagChildren(path, child -> !("exclusions".equals(child.getName())));
} else if (exclusions != null) {
path = addExclusionsToPath(path, ctx);
}
childTag = path;
}
return childTag;
});
}

private Xml.Tag addExclusionsToPath(Xml.Tag path, ExecutionContext ctx) {
Xml.Tag exclusionsTag = Xml.Tag.build("\n<exclusions>\n" + buildExclusionsContent() + "</exclusions>");
doAfterVisit(new AddOrUpdateChild<>(path, exclusionsTag));
return path;
}

private String buildExclusionsContent() {
if (exclusions == null) {
return "";
}
return exclusions.stream().map(exclusion -> {
StringBuilder exclusionContent = new StringBuilder("<exclusion>\n");
String[] exclusionParts = exclusion.split(":");
if (exclusionParts.length != 2) {
throw new IllegalStateException("Expected an exclusion in the form of groupId:artifactId but was '" + exclusion + "'");
}
exclusionContent.append("<groupId>").append(exclusionParts[0]).append("</groupId>\n")
.append("<artifactId>").append(exclusionParts[1]).append("</artifactId>\n")
.append("</exclusion>\n");
return exclusionContent.toString();
}).collect(Collectors.joining());
}

private boolean isPathMatch(Xml.Tag path) {
return oldGroupId.equals(path.getChildValue("groupId").orElse(null)) &&
oldArtifactId.equals(path.getChildValue("artifactId").orElse(null));
}

private Xml.Tag changeChildTagValue(Xml.Tag tag, String childTagName, String newValue, ExecutionContext ctx) {
Optional<Xml.Tag> childTag = tag.getChild(childTagName);
if (childTag.isPresent() && !newValue.equals(childTag.get().getValue().orElse(null))) {
tag = (Xml.Tag) new ChangeTagValueVisitor<>(childTag.get(), newValue).visitNonNull(tag, ctx);
}
return tag;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.java.micronaut;

import org.openrewrite.ExecutionContext;
import org.openrewrite.HasSourcePath;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;

public class FindPropertiesConfig extends Recipe {
jeremyg484 marked this conversation as resolved.
Show resolved Hide resolved

@Override
public String getDisplayName() {
return "Find Micronaut properties config";
}

@Override
public String getDescription() {
return "Find Micronaut properties configuration files.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new HasSourcePath<>("**/{application,application-*,bootstrap,bootstrap-*}.{properties}");
}
}
Loading