diff --git a/plugin-modernizer-core/pom.xml b/plugin-modernizer-core/pom.xml index 2fc34f459..b1495cf2d 100644 --- a/plugin-modernizer-core/pom.xml +++ b/plugin-modernizer-core/pom.xml @@ -117,6 +117,10 @@ org.openrewrite rewrite-xml + + org.openrewrite.recipe + rewrite-apache + org.openrewrite.recipe rewrite-jenkins diff --git a/plugin-modernizer-core/src/main/jte/pr-body-MigrateCommonsLangToJdkApi.jte b/plugin-modernizer-core/src/main/jte/pr-body-MigrateCommonsLangToJdkApi.jte new file mode 100644 index 000000000..5992e62f2 --- /dev/null +++ b/plugin-modernizer-core/src/main/jte/pr-body-MigrateCommonsLangToJdkApi.jte @@ -0,0 +1,3 @@ +This PR migrates commons-lang usage to standard JDK APIs. + +It replaces commonly used Apache Commons Lang utility methods with equivalent methods from the Java standard library. \ No newline at end of file diff --git a/plugin-modernizer-core/src/main/jte/pr-title-MigrateCommonsLangToJdkApi.jte b/plugin-modernizer-core/src/main/jte/pr-title-MigrateCommonsLangToJdkApi.jte new file mode 100644 index 000000000..c36c4c7a5 --- /dev/null +++ b/plugin-modernizer-core/src/main/jte/pr-title-MigrateCommonsLangToJdkApi.jte @@ -0,0 +1 @@ +Migrate commons-lang usage to JDK APIs \ No newline at end of file diff --git a/plugin-modernizer-core/src/main/resources/META-INF/rewrite/recipes.yml b/plugin-modernizer-core/src/main/resources/META-INF/rewrite/recipes.yml index 16d129737..0c4539368 100644 --- a/plugin-modernizer-core/src/main/resources/META-INF/rewrite/recipes.yml +++ b/plugin-modernizer-core/src/main/resources/META-INF/rewrite/recipes.yml @@ -249,6 +249,16 @@ recipeList: - io.jenkins.tools.pluginmodernizer.core.recipes.MigrateToJenkinsBaseLineProperty --- type: specs.openrewrite.org/v1beta/recipe +name: io.jenkins.tools.pluginmodernizer.MigrateCommonsLangToJdkApi +displayName: Migrate commons-lang usage to JDK APIs +description: Replace commons-lang utility methods with modern JDK API equivalents using OpenRewrite. +tags: ['dependencies', 'migration'] +recipeList: + - org.openrewrite.apache.commons.lang.ApacheCommonsStringUtilsRecipes + - org.openrewrite.apache.commons.lang.IsNotEmptyToJdk + - org.openrewrite.java.RemoveUnusedImports +--- +type: specs.openrewrite.org/v1beta/recipe name: io.jenkins.tools.pluginmodernizer.AddCodeOwner displayName: Add CODEOWNERS file description: Adds a CODEOWNERS file to a Jenkins plugin. diff --git a/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/recipes/DeclarativeRecipesTest.java b/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/recipes/DeclarativeRecipesTest.java index a7b9c9a5c..1ea8bdfd6 100644 --- a/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/recipes/DeclarativeRecipesTest.java +++ b/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/recipes/DeclarativeRecipesTest.java @@ -3506,6 +3506,94 @@ public String getHtml() { """)); } + @Test + void migrateCommonsLangToJdkApi() { + rewriteRun( + spec -> { + var parser = JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true); + + collectRewriteTestDependencies().forEach(parser::addClasspathEntry); + + spec.recipeFromResource( + "/META-INF/rewrite/recipes.yml", + "io.jenkins.tools.pluginmodernizer.MigrateCommonsLangToJdkApi") + .parser(parser); + }, + // Stub + java(""" + package org.apache.commons.lang3; + public class StringUtils { + public static String defaultString(String str) { + return str == null ? "" : str; + } + public static String defaultString(String str, String defaultStr) { + return str == null ? defaultStr : str; + } + public static boolean isNotEmpty(String str) { + return str != null && !str.isEmpty(); + } + } + """), + // Input → Output + java(""" + import org.apache.commons.lang3.StringUtils; + + class MyComponent { + public String getDefault(String input) { + return StringUtils.defaultString(input); + } + public String getDefaultWithFallback(String input) { + return StringUtils.defaultString(input, "N/A"); + } + } + """, """ + import java.util.Objects; + + class MyComponent { + public String getDefault(String input) { + return Objects.toString(input, ""); + } + public String getDefaultWithFallback(String input) { + return Objects.toString(input, "N/A"); + } + } + """), + java(""" + import org.apache.commons.lang3.StringUtils; + + class Test { + boolean check(String str) { + return StringUtils.isNotEmpty(str); + } + } + """, """ + class Test { + boolean check(String str) { + return str != null && !str.isEmpty(); + } + } + """)); + } + + @Test + void noChangeWhenNoCommonsLang() { + rewriteRun( + spec -> { + var parser = JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true); + collectRewriteTestDependencies().forEach(parser::addClasspathEntry); + + spec.recipeFromResource( + "/META-INF/rewrite/recipes.yml", + "io.jenkins.tools.pluginmodernizer.MigrateCommonsLangToJdkApi") + .parser(parser); + }, + java(""" + class Test { + String s = "hello"; + } + """)); + } + @Test void migrateToJUnit5() { rewriteRun( diff --git a/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/utils/TemplateUtilsTest.java b/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/utils/TemplateUtilsTest.java index e9ea3ce9f..26f9d699e 100644 --- a/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/utils/TemplateUtilsTest.java +++ b/plugin-modernizer-core/src/test/java/io/jenkins/tools/pluginmodernizer/core/utils/TemplateUtilsTest.java @@ -1,6 +1,7 @@ package io.jenkins.tools.pluginmodernizer.core.utils; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -855,6 +856,46 @@ public void testFriendlyPrBodyMigrateCommonsLang2ToLang3AndCommonText() { "Description"); } + @Test + public void testFriendlyPrTitleMigrateCommonsLangToJdkApi() { + + // Mocks + Plugin plugin = mock(Plugin.class); + Recipe recipe = mock(Recipe.class); + + doReturn("io.jenkins.tools.pluginmodernizer.MigrateCommonsLangToJdkApi") + .when(recipe) + .getName(); + + // Test + String result = TemplateUtils.renderPullRequestTitle(plugin, recipe); + + // Assert + assertNotNull(result); + assertTrue(result.contains("commons-lang")); + assertEquals("Migrate commons-lang usage to JDK APIs", result); + } + + @Test + public void testFriendlyPrBodyMigrateCommonsLangToJdkApi() { + + // Mocks + Plugin plugin = mock(Plugin.class); + Recipe recipe = mock(Recipe.class); + + doReturn("io.jenkins.tools.pluginmodernizer.MigrateCommonsLangToJdkApi") + .when(recipe) + .getName(); + + // Test + String result = TemplateUtils.renderPullRequestBody(plugin, recipe); + + // Assert + assertNotNull(result); + assertTrue(result.contains("commons-lang")); + assertTrue(result.contains("standard JDK APIs")); + } + @Test public void testFriendlyPrTitleMigrateJavaxAnnotationsToSpotbugs() { diff --git a/scripts/validate_metadata.py b/scripts/validate_metadata.py index 6b7e788a5..5db5f9039 100644 --- a/scripts/validate_metadata.py +++ b/scripts/validate_metadata.py @@ -94,6 +94,7 @@ "io.jenkins.tools.pluginmodernizer.EnsureIndexJelly", "io.jenkins.tools.pluginmodernizer.MigrateTomakehurstToWiremock", "io.jenkins.tools.pluginmodernizer.MigrateCommonsLang2ToLang3AndCommonText", + "io.jenkins.tools.pluginmodernizer.MigrateCommonsLangToJdkApi", "io.jenkins.tools.pluginmodernizer.RemoveOldJavaVersionForModernJenkins", "io.jenkins.tools.pluginmodernizer.SwitchToRenovate", "io.jenkins.tools.pluginmodernizer.JavaxAnnotationsToSpotbugs",