diff --git a/.gitignore b/.gitignore index 261a2e0..7318773 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ .mtj.tmp/ # Package Files # -*.jar *.war *.nar *.ear diff --git a/build.gradle.kts b/build.gradle.kts index f2f3363..b8a0bd7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,5 +19,11 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-engine:latest.release") - testImplementation("com.launchdarkly:launchdarkly-java-server-sdk:5.10.+") + testRuntimeOnly("org.gradle:gradle-tooling-api:latest.release") } + +recipeDependencies { + parserClasspath("com.launchdarkly:launchdarkly-java-server-sdk:5.10.+") + parserClasspath("com.launchdarkly:launchdarkly-java-server-sdk:6.+") + //parserClasspath("com.launchdarkly:launchdarkly-java-server-sdk:7.+") +} \ No newline at end of file diff --git a/src/main/java/org/openrewrite/launchdarkly/MigrateUserToContext.java b/src/main/java/org/openrewrite/launchdarkly/MigrateUserToContext.java new file mode 100644 index 0000000..0ff577b --- /dev/null +++ b/src/main/java/org/openrewrite/launchdarkly/MigrateUserToContext.java @@ -0,0 +1,238 @@ +/* + * Copyright 2023 the original author or authors. + *

+ * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.launchdarkly; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.*; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.java.*; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Space; +import org.openrewrite.marker.Markers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static java.util.Objects.requireNonNull; + +@Value +@EqualsAndHashCode(callSuper = true) +public class MigrateUserToContext extends Recipe { + private static final MethodMatcher NEW_USER = new MethodMatcher("com.launchdarkly.sdk.LDUser (java.lang.String)"); + private static final MethodMatcher NEW_USER_BUILDER = new MethodMatcher("com.launchdarkly.sdk.LDUser.Builder (java.lang.String)"); + + private static final List BASIC_ATTRIBUTES = Arrays.asList("avatar", "country", "email", "firstName", "ip", "lastName"); + private static final List PRIVATE_ATTRIBUTES = Arrays.asList("privateAvatar", "privateCountry", "privateEmail", "privateFirstName", "privateIp", "privateLastName", "privateName"); + private static final MethodMatcher BUILTIN_ATTRIBUTE = new MethodMatcher("com.launchdarkly.sdk.LDUser.Builder *(java.lang.String)"); + private static final MethodMatcher BUILTIN_PRIVATE_ATTRIBUTE = new MethodMatcher("com.launchdarkly.sdk.LDUser.Builder private*(java.lang.String)"); + private static final MethodMatcher CUSTOM_ATTRIBUTES = new MethodMatcher("com.launchdarkly.sdk.LDUser.Builder custom(java.lang.String, ..)"); // FIXME: This really should be `*` + private static final MethodMatcher PRIVATE_CUSTOM_ATTRIBUTES = new MethodMatcher("com.launchdarkly.sdk.LDUser.Builder privateCustom(java.lang.String, ..)"); // FIXME: This really should be `*` + + @Override + public String getDisplayName() { + return "Migrate `LDUser` to `LDContext`"; + } + + @Override + public String getDescription() { + return "Migrate from `LDUser` and `LDUser.Builder` to `LDContext` and `ContextBuilder`."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + new UsesType<>("com.launchdarkly.sdk.LDUser", null), + new JavaVisitor() { + @Override + public J visitNewClass(J.NewClass newClass, ExecutionContext ctx) { + if (NEW_USER.matches(newClass)) { + maybeRemoveImport("com.launchdarkly.sdk.LDUser"); + maybeAddImport("com.launchdarkly.sdk.LDContext"); + doAfterVisit(new ChangeType("com.launchdarkly.sdk.LDUser", "com.launchdarkly.sdk.LDContext", null).getVisitor()); + return JavaTemplate.builder("LDContext.create(#{any(java.lang.String)})") + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "launchdarkly-java-server-sdk-6")) + .imports("com.launchdarkly.sdk.LDContext") + .build() + .apply(getCursor(), newClass.getCoordinates().replace(), newClass.getArguments().get(0)); + } else if (NEW_USER_BUILDER.matches(newClass)) { + maybeRemoveImport("com.launchdarkly.sdk.LDUser"); + maybeAddImport("com.launchdarkly.sdk.LDContext"); + doAfterVisit(new ChangeType("com.launchdarkly.sdk.LDUser", "com.launchdarkly.sdk.LDContext", null).getVisitor()); + return JavaTemplate.builder("LDContext.builder(#{any(java.lang.String)})") + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "launchdarkly-java-server-sdk-6")) + .imports("com.launchdarkly.sdk.LDContext") + .build() + .apply(getCursor(), newClass.getCoordinates().replace(), newClass.getArguments().get(0)); + } + + return super.visitNewClass(newClass, ctx); + } + + @Override + public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); + if (BUILTIN_ATTRIBUTE.matches(m) && BASIC_ATTRIBUTES.contains(m.getSimpleName())) { + String code; + if (requireNonNull(m.getPadding().getSelect()).getAfter().getWhitespace().contains("\n")) { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}\n.set(#{any(java.lang.String)}, #{any()})"; + } else { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}.set(#{any(java.lang.String)}, #{any()})"; + } + return JavaTemplate.builder(code) + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "launchdarkly-java-server-sdk-6")) + .imports("com.launchdarkly.sdk.ContextBuilder") + .build() + .apply( + getCursor(), + m.getCoordinates().replace(), + m.getSelect(), + new J.Literal(Tree.randomId(), Space.EMPTY, Markers.EMPTY, m.getSimpleName(), "\"" + m.getSimpleName() + "\"", null, JavaType.Primitive.String), + m.getArguments().get(0) + ); + } else if (BUILTIN_PRIVATE_ATTRIBUTE.matches(m) && PRIVATE_ATTRIBUTES.contains(m.getSimpleName())) { + doAfterVisit(new UseVarargsForPrivateAttributes()); + + String code; + if (requireNonNull(m.getPadding().getSelect()).getAfter().getWhitespace().contains("\n")) { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}\n.set(#{any(java.lang.String)}, #{any()})\n.privateAttributes(#{any(java.lang.String)})"; + } else { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}.set(#{any(java.lang.String)}, #{any()}).privateAttributes(#{any(java.lang.String)})"; + } + String attributeName = StringUtils.uncapitalize(m.getSimpleName().replace("private", "")); + return JavaTemplate.builder(code) + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "launchdarkly-java-server-sdk-6")) + .imports("com.launchdarkly.sdk.ContextBuilder") + .build() + .apply( + getCursor(), + m.getCoordinates().replace(), + m.getSelect(), + new J.Literal(Tree.randomId(), Space.EMPTY, Markers.EMPTY, attributeName, "\"" + attributeName + "\"", null, JavaType.Primitive.String), + m.getArguments().get(0), + new J.Literal(Tree.randomId(), Space.EMPTY, Markers.EMPTY, attributeName, "\"" + attributeName + "\"", null, JavaType.Primitive.String) + ); + } else if (CUSTOM_ATTRIBUTES.matches(m)) { + String code; + if (requireNonNull(m.getPadding().getSelect()).getAfter().getWhitespace().contains("\n")) { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}\n.set(#{any(java.lang.String)}, #{any()})"; + } else { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}.set(#{any(java.lang.String)}, #{any()})"; + } + return JavaTemplate.builder(code) + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "launchdarkly-java-server-sdk-6")) + .imports("com.launchdarkly.sdk.ContextBuilder") + .build() + .apply(getCursor(), m.getCoordinates().replace(), m.getSelect(), m.getArguments().get(0), m.getArguments().get(1)); + } else if (PRIVATE_CUSTOM_ATTRIBUTES.matches(m)) { + doAfterVisit(new UseVarargsForPrivateAttributes()); + + String code; + if (requireNonNull(m.getPadding().getSelect()).getAfter().getWhitespace().contains("\n")) { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}\n.set(#{any(java.lang.String)}, #{any()})\n.privateAttributes(#{any(java.lang.String)})"; + } else { + code = "#{any(com.launchdarkly.sdk.ContextBuilder)}.set(#{any(java.lang.String)}, #{any()}).privateAttributes(#{any(java.lang.String)})"; + } + return JavaTemplate.builder(code) + .contextSensitive() + .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "launchdarkly-java-server-sdk-6")) + .imports("com.launchdarkly.sdk.ContextBuilder") + .build() + .apply(getCursor(), m.getCoordinates().replace(), m.getSelect(), m.getArguments().get(0), m.getArguments().get(1), m.getArguments().get(0)); + } + return m; + } + } + ); + } + + private static class UseVarargsForPrivateAttributes extends JavaIsoVisitor { + private static final MethodMatcher CONTEXT_BUILDER_MATCHER = new MethodMatcher("com.launchdarkly.sdk.ContextBuilder *(..)"); + private static final MethodMatcher PRIVATE_ATTRIBUTES_STRING_VARARGS_MATCHER = new MethodMatcher("com.launchdarkly.sdk.ContextBuilder privateAttributes(java.lang.String...)"); + private static final MethodMatcher USER_BUILDER_BUILD_MATCHER = new MethodMatcher("com.launchdarkly.sdk.LDUser.Builder build()"); + private static final MethodMatcher CONTEXT_BUILDER_BUILD_MATCHER = new MethodMatcher("com.launchdarkly.sdk.ContextBuilder build()"); + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); + if (!(USER_BUILDER_BUILD_MATCHER.matches(m) || CONTEXT_BUILDER_BUILD_MATCHER.matches(m))) { + return m; + } + + List chain = computeChain(m); + return unfold(m, chain); + } + + private List computeChain(J.MethodInvocation build) { + List chain = new ArrayList<>(); + if (!(build.getSelect() instanceof J.MethodInvocation)) { + return chain; + } + + List attributes = new ArrayList<>(); + Expression select = build.getSelect(); + int privateAttributesInvocations = 0; + int lastPrivateAttributesIdx = -1; + while (CONTEXT_BUILDER_MATCHER.matches(select)) { + J.MethodInvocation m = (J.MethodInvocation) select; + if (PRIVATE_ATTRIBUTES_STRING_VARARGS_MATCHER.matches(m)) { + if (lastPrivateAttributesIdx == -1 && CONTEXT_BUILDER_MATCHER.matches(m.getSelect())) { + lastPrivateAttributesIdx = chain.size(); + chain.add(m); + } + attributes.addAll(0, m.getArguments()); + privateAttributesInvocations++; + } else { + chain.add(m); + } + select = m.getSelect(); + } + if (privateAttributesInvocations <= 1) { + return Collections.emptyList(); + } + for (int i = 1; i < attributes.size(); i++) { + attributes.set(i, attributes.get(i).withPrefix(Space.SINGLE_SPACE)); + } + chain.set(lastPrivateAttributesIdx, chain.get(lastPrivateAttributesIdx).withArguments(attributes)); + return chain; + } + + private J.MethodInvocation unfold(J.MethodInvocation build, List chain) { + if (chain.isEmpty()) { + return build; + } + Collections.reverse(chain); + + J.MethodInvocation select = chain.get(0); + for (int i = 1; i < chain.size(); i++) { + select = chain.get(i) + .withId(Tree.randomId()) + .withSelect(select); + } + return build.withSelect(select); + } + } +} diff --git a/src/main/resources/META-INF/rewrite/classpath/launchdarkly-java-server-sdk-5.10.9.jar b/src/main/resources/META-INF/rewrite/classpath/launchdarkly-java-server-sdk-5.10.9.jar new file mode 100644 index 0000000..b04b6d0 Binary files /dev/null and b/src/main/resources/META-INF/rewrite/classpath/launchdarkly-java-server-sdk-5.10.9.jar differ diff --git a/src/main/resources/META-INF/rewrite/classpath/launchdarkly-java-server-sdk-6.3.0.jar b/src/main/resources/META-INF/rewrite/classpath/launchdarkly-java-server-sdk-6.3.0.jar new file mode 100644 index 0000000..e156e59 Binary files /dev/null and b/src/main/resources/META-INF/rewrite/classpath/launchdarkly-java-server-sdk-6.3.0.jar differ diff --git a/src/main/resources/META-INF/rewrite/launchdarkly-6.yml b/src/main/resources/META-INF/rewrite/launchdarkly-6.yml index 8d8e90d..2068be9 100644 --- a/src/main/resources/META-INF/rewrite/launchdarkly-6.yml +++ b/src/main/resources/META-INF/rewrite/launchdarkly-6.yml @@ -21,15 +21,8 @@ displayName: Migrate to LaunchDarkly 6.x description: This recipe will apply changes commonly needed when migrating to LaunchDarkly 6.x. recipeList: # https://docs.launchdarkly.com/sdk/server-side/java/migration-5-to-6 - - org.openrewrite.launchdarkly.UpgradeLaunchDarkly6Dependencies - ---- -type: specs.openrewrite.org/v1beta/recipe -name: org.openrewrite.launchdarkly.UpgradeLaunchDarkly6Dependencies -displayName: Migrate LaunchDarkly dependencies to 6.x -description: Migrate LaunchDarkly dependencies to 6.x. -recipeList: - - org.openrewrite.java.dependencies.ChangeDependency: - oldGroupId: com.launchdarkly - oldArtifactId: launchdarkly-java-server-sdk + - org.openrewrite.java.dependencies.UpgradeDependencyVersion: + groupId: com.launchdarkly + artifactId: launchdarkly-java-server-sdk newVersion: 6.x + - org.openrewrite.launchdarkly.MigrateUserToContext diff --git a/src/main/resources/META-INF/rewrite/launchdarkly-7.yml b/src/main/resources/META-INF/rewrite/launchdarkly-7.yml new file mode 100644 index 0000000..21686cd --- /dev/null +++ b/src/main/resources/META-INF/rewrite/launchdarkly-7.yml @@ -0,0 +1,28 @@ +# +# Copyright 2023 the original author or authors. +#

+# 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 +#

+# https://www.apache.org/licenses/LICENSE-2.0 +#

+# 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. +# + +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.launchdarkly.UpgradeLaunchDarkly7 +displayName: Migrate to LaunchDarkly 7.x +description: This recipe will apply changes commonly needed when migrating to LaunchDarkly 7.x. +recipeList: + - org.openrewrite.launchdarkly.UpgradeLaunchDarkly6 + # https://docs.launchdarkly.com/sdk/server-side/java/migration-6-to-7 + - org.openrewrite.java.dependencies.UpgradeDependencyVersion: + groupId: com.launchdarkly + artifactId: launchdarkly-java-server-sdk + newVersion: 7.x diff --git a/src/test/java/org/openrewrite/launchdarkly/MigrateUserToContextTest.java b/src/test/java/org/openrewrite/launchdarkly/MigrateUserToContextTest.java new file mode 100644 index 0000000..ea8b23d --- /dev/null +++ b/src/test/java/org/openrewrite/launchdarkly/MigrateUserToContextTest.java @@ -0,0 +1,137 @@ +/* + * Copyright 2021 the original author or authors. + *

+ * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.launchdarkly; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class MigrateUserToContextTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new MigrateUserToContext()) + .parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "launchdarkly-java-server-sdk-5")); + } + + @Test + @DocumentExample + void builderUserToContext() { + rewriteRun( + //language=java + java( + """ + import com.launchdarkly.sdk.LDUser; + import com.launchdarkly.sdk.LDValue; + + class A { + void foo() { + LDUser user = new LDUser.Builder("user-key-123abc") + .name("Sandy") + .email("sandy@example.com") + .custom("groups", LDValue.buildArray().add("Google").add("Microsoft").build()) + .build(); + } + } + """, + """ + import com.launchdarkly.sdk.LDContext; + import com.launchdarkly.sdk.LDValue; + + class A { + void foo() { + LDContext user = LDContext.builder("user-key-123abc") + .name("Sandy") + .set("email", "sandy@example.com") + .set("groups", LDValue.buildArray().add("Google").add("Microsoft").build()) + .build(); + } + } + """ + ) + ); + } + + @Test + void userToContext() { + rewriteRun( + //language=java + java( + """ + import com.launchdarkly.sdk.LDUser; + + class A { + void foo() { + LDUser user = new LDUser("user-key-123abc"); + } + } + """, + """ + import com.launchdarkly.sdk.LDContext; + + class A { + void foo() { + LDContext user = LDContext.create("user-key-123abc"); + } + } + """ + ) + ); + } + + @Test + void privateAttribute() { + rewriteRun( + //language=java + java( + """ + import com.launchdarkly.sdk.LDUser; + import com.launchdarkly.sdk.LDValue; + + class A { + void foo() { + LDUser user = new LDUser.Builder("user-key-123abc") + .name("Sandy") + .privateEmail("sandy@example.com") + .privateCustom("groups", LDValue.buildArray().add("Google").add("Microsoft").build()) + .build(); + } + } + """, + """ + import com.launchdarkly.sdk.LDContext; + import com.launchdarkly.sdk.LDValue; + + class A { + void foo() { + LDContext user = LDContext.builder("user-key-123abc") + .name("Sandy") + .set("email", "sandy@example.com") + .set("groups", LDValue.buildArray().add("Google").add("Microsoft").build()) + .privateAttributes("email", "groups") + .build(); + } + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/launchdarkly/UpgradeLaunchDarkly6Test.java b/src/test/java/org/openrewrite/launchdarkly/UpgradeLaunchDarkly6Test.java index fe204b2..4c7cf34 100644 --- a/src/test/java/org/openrewrite/launchdarkly/UpgradeLaunchDarkly6Test.java +++ b/src/test/java/org/openrewrite/launchdarkly/UpgradeLaunchDarkly6Test.java @@ -15,11 +15,9 @@ */ package org.openrewrite.launchdarkly; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; -import org.openrewrite.config.Environment; +import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -28,108 +26,104 @@ import java.util.regex.Pattern; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.gradle.Assertions.buildGradle; +import static org.openrewrite.gradle.Assertions.withToolingApi; import static org.openrewrite.maven.Assertions.pomXml; class UpgradeLaunchDarkly6Test implements RewriteTest { - @Override public void defaults(RecipeSpec spec) { - spec.recipe(Environment.builder() - .scanRuntimeClasspath("org.openrewrite.launchdarkly") - .build() - .activateRecipes("org.openrewrite.launchdarkly.UpgradeLaunchDarkly6")) - .parser(JavaParser.fromJavaVersion().classpath("launchdarkly-java-server-sdk")); + spec.recipeFromResource("/META-INF/rewrite/launchdarkly-6.yml", "org.openrewrite.launchdarkly.UpgradeLaunchDarkly6") + .parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "launchdarkly-java-server-sdk-5")); } - @Nested - class Dependencies { - @Test - @DocumentExample - void mavenDependency() { - rewriteRun( - //language=xml - pomXml( - """ - - - 4.0.0 - com.example - demo - 0.0.1-SNAPSHOT - - - com.launchdarkly - launchdarkly-java-server-sdk - 5.10.9 - - - - """, - spec -> spec.after(actual -> { - Matcher matcher = Pattern.compile("(6\\.\\d\\.\\d+)").matcher(actual); - assertTrue(matcher.find(), actual); - return """ - - - 4.0.0 - com.example - demo - 0.0.1-SNAPSHOT - - - com.launchdarkly - launchdarkly-java-server-sdk - %s - - - - """.formatted(matcher.group(1)); - } - ) - ) - ); - } + @Test + @DocumentExample("Maven") + void mavenDependency() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + com.launchdarkly + launchdarkly-java-server-sdk + 5.10.9 + + + + """, + spec -> spec.after(actual -> { + Matcher matcher = Pattern.compile("(6\\.\\d\\.\\d+)").matcher(actual); + assertTrue(matcher.find(), actual); + return """ + + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + com.launchdarkly + launchdarkly-java-server-sdk + %s + + + + """.formatted(matcher.group(1)); + } + ) + ) + ); } - - @Nested - class CodeChanges { - @Test - @DocumentExample - @Disabled("Not yet implemented") - void userToContext() { - rewriteRun( - //language=java - java( - """ - class A { - void foo() { - LDUser user = new LDUser.Builder("user-key-123abc") - .name("Sandy") - .email("sandy@example.com") - .custom("groups", - LDValue.buildArray().add("Google").add("Microsoft").build()) - .build(); + @Test + @DocumentExample("Gradle") + void gradleDependency() { + rewriteRun( + spec -> spec.beforeRecipe(withToolingApi()), + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation "com.launchdarkly:launchdarkly-java-server-sdk:5.10.9" + } + """, + spec -> spec.after(actual -> { + Matcher matcher = Pattern.compile("com\\.launchdarkly:launchdarkly-java-server-sdk:(6\\.\\d+\\.\\d+)").matcher(actual); + assertTrue(matcher.find(), actual); + return """ + plugins { + id "java" + } + + repositories { + mavenCentral() } - } - """, - """ - class A { - void foo() { - LDContext context = LDContext.builder("user-key-123abc") - .name("Sandy") - .set("email", "sandy@example.com") - .set("groups", - LDValue.buildArray().add("Google").add("Microsoft").build()) - .build(); + + dependencies { + implementation "com.launchdarkly:launchdarkly-java-server-sdk:%s" } - } - """ - ) - ); - } + """.formatted(matcher.group(1)); + } + ) + ) + ); } -} \ No newline at end of file +} diff --git a/src/test/java/org/openrewrite/launchdarkly/UpgradeLaunchDarkly7Test.java b/src/test/java/org/openrewrite/launchdarkly/UpgradeLaunchDarkly7Test.java new file mode 100644 index 0000000..7ed5b14 --- /dev/null +++ b/src/test/java/org/openrewrite/launchdarkly/UpgradeLaunchDarkly7Test.java @@ -0,0 +1,138 @@ +/* + * Copyright 2021 the original author or authors. + *

+ * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.launchdarkly; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.config.Environment; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.openrewrite.gradle.Assertions.buildGradle; +import static org.openrewrite.gradle.Assertions.withToolingApi; +import static org.openrewrite.maven.Assertions.pomXml; + +class UpgradeLaunchDarkly7Test implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(Environment.builder() + .scanRuntimeClasspath("org.openrewrite.launchdarkly") + .build() + .activateRecipes("org.openrewrite.launchdarkly.UpgradeLaunchDarkly7")) + .parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "launchdarkly-java-server-sdk-6")); + } + + @Nested + class Dependencies { + @Test + @DocumentExample("Maven") + void mavenDependency() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + com.launchdarkly + launchdarkly-java-server-sdk + 6.3.0 + + + + """, + spec -> spec.after(actual -> { + Matcher matcher = Pattern.compile("(7\\.\\d\\.\\d+)").matcher(actual); + assertTrue(matcher.find(), actual); + return """ + + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + com.launchdarkly + launchdarkly-java-server-sdk + %s + + + + """.formatted(matcher.group(1)); + } + ) + ) + ); + } + + @Test + @DocumentExample("Gradle") + void gradleDependency() { + rewriteRun( + spec -> spec.beforeRecipe(withToolingApi()), + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation "com.launchdarkly:launchdarkly-java-server-sdk:6.3.0" + } + """, + spec -> spec.after(actual -> { + Matcher matcher = Pattern.compile("com\\.launchdarkly:launchdarkly-java-server-sdk:(7\\.\\d+\\.\\d+)").matcher(actual); + assertTrue(matcher.find(), actual); + return """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation "com.launchdarkly:launchdarkly-java-server-sdk:%s" + } + """.formatted(matcher.group(1)); + } + ) + ) + ); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/openrewrite/launchdarkly/search/FindFeatureFlagTest.java b/src/test/java/org/openrewrite/launchdarkly/search/FindFeatureFlagTest.java index 5fb0ad8..6e0286f 100644 --- a/src/test/java/org/openrewrite/launchdarkly/search/FindFeatureFlagTest.java +++ b/src/test/java/org/openrewrite/launchdarkly/search/FindFeatureFlagTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -26,7 +27,7 @@ class FindFeatureFlagTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.parser(JavaParser.fromJavaVersion().classpath("launchdarkly-java-server-sdk")); + spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "launchdarkly-java-server-sdk-5")); } @Test @@ -34,6 +35,7 @@ public void defaults(RecipeSpec spec) { void findFeatureFlag() { rewriteRun( spec -> spec.recipe(new FindFeatureFlag(null, null)), + //language=java java( """ import com.launchdarkly.sdk.LDUser; @@ -81,6 +83,7 @@ public void a() { void findFeatureFlagByType() { rewriteRun( spec -> spec.recipe(new FindFeatureFlag(FindFeatureFlag.FeatureFlagType.Bool, null)), + //language=java java( """ import com.launchdarkly.sdk.LDUser; @@ -140,6 +143,7 @@ public void a() { void findFeatureFlagByName() { rewriteRun( spec -> spec.recipe(new FindFeatureFlag(null, "flag-key-123abc")), + //language=java java( """ import com.launchdarkly.sdk.LDUser; @@ -199,6 +203,7 @@ public void a() { void findFeatureFlagByTypeAndName() { rewriteRun( spec -> spec.recipe(new FindFeatureFlag(FindFeatureFlag.FeatureFlagType.Bool, "flag-key-123abc")), + //language=java java( """ import com.launchdarkly.sdk.LDUser; @@ -258,6 +263,7 @@ public void a() { void findFlagByNameUsingVariable() { rewriteRun( spec -> spec.recipe(new FindFeatureFlag(null, "flag-key-123abc")), + //language=java java( """ import com.launchdarkly.sdk.LDUser;