From deb7f462af828ca1da72f45ed0eca49281e94af7 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Wed, 26 Feb 2025 11:07:54 +0100 Subject: [PATCH 01/17] add: add help information for the rewrite command --- cli/src/main/resources/nls/Help.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index 3c7ac3fa87..1b6ea67b06 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -83,6 +83,8 @@ cmd.quarkus.detail=Quarkus is a Kubernetes-native Java framework for building cl cmd.repository=Set up pre-configured git repositories using 'ide repository setup ' cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/.properties' and can therefore be shared with your project team for automatic or optional setup. cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. +cmd.rewrite=Refactor existing code base with specific recipes provided by OpenRewrite +cmd.rewrite.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ cmd.set-edition=Set the edition of the selected tool. cmd.set-edition.detail=This will set the according tool edition variable in your configuration file. If you want to roll out such change and share it with your team, you can commit and push your settings git repository.\nBy default these changes are saved in the project specific settings. Use --conf --home or --workspace to specify otherwise. cmd.set-edition.opt.--cfg=Selection of the configuration file (settings | home | conf | workspace). From 0b18f92fdf9c5021c8c7bb15113e7550d73cf4bf Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Mon, 3 Mar 2025 08:56:30 +0100 Subject: [PATCH 02/17] add: add help information for the rewrite command --- .../ide/commandlet/CommandletManagerImpl.java | 2 + .../tools/ide/tool/rewrite/Rewrite.java | 47 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java index 3083ae283e..6a3ae994b4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java @@ -40,6 +40,7 @@ import com.devonfw.tools.ide.tool.oc.Oc; import com.devonfw.tools.ide.tool.pgadmin.PgAdmin; import com.devonfw.tools.ide.tool.quarkus.Quarkus; +import com.devonfw.tools.ide.tool.rewrite.Rewrite; import com.devonfw.tools.ide.tool.sonar.Sonar; import com.devonfw.tools.ide.tool.terraform.Terraform; import com.devonfw.tools.ide.tool.tomcat.Tomcat; @@ -101,6 +102,7 @@ public CommandletManagerImpl(IdeContext context) { add(new Node(context)); add(new Npm(context)); add(new Mvn(context)); + add(new Rewrite(context)); add(new GcViewer(context)); add(new Gradle(context)); add(new Eclipse(context)); diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java b/cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java new file mode 100644 index 0000000000..019adcd9f5 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java @@ -0,0 +1,47 @@ +package com.devonfw.tools.ide.tool.rewrite; + +import com.devonfw.tools.ide.common.Tag; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.step.Step; +import com.devonfw.tools.ide.tool.ToolCommandlet; +import com.devonfw.tools.ide.tool.plugin.PluginBasedCommandlet; +import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor; + +import java.util.Set; + +/** + * {@link ToolCommandlet} for Rewrite. + */ +public class Rewrite extends PluginBasedCommandlet { + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + * @param tool the {@link #getName() tool name}. + * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method. + */ + public Rewrite(IdeContext context, String tool, Set tags) { + super(context, tool, tags); + } + + /** + * we do not need to do anything because right now we will only call OpenRewrite in the command line form + * @param plugin the {@link ToolPluginDescriptor} to install. + * @param step the {@link Step} for the plugin installation. + */ + @Override + public void installPlugin(ToolPluginDescriptor plugin, Step step) { + //do nothing + } + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + */ + public Rewrite(IdeContext context) { + + super(context, "rewrite", Set.of(Tag.JAVA)); + } +} From 2eecccc2d423476096251de15ced2eec8b08bc3a Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Thu, 6 Mar 2025 09:54:32 +0100 Subject: [PATCH 03/17] add: add help information for the rewrite command --- .../devonfw/tools/ide/commandlet/CommandletManagerImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java index 6a3ae994b4..258bc7a83a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java @@ -40,7 +40,6 @@ import com.devonfw.tools.ide.tool.oc.Oc; import com.devonfw.tools.ide.tool.pgadmin.PgAdmin; import com.devonfw.tools.ide.tool.quarkus.Quarkus; -import com.devonfw.tools.ide.tool.rewrite.Rewrite; import com.devonfw.tools.ide.tool.sonar.Sonar; import com.devonfw.tools.ide.tool.terraform.Terraform; import com.devonfw.tools.ide.tool.tomcat.Tomcat; @@ -102,7 +101,7 @@ public CommandletManagerImpl(IdeContext context) { add(new Node(context)); add(new Npm(context)); add(new Mvn(context)); - add(new Rewrite(context)); + add(new RefactorCommandlet(context)); add(new GcViewer(context)); add(new Gradle(context)); add(new Eclipse(context)); From d746c6a3e6dac57a369ecf9b3076ac32736fb642 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Thu, 6 Mar 2025 09:54:42 +0100 Subject: [PATCH 04/17] add: add help information for the rewrite command --- cli/src/main/resources/nls/Help.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index 1b6ea67b06..afed28bba1 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -83,8 +83,8 @@ cmd.quarkus.detail=Quarkus is a Kubernetes-native Java framework for building cl cmd.repository=Set up pre-configured git repositories using 'ide repository setup ' cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/.properties' and can therefore be shared with your project team for automatic or optional setup. cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. -cmd.rewrite=Refactor existing code base with specific recipes provided by OpenRewrite -cmd.rewrite.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ +cmd.refactor=Refactor existing code base with specific recipes provided by OpenRewrite +cmd.refactor.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ cmd.set-edition=Set the edition of the selected tool. cmd.set-edition.detail=This will set the according tool edition variable in your configuration file. If you want to roll out such change and share it with your team, you can commit and push your settings git repository.\nBy default these changes are saved in the project specific settings. Use --conf --home or --workspace to specify otherwise. cmd.set-edition.opt.--cfg=Selection of the configuration file (settings | home | conf | workspace). From a7a0312a21fccec95f4d0d155467be577dbb3213 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Thu, 6 Mar 2025 09:57:45 +0100 Subject: [PATCH 05/17] update: add necessary commandlet and property --- .../ide/commandlet/RefactorCommandlet.java | 41 +++++++++++++++ .../ide/property/RefactorRecipeProperty.java | 50 +++++++++++++++++++ .../tools/ide/tool/rewrite/Rewrite.java | 47 ----------------- 3 files changed, 91 insertions(+), 47 deletions(-) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java create mode 100644 cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java delete mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java new file mode 100644 index 0000000000..751cc9c42a --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java @@ -0,0 +1,41 @@ +package com.devonfw.tools.ide.commandlet; + +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.property.StringProperty; +import com.devonfw.tools.ide.tool.ToolCommandlet; + +/** + * {@link ToolCommandlet} for Refactor. + */ +public class RefactorCommandlet extends Commandlet { + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + */ + public RefactorCommandlet(IdeContext context) { + + super(context); + addKeyword(getName()); + add(new StringProperty("recipe", true, true, "")); + } + + @Override + public String getName() { + return "refactor"; + } + + @Override + public void run() { + //3 branches + //1. list available recipes + //2. execute the exact recipe + } + + @Override + public boolean isIdeHomeRequired() { + + return false; + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java b/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java new file mode 100644 index 0000000000..04a1321aa8 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java @@ -0,0 +1,50 @@ +package com.devonfw.tools.ide.property; + +import com.devonfw.tools.ide.commandlet.Commandlet; +import com.devonfw.tools.ide.completion.CompletionCandidateCollector; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.tool.ToolCommandlet; +import com.devonfw.tools.ide.tool.plugin.PluginBasedCommandlet; +import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor; +import com.devonfw.tools.ide.tool.plugin.ToolPlugins; +import com.devonfw.tools.ide.validation.PropertyValidator; + +public class RefactorRecipeProperty extends Property { + + public RefactorRecipeProperty(String name) { + + this(name, null); + } + + public RefactorRecipeProperty(String name, PropertyValidator validator) { + + super(name, true, null, true, validator); + } + + @Override + public Class getValueType() { + + return String.class; + } + + @Override + public String parse(String valueAsString, IdeContext context) { + + return valueAsString; + } + + @Override + protected void completeValue(String arg, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) { + + ToolCommandlet cmd = commandlet.getToolForCompletion(); + if (cmd instanceof PluginBasedCommandlet pbc) { + ToolPlugins plugins = pbc.getPlugins(); + for (ToolPluginDescriptor pluginDescriptor : plugins.getPlugins()) { + if (pluginDescriptor.name().toLowerCase().startsWith(arg.toLowerCase())) { + collector.add(pluginDescriptor.name(), null, null, commandlet); + } + } + } + } + +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java b/cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java deleted file mode 100644 index 019adcd9f5..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/rewrite/Rewrite.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.devonfw.tools.ide.tool.rewrite; - -import com.devonfw.tools.ide.common.Tag; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.step.Step; -import com.devonfw.tools.ide.tool.ToolCommandlet; -import com.devonfw.tools.ide.tool.plugin.PluginBasedCommandlet; -import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor; - -import java.util.Set; - -/** - * {@link ToolCommandlet} for Rewrite. - */ -public class Rewrite extends PluginBasedCommandlet { - - /** - * The constructor. - * - * @param context the {@link IdeContext}. - * @param tool the {@link #getName() tool name}. - * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method. - */ - public Rewrite(IdeContext context, String tool, Set tags) { - super(context, tool, tags); - } - - /** - * we do not need to do anything because right now we will only call OpenRewrite in the command line form - * @param plugin the {@link ToolPluginDescriptor} to install. - * @param step the {@link Step} for the plugin installation. - */ - @Override - public void installPlugin(ToolPluginDescriptor plugin, Step step) { - //do nothing - } - - /** - * The constructor. - * - * @param context the {@link IdeContext}. - */ - public Rewrite(IdeContext context) { - - super(context, "rewrite", Set.of(Tag.JAVA)); - } -} From 6970443801a004517af49f3b57bf2c810fbea8e9 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Tue, 26 Aug 2025 11:33:29 +0200 Subject: [PATCH 06/17] add: help message for RefactorCommandlet --- cli/src/main/resources/nls/Help.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index fd58bb84d7..d6db316d89 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -89,6 +89,7 @@ cmd.repository.detail=Without further arguments this will set up all pre-configu cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. cmd.refactor=Refactor existing code base with specific recipes provided by OpenRewrite cmd.refactor.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ +cmd.refactor.val.recipe_name=Refactor recipe names (RECIPE_1|RECIPE_2|RECIPE_3) cmd.set-edition=Set the edition of the selected tool. cmd.set-edition.detail=This will set the according tool edition variable in your configuration file. If you want to roll out such change and share it with your team, you can commit and push your settings git repository.\nBy default these changes are saved in the project specific settings. Use --conf --home or --workspace to specify otherwise. cmd.set-edition.opt.--cfg=Selection of the configuration file (settings | home | conf | workspace). @@ -153,5 +154,6 @@ val.plugin=The plugin to select val.settingsRepository=The settings git repository with the IDEasy configuration for the project. val.tool=The tool commandlet to select. val.version=The tool version. +val.recipe_extra_arguments=possible additional arguments for the recipe values=Values: version-banner=Current version of IDE is {} From 10f82d70b32e34f4faaa7e1aa970dd89af8e8a64 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Tue, 26 Aug 2025 11:35:09 +0200 Subject: [PATCH 07/17] add: wrapper of the configurable recipe --- .../ide/tool/openrewrite/RecipeWrapper.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java new file mode 100644 index 0000000000..c13de47c0b --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java @@ -0,0 +1,17 @@ +package com.devonfw.tools.ide.tool.openrewrite; + +import java.util.Locale; + +public class RecipeWrapper { + public String description; + public String origin_name; + public String url; + public RefactorRecipeEnum ideasy_command; + public String raw_cmd; + + //in case of future need + public String getName() { + return this.origin_name; + } + +} From 5e29a3aa0130faad48f4e58087bd626e40eb8a5d Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Tue, 26 Aug 2025 11:35:43 +0200 Subject: [PATCH 08/17] update: two configuration files (more recipes can be added in this way) --- cli/src/main/resources/refactor/openrewrite.json | 16 ++++++++++++++++ cli/src/test/resources/refactor/openrewrite.json | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 cli/src/main/resources/refactor/openrewrite.json create mode 100644 cli/src/test/resources/refactor/openrewrite.json diff --git a/cli/src/main/resources/refactor/openrewrite.json b/cli/src/main/resources/refactor/openrewrite.json new file mode 100644 index 0000000000..4ed6375340 --- /dev/null +++ b/cli/src/main/resources/refactor/openrewrite.json @@ -0,0 +1,16 @@ +[ + { + "origin_name": "java.format_java_code", + "ideasy_command": "FORMAT_JAVA_CODE", + "description": "Format Java code using a standard comprehensive set of Java formatting recipes.", + "url": "https://docs.openrewrite.org/recipes/java/format/autoformat", + "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.AutoFormat -Drewrite.exportDatatables=true" + }, + { + "origin_name": "java.remove_blank_lines", + "ideasy_command": "REMOVE_BLANK_LINES", + "description": "Add and/or remove blank lines.", + "url": "https://docs.openrewrite.org/recipes/java/format/blanklines", + "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.BlankLines -Drewrite.exportDatatables=true" + } +] diff --git a/cli/src/test/resources/refactor/openrewrite.json b/cli/src/test/resources/refactor/openrewrite.json new file mode 100644 index 0000000000..4ed6375340 --- /dev/null +++ b/cli/src/test/resources/refactor/openrewrite.json @@ -0,0 +1,16 @@ +[ + { + "origin_name": "java.format_java_code", + "ideasy_command": "FORMAT_JAVA_CODE", + "description": "Format Java code using a standard comprehensive set of Java formatting recipes.", + "url": "https://docs.openrewrite.org/recipes/java/format/autoformat", + "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.AutoFormat -Drewrite.exportDatatables=true" + }, + { + "origin_name": "java.remove_blank_lines", + "ideasy_command": "REMOVE_BLANK_LINES", + "description": "Add and/or remove blank lines.", + "url": "https://docs.openrewrite.org/recipes/java/format/blanklines", + "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.BlankLines -Drewrite.exportDatatables=true" + } +] From 3f843e3325580c4d8fd14f99f5df9f6ce8729391 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Tue, 26 Aug 2025 11:37:03 +0200 Subject: [PATCH 09/17] update: keep names consistent with the names in the config file --- .../tools/ide/tool/openrewrite/RefactorRecipeEnum.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java new file mode 100644 index 0000000000..e2761b32bd --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java @@ -0,0 +1,5 @@ +package com.devonfw.tools.ide.tool.openrewrite; + +public enum RefactorRecipeEnum { + FORMAT_JAVA_CODE, REMOVE_BLANK_LINES +} From faa40be4bb159d931dd0867b116238eb87f9e5a1 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Tue, 26 Aug 2025 11:55:38 +0200 Subject: [PATCH 10/17] add: placeholder enum --- .../devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java index e2761b32bd..c72c299526 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java @@ -1,5 +1,5 @@ package com.devonfw.tools.ide.tool.openrewrite; public enum RefactorRecipeEnum { - FORMAT_JAVA_CODE, REMOVE_BLANK_LINES + FORMAT_JAVA_CODE, REMOVE_BLANK_LINES, UNRECOGNIZED_RECIPE } From 35eb98c32c80f06210569d5135f036a788d84b08 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Tue, 26 Aug 2025 11:57:01 +0200 Subject: [PATCH 11/17] update: finish the implementation --- .../ide/commandlet/RefactorCommandlet.java | 76 ++++++++++++++++++- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java index 751cc9c42a..c7028470d7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java @@ -1,14 +1,27 @@ package com.devonfw.tools.ide.commandlet; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.property.EnumProperty; import com.devonfw.tools.ide.property.StringProperty; import com.devonfw.tools.ide.tool.ToolCommandlet; +import com.devonfw.tools.ide.tool.mvn.Mvn; +import com.devonfw.tools.ide.tool.openrewrite.RecipeManager; +import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper; +import com.devonfw.tools.ide.tool.openrewrite.RefactorRecipeEnum; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Scanner; /** * {@link ToolCommandlet} for Refactor. */ public class RefactorCommandlet extends Commandlet { + public final EnumProperty command; + public final StringProperty arguments; + private RecipeManager recipeManager; /** * The constructor. * @@ -18,19 +31,74 @@ public RefactorCommandlet(IdeContext context) { super(context); addKeyword(getName()); - add(new StringProperty("recipe", true, true, "")); + this.command = add(new EnumProperty<>("", true, "recipe_name", RefactorRecipeEnum.class)); + this.arguments = new StringProperty("", false, true, "recipe_extra_arguments"); + recipeManager = new RecipeManager(); + add(this.arguments); + //this.recipe = context. } @Override public String getName() { + //this indicates the command name return "refactor"; } + private String[] adaptMVNCommand(String recipeRawCommands) { + if(recipeRawCommands.startsWith("mvn")) { + return recipeRawCommands.replaceFirst("\\Qmvn\\E", "").split("\\s+"); + } else { + return recipeRawCommands.split("\\s+"); + } + } + + private String changeToDryRunCommand(String recipeRawCommands) { + return recipeRawCommands.replaceAll(":run\\b", ":dryrun"); + } + + private void showInfo(RecipeWrapper wrapper) { + context.info("Recipe [{}], {} ", wrapper.ideasy_command.name(), wrapper.description); + context.info("Reference {}", wrapper.url); + context.info("Raw command: {}", wrapper.raw_cmd); + } + + private boolean confirmApplyChange() { + context.info("***Before making actual changes to the code, please confirm it seriously. It is strongly recommended to perform a DRY-RUN first***"); + context.info("Type yes to apply changes, or press other keys to perform DRY-RUN: "); + + Scanner scanner = new Scanner(System.in); + String input = scanner.nextLine(); + + return (input.equalsIgnoreCase("yes")); + } + @Override public void run() { - //3 branches - //1. list available recipes - //2. execute the exact recipe + + context.info("{} called", getClass().getSimpleName()); + + RefactorRecipeEnum command = this.command.getValue(); + String option = this.arguments.getValue(); + + if(!recipeManager.isValidRecipeEnum(command)) { + context.error("INVALID recipe name: {}", command); + return; + } + + RecipeWrapper wrapper = recipeManager.getRecipeWrapper(command); + + showInfo(wrapper); + + String commandLine = wrapper.raw_cmd; + + if(!confirmApplyChange()) { + commandLine = changeToDryRunCommand(commandLine); + } + + context.info("Actual command line: {}", commandLine); + + getCommandlet(Mvn.class).runTool(adaptMVNCommand(commandLine)); + } @Override From 7bffb92dcca8f4787bb268f373213ddd7053e63b Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Tue, 26 Aug 2025 11:57:25 +0200 Subject: [PATCH 12/17] update: finish the feature --- .../ide/tool/openrewrite/RecipeManager.java | 62 +++++++++++++++++++ .../tool/openrewrite/RecipeManagerTest.java | 37 +++++++++++ 2 files changed, 99 insertions(+) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java create mode 100644 cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java new file mode 100644 index 0000000000..530606dcde --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java @@ -0,0 +1,62 @@ +package com.devonfw.tools.ide.tool.openrewrite; + +import com.devonfw.tools.ide.json.JsonMapping; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + + +public class RecipeManager { + + private static final String OPEN_REWRITE_CONFIG_JSON_PATH = "refactor/openrewrite.json"; + private final Map recipes = new HashMap<>(); + + + public RecipeManager() { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader( + Objects.requireNonNull(RecipeManager.class.getClassLoader().getResourceAsStream(OPEN_REWRITE_CONFIG_JSON_PATH)), StandardCharsets.UTF_8)); + ObjectMapper objectMapper = JsonMapping.create(); + + List wrapperList = objectMapper.readValue(reader, objectMapper.getTypeFactory().constructCollectionType(List.class, RecipeWrapper.class)); + + for(RecipeWrapper one: wrapperList) { + recipes.put(one.ideasy_command, one); + } + + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public List listAvailableRecipes() { + return Collections.unmodifiableList(recipes.values().stream().toList()); + } + + private Optional findRecipeByName(String rawName) { + return recipes.values().stream().filter(x -> x.origin_name.equals(rawName)).findAny(); + } + + public boolean isValidRecipeNameRawName(String rawName) { + return findRecipeByName(rawName).isPresent(); + } + + public boolean isValidRecipeEnum(RefactorRecipeEnum recipeEnum) { + return recipes.containsKey(recipeEnum); + } + + public RecipeWrapper getRecipeWrapper(RefactorRecipeEnum recipeEnum) { + return recipes.get(recipeEnum); + } + +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java new file mode 100644 index 0000000000..6710f0b767 --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java @@ -0,0 +1,37 @@ +package com.devonfw.tools.ide.tool.openrewrite; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class RecipeManagerTest { + + static RecipeManager manager; + + @BeforeAll + static void init() { + manager = new RecipeManager(); + } + + @Test + public void testCreation() { + assertFalse(manager.listAvailableRecipes().isEmpty()); + } + + @Test + public void testStringValidation() { + assertFalse(manager.isValidRecipeNameRawName("NONSENSE")); + assertTrue(manager.isValidRecipeNameRawName(manager.listAvailableRecipes().stream().findAny().get().origin_name)); + } + + @Test + public void testEnumValidation() { + assertFalse(manager.isValidRecipeEnum(RefactorRecipeEnum.UNRECOGNIZED_RECIPE)); + assertTrue(manager.isValidRecipeEnum( + Arrays.stream(RefactorRecipeEnum.values()) + .filter(x -> !x.equals(RefactorRecipeEnum.UNRECOGNIZED_RECIPE)).findAny().get())); + } +} From c32d2a193c1d44ecb45bdba71fa02ab14bf97aa3 Mon Sep 17 00:00:00 2001 From: Sheng Yu Date: Fri, 24 Oct 2025 13:03:25 +0200 Subject: [PATCH 13/17] fix: fix failed errors by correcting the text --- .../devonfw/tools/ide/commandlet/RefactorCommandlet.java | 2 +- cli/src/main/resources/nls/Help.properties | 8 ++++---- cli/src/main/resources/nls/Help_de.properties | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java index c7028470d7..77e1d14355 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java @@ -32,7 +32,7 @@ public RefactorCommandlet(IdeContext context) { super(context); addKeyword(getName()); this.command = add(new EnumProperty<>("", true, "recipe_name", RefactorRecipeEnum.class)); - this.arguments = new StringProperty("", false, true, "recipe_extra_arguments"); + this.arguments = new StringProperty("", false, true, "recipe-extra-arguments"); recipeManager = new RecipeManager(); add(this.arguments); //this.recipe = context. diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index ace9c2609c..22c97039ee 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -88,12 +88,12 @@ cmd.python=Tool commandlet for Python. cmd.python.detail=Python is an object-oriented programming language, comparable to Perl, Ruby, Scheme, or Java. Detailed documentation can be found at https://www.python.org/doc/ cmd.quarkus=Tool commandlet for Quarkus (framework for cloud-native apps). cmd.quarkus.detail=Quarkus is a Kubernetes-native Java framework for building cloud-native applications. Detailed documentation can be found at https://quarkus.io/ -cmd.repository=Set up pre-configured git repositories using 'ide repository setup ' -cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/.properties' and can therefore be shared with your project team for automatic or optional setup. -cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. cmd.refactor=Refactor existing code base with specific recipes provided by OpenRewrite cmd.refactor.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ cmd.refactor.val.recipe_name=Refactor recipe names (RECIPE_1|RECIPE_2|RECIPE_3) +cmd.repository=Set up pre-configured git repositories using 'ide repository setup ' +cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/.properties' and can therefore be shared with your project team for automatic or optional setup. +cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. cmd.set-edition=Set the edition of the selected tool. cmd.set-edition.detail=This will set the according tool edition variable in your configuration file. If you want to roll out such change and share it with your team, you can commit and push your settings git repository.\nBy default these changes are saved in the project specific settings. Use --conf --home or --workspace to specify otherwise. cmd.set-edition.opt.--cfg=Selection of the configuration file (settings | home | conf | workspace). @@ -158,9 +158,9 @@ val.cfg=Selection of the configuration file (settings | home | conf | workspace) val.commandlet=The selected commandlet (use 'ide help' to list all commandlets). val.edition=The tool edition. val.plugin=The plugin to select +val.recipe-extra-arguments=possible additional arguments for the recipe val.settingsRepository=The settings git repository with the IDEasy configuration for the project. val.tool=The tool commandlet to select. val.version=The tool version. -val.recipe_extra_arguments=possible additional arguments for the recipe values=Values: version-banner=Current version of IDE is {} diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 7944c5f23d..8abaa54cac 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -88,6 +88,9 @@ cmd.python=Werkzeug Kommando für Python. cmd.python.detail=Python ist eine objektorientierte Programmiersprache, vergleichbar mit Perl, Ruby, Scheme oder Java. Detaillierte Dokumentation ist zu finden unter https://www.python.org/doc/ cmd.quarkus=Werkzeug Kommando für Quarkus (Framework für Cloud-native Anwendungen). cmd.quarkus.detail=Quarkus ist ein Kubernetes-native Java-Framework zur Entwicklung von Cloud-native Anwendungen. Detaillierte Dokumentation ist zu finden unter https://quarkus.io/ +cmd.refactor=Refaktorieren Sie die vorhandene Codebasis mit spezifischen Rezepten von OpenRewrite +cmd.refactor.detail=OpenRewrite ist ein beliebtes Tool für Refactoring (Metaprogrammierung). Eine ausführliche Dokumentation finden Sie unter https://docs.openrewrite.org/ +cmd.refactor.val.recipe_name=Rezeptnamen umgestalten (RECIPE_1|RECIPE_2|RECIPE_3) cmd.repository=Richtet das vorkonfigurierte Git Repository ein mittels 'ide repository setup '. cmd.repository.detail=Dies wird alle vorkonfigurierten Repositories einrichten. Rufen Sie einfach 'ide repository setup ' auf, ersetzen Sie durch den Namen Ihrer Projektkonfigurationsdatei, die sich in 'settings/repository/your_project_name' befindet und IDEasy wird Ihr Projekt basierend auf der vorhandenen Eigenschaftsdatei automatisch klonen, bauen und einrichten.\nWenn Sie den Projektnamen weglassen, werden alle im Repository-Verzeichnis gefundenen Projekte vorkonfiguriert. cmd.repository.val.repository=Der Name der Properties-Datei des vorkonfigurierten Git Repositories zum Einrichten. Falls nicht angegeben, werden alle aktiven Projekte eingerichtet. @@ -155,6 +158,7 @@ val.cfg=Auswahl der Konfigurationsdatei (settings | home | conf | workspace). val.commandlet=Das ausgewählte Commandlet ("ide help" verwenden, um alle Commandlets aufzulisten). val.edition=Die Werkzeug Edition. val.plugin=Die zu selektierende Erweiterung. +val.recipe-extra-arguments=Mögliche zusätzliche Argumente für das Rezept. val.settingsRepository=Das settings git Repository mit den IDEasy Einstellungen für das Projekt. val.tool=Das zu selektierende Werkzeug Kommando. val.version=Die Werkzeug Version. From ad90c440fcb1a39557b6514a14d86f79544387ab Mon Sep 17 00:00:00 2001 From: samuelkos17 Date: Fri, 7 Aug 2026 13:33:28 +0200 Subject: [PATCH 14/17] #1031: Updated the OpenRewrite implementation to work with current version of IDEasy --- .../ide/commandlet/CommandletManagerImpl.java | 2 +- .../ide/commandlet/RefactorCommandlet.java | 109 ----------------- .../ide/commandlet/RewriteCommandlet.java | 114 ++++++++++++++++++ .../devonfw/tools/ide/json/JsonMapping.java | 4 + .../ide/property/RefactorRecipeProperty.java | 50 -------- .../ide/tool/openrewrite/RecipeManager.java | 22 ++-- .../ide/tool/openrewrite/RecipeWrapper.java | 21 +++- .../RecipeWrapperJsonDeserializer.java | 67 ++++++++++ ...RecipeEnum.java => RewriteRecipeEnum.java} | 2 +- .../ide-cli/reflect-config.json | 14 +++ .../ide-cli/resource-config.json | 3 +- cli/src/main/resources/nls/Help.properties | 6 +- cli/src/main/resources/nls/Help_de.properties | 6 +- .../tool/openrewrite/RecipeManagerTest.java | 15 +-- 14 files changed, 243 insertions(+), 192 deletions(-) delete mode 100644 cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java create mode 100644 cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java delete mode 100644 cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java rename cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/{RefactorRecipeEnum.java => RewriteRecipeEnum.java} (77%) diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java index 647443dc6c..1c45cebc27 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java @@ -134,7 +134,7 @@ public CommandletManagerImpl(IdeContext context) { add(new Npm(context)); add(new Mvn(context)); add(new Msvc(context)); - add(new RefactorCommandlet(context)); + add(new RewriteCommandlet(context)); add(new GcViewer(context)); add(new Gradle(context)); add(new Eclipse(context)); diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java deleted file mode 100644 index 77e1d14355..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.devonfw.tools.ide.commandlet; - -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.property.EnumProperty; -import com.devonfw.tools.ide.property.StringProperty; -import com.devonfw.tools.ide.tool.ToolCommandlet; -import com.devonfw.tools.ide.tool.mvn.Mvn; -import com.devonfw.tools.ide.tool.openrewrite.RecipeManager; -import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper; -import com.devonfw.tools.ide.tool.openrewrite.RefactorRecipeEnum; - -import org.apache.commons.lang3.StringUtils; - -import java.util.Arrays; -import java.util.Scanner; - -/** - * {@link ToolCommandlet} for Refactor. - */ -public class RefactorCommandlet extends Commandlet { - - public final EnumProperty command; - public final StringProperty arguments; - private RecipeManager recipeManager; - /** - * The constructor. - * - * @param context the {@link IdeContext}. - */ - public RefactorCommandlet(IdeContext context) { - - super(context); - addKeyword(getName()); - this.command = add(new EnumProperty<>("", true, "recipe_name", RefactorRecipeEnum.class)); - this.arguments = new StringProperty("", false, true, "recipe-extra-arguments"); - recipeManager = new RecipeManager(); - add(this.arguments); - //this.recipe = context. - } - - @Override - public String getName() { - //this indicates the command name - return "refactor"; - } - - private String[] adaptMVNCommand(String recipeRawCommands) { - if(recipeRawCommands.startsWith("mvn")) { - return recipeRawCommands.replaceFirst("\\Qmvn\\E", "").split("\\s+"); - } else { - return recipeRawCommands.split("\\s+"); - } - } - - private String changeToDryRunCommand(String recipeRawCommands) { - return recipeRawCommands.replaceAll(":run\\b", ":dryrun"); - } - - private void showInfo(RecipeWrapper wrapper) { - context.info("Recipe [{}], {} ", wrapper.ideasy_command.name(), wrapper.description); - context.info("Reference {}", wrapper.url); - context.info("Raw command: {}", wrapper.raw_cmd); - } - - private boolean confirmApplyChange() { - context.info("***Before making actual changes to the code, please confirm it seriously. It is strongly recommended to perform a DRY-RUN first***"); - context.info("Type yes to apply changes, or press other keys to perform DRY-RUN: "); - - Scanner scanner = new Scanner(System.in); - String input = scanner.nextLine(); - - return (input.equalsIgnoreCase("yes")); - } - - @Override - public void run() { - - context.info("{} called", getClass().getSimpleName()); - - RefactorRecipeEnum command = this.command.getValue(); - String option = this.arguments.getValue(); - - if(!recipeManager.isValidRecipeEnum(command)) { - context.error("INVALID recipe name: {}", command); - return; - } - - RecipeWrapper wrapper = recipeManager.getRecipeWrapper(command); - - showInfo(wrapper); - - String commandLine = wrapper.raw_cmd; - - if(!confirmApplyChange()) { - commandLine = changeToDryRunCommand(commandLine); - } - - context.info("Actual command line: {}", commandLine); - - getCommandlet(Mvn.class).runTool(adaptMVNCommand(commandLine)); - - } - - @Override - public boolean isIdeHomeRequired() { - - return false; - } -} diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java new file mode 100644 index 0000000000..1317bea481 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java @@ -0,0 +1,114 @@ +package com.devonfw.tools.ide.commandlet; + +import java.util.List; +import java.util.Scanner; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.property.EnumProperty; +import com.devonfw.tools.ide.property.StringProperty; +import com.devonfw.tools.ide.tool.ToolCommandlet; +import com.devonfw.tools.ide.tool.mvn.Mvn; +import com.devonfw.tools.ide.tool.openrewrite.RecipeManager; +import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper; +import com.devonfw.tools.ide.tool.openrewrite.RewriteRecipeEnum; + +/** + * {@link ToolCommandlet} for Refactor. + */ +public class RewriteCommandlet extends Commandlet { + + private static final Logger LOG = LoggerFactory.getLogger(RewriteCommandlet.class); + + + public final EnumProperty command; + public final StringProperty arguments; + private RecipeManager recipeManager; + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + */ + public RewriteCommandlet(IdeContext context) { + + super(context); + addKeyword(getName()); + this.command = add(new EnumProperty<>("", true, "recipe_name", RewriteRecipeEnum.class)); + this.arguments = new StringProperty("", false, true, "recipe-extra-arguments"); + recipeManager = new RecipeManager(); + add(this.arguments); + //this.recipe = context. + } + + @Override + public String getName() { + //this indicates the command name + return "rewrite"; + } + + private String[] adaptMVNCommand(String recipeRawCommands) { + if (recipeRawCommands.startsWith("mvn")) { + return recipeRawCommands.replaceFirst("^mvn\\s+", "").split("\\s+"); + } else { + return recipeRawCommands.trim().split("\\s+"); + } + } + + private String changeToDryRunCommand(String recipeRawCommands) { + return recipeRawCommands.replaceAll(":run\\b", ":dryRun"); + } + + private void showInfo(RecipeWrapper wrapper) { + LOG.info("Recipe [{}], {} ", wrapper.ideasyCommand.name(), wrapper.description); + LOG.info("Reference {}", wrapper.url); + LOG.info("Raw command: {}", wrapper.rawCmd); + } + + private boolean confirmApplyChange() { + LOG.info("***Before making actual changes to the code, please confirm it seriously. It is strongly recommended to perform a DRY-RUN first***"); + LOG.info("Type yes to apply changes, or press other keys to perform DRY-RUN: "); + + try (Scanner scanner = new Scanner(System.in)) { + String input = scanner.nextLine(); + return input.equalsIgnoreCase("yes"); + } + } + + @Override + public void doRun() { + + LOG.info("{} called", getClass().getSimpleName()); + + RewriteRecipeEnum command = this.command.getValue(); + String option = this.arguments.getValue(); + + if (!recipeManager.isValidRecipeEnum(command)) { + LOG.error("INVALID recipe name: {}", command); + return; + } + + RecipeWrapper wrapper = recipeManager.getRecipeWrapper(command); + + showInfo(wrapper); + + String commandLine = wrapper.rawCmd; + + if (!confirmApplyChange()) { + commandLine = changeToDryRunCommand(commandLine); + } + + LOG.info("Actual command line: {}", commandLine); + + getCommandlet(Mvn.class).runTool(List.of(adaptMVNCommand(commandLine))); + + } + + @Override + public boolean isIdeHomeRequired() { + + return false; + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/json/JsonMapping.java b/cli/src/main/java/com/devonfw/tools/ide/json/JsonMapping.java index 8bd0714350..a5f354c90b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/json/JsonMapping.java +++ b/cli/src/main/java/com/devonfw/tools/ide/json/JsonMapping.java @@ -26,6 +26,8 @@ import com.devonfw.tools.ide.tool.npm.NpmJsVersions; import com.devonfw.tools.ide.tool.npm.NpmJsVersionsJsonDeserializer; import com.devonfw.tools.ide.tool.npm.NpmJsVersionsJsonSerializer; +import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper; +import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapperJsonDeserializer; import com.devonfw.tools.ide.tool.pip.PypiObject; import com.devonfw.tools.ide.tool.pip.PypiObjectJsonDeserializer; import com.devonfw.tools.ide.tool.pip.PypiObjectJsonSerializer; @@ -102,6 +104,8 @@ private static ObjectMapper create(boolean supportReflection) { customModule.addDeserializer(ToolSecurity.class, new ToolSecurityJsonDeserializer()); customModule.addSerializer(Cve.class, new CveJsonSerializer()); customModule.addDeserializer(Cve.class, new CveJsonDeserializer()); + // openrewrite mapping + customModule.addDeserializer(RecipeWrapper.class, new RecipeWrapperJsonDeserializer()); // pypi mapping customModule.addDeserializer(PypiObject.class, new PypiObjectJsonDeserializer()); customModule.addSerializer(PypiObject.class, new PypiObjectJsonSerializer()); diff --git a/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java b/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java deleted file mode 100644 index 04a1321aa8..0000000000 --- a/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.devonfw.tools.ide.property; - -import com.devonfw.tools.ide.commandlet.Commandlet; -import com.devonfw.tools.ide.completion.CompletionCandidateCollector; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.tool.ToolCommandlet; -import com.devonfw.tools.ide.tool.plugin.PluginBasedCommandlet; -import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor; -import com.devonfw.tools.ide.tool.plugin.ToolPlugins; -import com.devonfw.tools.ide.validation.PropertyValidator; - -public class RefactorRecipeProperty extends Property { - - public RefactorRecipeProperty(String name) { - - this(name, null); - } - - public RefactorRecipeProperty(String name, PropertyValidator validator) { - - super(name, true, null, true, validator); - } - - @Override - public Class getValueType() { - - return String.class; - } - - @Override - public String parse(String valueAsString, IdeContext context) { - - return valueAsString; - } - - @Override - protected void completeValue(String arg, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) { - - ToolCommandlet cmd = commandlet.getToolForCompletion(); - if (cmd instanceof PluginBasedCommandlet pbc) { - ToolPlugins plugins = pbc.getPlugins(); - for (ToolPluginDescriptor pluginDescriptor : plugins.getPlugins()) { - if (pluginDescriptor.name().toLowerCase().startsWith(arg.toLowerCase())) { - collector.add(pluginDescriptor.name(), null, null, commandlet); - } - } - } - } - -} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java index 530606dcde..76fb5050b4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java @@ -1,8 +1,5 @@ package com.devonfw.tools.ide.tool.openrewrite; -import com.devonfw.tools.ide.json.JsonMapping; -import com.fasterxml.jackson.databind.ObjectMapper; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -14,11 +11,14 @@ import java.util.Objects; import java.util.Optional; +import com.devonfw.tools.ide.json.JsonMapping; +import com.fasterxml.jackson.databind.ObjectMapper; + public class RecipeManager { private static final String OPEN_REWRITE_CONFIG_JSON_PATH = "refactor/openrewrite.json"; - private final Map recipes = new HashMap<>(); + private final Map recipes = new HashMap<>(); public RecipeManager() { @@ -27,15 +27,15 @@ public RecipeManager() { Objects.requireNonNull(RecipeManager.class.getClassLoader().getResourceAsStream(OPEN_REWRITE_CONFIG_JSON_PATH)), StandardCharsets.UTF_8)); ObjectMapper objectMapper = JsonMapping.create(); - List wrapperList = objectMapper.readValue(reader, objectMapper.getTypeFactory().constructCollectionType(List.class, RecipeWrapper.class)); + List wrapperList = objectMapper.readValue(reader, objectMapper.getTypeFactory().constructCollectionType(List.class, RecipeWrapper.class)); - for(RecipeWrapper one: wrapperList) { - recipes.put(one.ideasy_command, one); + for (RecipeWrapper one : wrapperList) { + recipes.put(one.ideasyCommand, one); } } catch (IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("Failed to load " + OPEN_REWRITE_CONFIG_JSON_PATH, e); } } @@ -44,18 +44,18 @@ public List listAvailableRecipes() { } private Optional findRecipeByName(String rawName) { - return recipes.values().stream().filter(x -> x.origin_name.equals(rawName)).findAny(); + return recipes.values().stream().filter(x -> x.originName.equals(rawName)).findAny(); } public boolean isValidRecipeNameRawName(String rawName) { return findRecipeByName(rawName).isPresent(); } - public boolean isValidRecipeEnum(RefactorRecipeEnum recipeEnum) { + public boolean isValidRecipeEnum(RewriteRecipeEnum recipeEnum) { return recipes.containsKey(recipeEnum); } - public RecipeWrapper getRecipeWrapper(RefactorRecipeEnum recipeEnum) { + public RecipeWrapper getRecipeWrapper(RewriteRecipeEnum recipeEnum) { return recipes.get(recipeEnum); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java index c13de47c0b..53ea3cdc7e 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java @@ -1,17 +1,26 @@ package com.devonfw.tools.ide.tool.openrewrite; -import java.util.Locale; +import com.devonfw.tools.ide.json.JsonObject; + +public class RecipeWrapper implements JsonObject { -public class RecipeWrapper { public String description; - public String origin_name; + public String originName; public String url; - public RefactorRecipeEnum ideasy_command; - public String raw_cmd; + public RewriteRecipeEnum ideasyCommand; + public String rawCmd; + + public RecipeWrapper(String description, String originName, String url, RewriteRecipeEnum ideasyCommand, String rawCmd) { + this.description = description; + this.originName = originName; + this.url = url; + this.ideasyCommand = ideasyCommand; + this.rawCmd = rawCmd; + } //in case of future need public String getName() { - return this.origin_name; + return this.originName; } } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java new file mode 100644 index 0000000000..fd48a1f7c4 --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java @@ -0,0 +1,67 @@ +package com.devonfw.tools.ide.tool.openrewrite; + +import java.io.IOException; + +import com.devonfw.tools.ide.json.JsonBuilder; +import com.devonfw.tools.ide.json.JsonObjectDeserializer; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; + +/** + * {@link JsonObjectDeserializer} for {@link RecipeWrapper}. + */ +public class RecipeWrapperJsonDeserializer extends JsonObjectDeserializer { + + @Override + protected JsonBuilder createBuilder() { + + return new RecipeWrapperBuilder(); + } + + private class RecipeWrapperBuilder extends JsonBuilder { + + private String description; + private String originName; + private String url; + private RewriteRecipeEnum ideasyCommand; + private String rawCmd; + + @Override + public void setProperty(String property, JsonParser p, DeserializationContext ctxt) throws IOException { + + switch (property) { + case "description" -> { + this.description = readValueAsString(p, property, this.description); + } + case "origin_name" -> { + this.originName = readValueAsString(p, property, this.originName); + } + case "url" -> { + this.url = readValueAsString(p, property, this.url); + } + case "ideasy_command" -> { + String value = readValueAsString(p, property, null); + if (value != null) { + try { + this.ideasyCommand = RewriteRecipeEnum.valueOf(value); + } catch (IllegalArgumentException e) { + this.ideasyCommand = RewriteRecipeEnum.UNRECOGNIZED_RECIPE; + } + } + } + case "raw_cmd" -> { + this.rawCmd = readValueAsString(p, property, this.rawCmd); + } + default -> { + super.setProperty(property, p, ctxt); + } + } + } + + @Override + public RecipeWrapper build() { + + return new RecipeWrapper(this.description, this.originName, this.url, this.ideasyCommand, this.rawCmd); + } + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RewriteRecipeEnum.java similarity index 77% rename from cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java rename to cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RewriteRecipeEnum.java index c72c299526..22d00a90bd 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RewriteRecipeEnum.java @@ -1,5 +1,5 @@ package com.devonfw.tools.ide.tool.openrewrite; -public enum RefactorRecipeEnum { +public enum RewriteRecipeEnum { FORMAT_JAVA_CODE, REMOVE_BLANK_LINES, UNRECOGNIZED_RECIPE } diff --git a/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json b/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json index 5eb3b81a7d..1293b4ff23 100644 --- a/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json +++ b/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/reflect-config.json @@ -58,5 +58,19 @@ "allPublicConstructors": true, "allDeclaredFields": false, "allDeclaredMethods": false + }, + { + "name": "com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper", + "allDeclaredConstructors": true, + "allPublicConstructors": true, + "allDeclaredFields": true, + "allDeclaredMethods": true + }, + { + "name": "com.devonfw.tools.ide.tool.openrewrite.RewriteRecipeEnum", + "allDeclaredConstructors": true, + "allPublicConstructors": true, + "allDeclaredFields": true, + "allDeclaredMethods": true } ] diff --git a/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/resource-config.json b/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/resource-config.json index 9d570eb1c6..5870fea20d 100644 --- a/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/resource-config.json +++ b/cli/src/main/resources/META-INF/native-image/com.devonfw.tools.IDEasy/ide-cli/resource-config.json @@ -1,7 +1,8 @@ { "resources": { "includes": [ - {"pattern": "nls/.*"} + {"pattern": "nls/.*"}, + {"pattern": "refactor/openrewrite.json"} ] }, "bundles": [ diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index 4587408f17..02c0123c83 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -118,12 +118,12 @@ cmd.quarkus.detail=Quarkus is a Kubernetes-native Java framework for building cl cmd.release=Performs a release of the project in your current working directory. cmd.release.detail=Builds and deploys a release of the project in your current working directory. It sets the release version, tags it in git as `release/«version»`, runs the deploy build and then bumps to the next development version. Nothing is pushed until you confirm. You can pass extra arguments with `ide release «args»`, which go to the build command (e.g. `mvn`). cmd.release.val.args=Additional arguments to pass to the build and deploy command. -cmd.refactor=Refactor existing code base with specific recipes provided by OpenRewrite -cmd.refactor.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ -cmd.refactor.val.recipe_name=Refactor recipe names (RECIPE_1|RECIPE_2|RECIPE_3) cmd.repository=Set up pre-configured git repositories using 'ide repository setup ' cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/.properties' and can therefore be shared with your project team for automatic or optional setup. cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. +cmd.rewrite=Refactor existing code base with specific recipes provided by OpenRewrite +cmd.rewrite.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ +cmd.rewrite.val.recipe_name=Rewrite recipe names (RECIPE_1|RECIPE_2|RECIPE_3) cmd.rust=Tool commandlet for Rust (programming language). cmd.rust.detail=Rust is a programming-language focused on safety and performance. Detailed documentation can be found at https://www.rust-lang.org/learn cmd.set-edition=Set the edition of the selected tool. diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 8342057654..1247712698 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -118,12 +118,12 @@ cmd.quarkus.detail=Quarkus ist ein Kubernetes-native Java-Framework zur Entwickl cmd.release=Führt ein Release des Projekts in Ihrem aktuellen Arbeitsverzeichnis durch. cmd.release.detail=Baut und veröffentlicht ein Release des Projekts in Ihrem aktuellen Arbeitsverzeichnis. Setzt die Release-Version, taggt sie in git als `release/«version»`, führt den Deploy-Build aus und wechselt danach zur nächsten Entwicklungsversion. Gepusht wird erst, nachdem Sie bestätigt haben. Zusätzliche Argumente können Sie mit `ide release «args»` übergeben, sie gehen an den Build-Befehl (z.B. `mvn`). cmd.release.val.args=Zusätzliche Argumente, die an den Build- und Deploy-Befehl übergeben werden. -cmd.refactor=Refaktorieren Sie die vorhandene Codebasis mit spezifischen Rezepten von OpenRewrite -cmd.refactor.detail=OpenRewrite ist ein beliebtes Tool für Refactoring (Metaprogrammierung). Eine ausführliche Dokumentation finden Sie unter https://docs.openrewrite.org/ -cmd.refactor.val.recipe_name=Rezeptnamen umgestalten (RECIPE_1|RECIPE_2|RECIPE_3) cmd.repository=Richtet das vorkonfigurierte Git Repository ein mittels 'ide repository setup '. cmd.repository.detail=Dies wird alle vorkonfigurierten Repositories einrichten. Rufen Sie einfach 'ide repository setup ' auf, ersetzen Sie durch den Namen Ihrer Projektkonfigurationsdatei, die sich in 'settings/repository/your_project_name' befindet und IDEasy wird Ihr Projekt basierend auf der vorhandenen Eigenschaftsdatei automatisch klonen, bauen und einrichten.\nWenn Sie den Projektnamen weglassen, werden alle im Repository-Verzeichnis gefundenen Projekte vorkonfiguriert. cmd.repository.val.repository=Der Name der Properties-Datei des vorkonfigurierten Git Repositories zum Einrichten. Falls nicht angegeben, werden alle aktiven Projekte eingerichtet. +cmd.rewrite=Refaktorieren Sie die vorhandene Codebasis mit spezifischen Rezepten von OpenRewrite +cmd.rewrite.detail=OpenRewrite ist ein beliebtes Tool für Refactoring (Metaprogrammierung). Eine ausführliche Dokumentation finden Sie unter https://docs.openrewrite.org/ +cmd.rewrite.val.recipe_name=Rezeptnamen umgestalten (RECIPE_1|RECIPE_2|RECIPE_3) cmd.rust=Werkzeug Kommando für Rust (Programmiersprache). cmd.rust.detail=Rust ist eine Programmiersprache mit Fokus auf Sicherheit und Performance. Detaillierte Dokumentation findet sich unter https://www.rust-lang.org/learn cmd.set-edition=Setzt die Edition des selektierten Werkzeugs. diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java index 6710f0b767..2607211649 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java @@ -1,11 +1,12 @@ package com.devonfw.tools.ide.tool.openrewrite; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; class RecipeManagerTest { @@ -24,14 +25,14 @@ public void testCreation() { @Test public void testStringValidation() { assertFalse(manager.isValidRecipeNameRawName("NONSENSE")); - assertTrue(manager.isValidRecipeNameRawName(manager.listAvailableRecipes().stream().findAny().get().origin_name)); + assertTrue(manager.isValidRecipeNameRawName(manager.listAvailableRecipes().stream().findAny().get().originName)); } @Test public void testEnumValidation() { - assertFalse(manager.isValidRecipeEnum(RefactorRecipeEnum.UNRECOGNIZED_RECIPE)); + assertFalse(manager.isValidRecipeEnum(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)); assertTrue(manager.isValidRecipeEnum( - Arrays.stream(RefactorRecipeEnum.values()) - .filter(x -> !x.equals(RefactorRecipeEnum.UNRECOGNIZED_RECIPE)).findAny().get())); + Arrays.stream(RewriteRecipeEnum.values()) + .filter(x -> !x.equals(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)).findAny().get())); } } From cdd87e41f7d5d99425f6015a5133be065448cc11 Mon Sep 17 00:00:00 2001 From: samuelkos17 Date: Mon, 10 Aug 2026 10:13:48 +0200 Subject: [PATCH 15/17] #1031: Refactored the Openrewrite implementation to fit standards and added more tests --- .../ide/commandlet/RewriteCommandlet.java | 114 +++++++++---- .../ide/tool/openrewrite/RecipeManager.java | 52 ++++-- .../RecipeWrapperJsonDeserializer.java | 6 + .../ide/commandlet/RewriteCommandletTest.java | 160 ++++++++++++++++++ .../tool/openrewrite/RecipeManagerTest.java | 32 ++-- 5 files changed, 301 insertions(+), 63 deletions(-) create mode 100644 cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java index 1317bea481..02acfa6933 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java @@ -1,31 +1,30 @@ package com.devonfw.tools.ide.commandlet; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; -import java.util.Scanner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.property.EnumProperty; -import com.devonfw.tools.ide.property.StringProperty; -import com.devonfw.tools.ide.tool.ToolCommandlet; import com.devonfw.tools.ide.tool.mvn.Mvn; import com.devonfw.tools.ide.tool.openrewrite.RecipeManager; import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper; import com.devonfw.tools.ide.tool.openrewrite.RewriteRecipeEnum; /** - * {@link ToolCommandlet} for Refactor. + * {@link Commandlet} for OpenRewrite refactoring. */ public class RewriteCommandlet extends Commandlet { private static final Logger LOG = LoggerFactory.getLogger(RewriteCommandlet.class); - public final EnumProperty command; - public final StringProperty arguments; - private RecipeManager recipeManager; + private final RecipeManager recipeManager; /** * The constructor. @@ -37,44 +36,87 @@ public RewriteCommandlet(IdeContext context) { super(context); addKeyword(getName()); this.command = add(new EnumProperty<>("", true, "recipe_name", RewriteRecipeEnum.class)); - this.arguments = new StringProperty("", false, true, "recipe-extra-arguments"); - recipeManager = new RecipeManager(); - add(this.arguments); - //this.recipe = context. + this.recipeManager = new RecipeManager(); } @Override public String getName() { - //this indicates the command name + return "rewrite"; } - private String[] adaptMVNCommand(String recipeRawCommands) { - if (recipeRawCommands.startsWith("mvn")) { - return recipeRawCommands.replaceFirst("^mvn\\s+", "").split("\\s+"); - } else { - return recipeRawCommands.trim().split("\\s+"); + /** + * Parses the raw MVN command from JSON into individual argument tokens, stripping the leading "mvn" if present. + * + * @param recipeRawCommands the raw command string from the recipe configuration. + * @return list of individual MVN argument tokens. + */ + private List adaptMVNCommand(String recipeRawCommands) { + String trimmed = recipeRawCommands.trim(); + if (trimmed.startsWith("mvn ")) { + trimmed = trimmed.substring(4); + } else if (trimmed.equals("mvn")) { + trimmed = ""; + } + List args = new ArrayList<>(); + for (String token : trimmed.split("\\s+")) { + if (!token.isEmpty()) { + args.add(token); + } } + return args; } + /** + * Converts a raw command to dry-run mode by replacing the ":run" goal with ":dryRun". + * + * @param recipeRawCommands the raw command string. + * @return the command with dry-run mode applied. + * @throws CliException if the command does not contain a ":run" goal to replace. + */ private String changeToDryRunCommand(String recipeRawCommands) { - return recipeRawCommands.replaceAll(":run\\b", ":dryRun"); + String result = recipeRawCommands.replace(":run", ":dryRun"); + if (result.equals(recipeRawCommands)) { + throw new CliException("Cannot convert to dry-run: command does not contain ':run' goal: " + recipeRawCommands); + } + return result; } private void showInfo(RecipeWrapper wrapper) { - LOG.info("Recipe [{}], {} ", wrapper.ideasyCommand.name(), wrapper.description); + LOG.info("Recipe [{}], {}", wrapper.ideasyCommand.name(), wrapper.description); LOG.info("Reference {}", wrapper.url); LOG.info("Raw command: {}", wrapper.rawCmd); } private boolean confirmApplyChange() { - LOG.info("***Before making actual changes to the code, please confirm it seriously. It is strongly recommended to perform a DRY-RUN first***"); - LOG.info("Type yes to apply changes, or press other keys to perform DRY-RUN: "); - try (Scanner scanner = new Scanner(System.in)) { - String input = scanner.nextLine(); - return input.equalsIgnoreCase("yes"); + String input = this.context.askForInput( + "***Before making actual changes to the code, please confirm it seriously." + + " It is strongly recommended to perform a DRY-RUN first***\n" + + "Type yes to apply changes, or press other keys to perform DRY-RUN: "); + + return input.equalsIgnoreCase("yes"); + + } + + /** + * Searches up from the current working directory to find the nearest pom.xml. + * + * @return the path to the project root containing pom.xml. + * @throws CliException if no pom.xml is found or cwd is not set. + */ + Path findProjectRoot() { + Path dir = this.context.getCwd(); + if (dir == null) { + throw new CliException("Cannot determine current working directory"); + } + while (dir != null) { + if (Files.exists(dir.resolve("pom.xml"))) { + return dir; + } + dir = dir.getParent(); } + throw new CliException("No pom.xml found in current directory or any parent directory"); } @Override @@ -82,15 +124,16 @@ public void doRun() { LOG.info("{} called", getClass().getSimpleName()); - RewriteRecipeEnum command = this.command.getValue(); - String option = this.arguments.getValue(); + RewriteRecipeEnum recipeEnum = this.command.getValue(); - if (!recipeManager.isValidRecipeEnum(command)) { - LOG.error("INVALID recipe name: {}", command); - return; + if (!recipeManager.isValidRecipeEnum(recipeEnum)) { + throw new CliException("Invalid recipe name: " + recipeEnum); } - RecipeWrapper wrapper = recipeManager.getRecipeWrapper(command); + RecipeWrapper wrapper = recipeManager.getRecipeWrapper(recipeEnum); + + Path projectRoot = findProjectRoot(); + LOG.info("Target project: {}", projectRoot); showInfo(wrapper); @@ -102,8 +145,15 @@ public void doRun() { LOG.info("Actual command line: {}", commandLine); - getCommandlet(Mvn.class).runTool(List.of(adaptMVNCommand(commandLine))); - + try { + List args = adaptMVNCommand(commandLine); + // Inject -f so Maven runs in the correct project + args.add(0, "-f"); + args.add(1, projectRoot.toString()); + getCommandlet(Mvn.class).runTool(args); + } catch (Exception e) { + throw new CliException("OpenRewrite execution failed for recipe '" + wrapper.ideasyCommand.name() + "': " + e.getMessage(), e); + } } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java index 76fb5050b4..168cf0fb16 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java @@ -4,59 +4,81 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.json.JsonMapping; import com.fasterxml.jackson.databind.ObjectMapper; - +/** + * Manages the loading and lookup of OpenRewrite {@link RecipeWrapper} configurations from JSON. + */ public class RecipeManager { private static final String OPEN_REWRITE_CONFIG_JSON_PATH = "refactor/openrewrite.json"; - private final Map recipes = new HashMap<>(); + private final Map recipes; public RecipeManager() { - try { - BufferedReader reader = new BufferedReader(new InputStreamReader( - Objects.requireNonNull(RecipeManager.class.getClassLoader().getResourceAsStream(OPEN_REWRITE_CONFIG_JSON_PATH)), StandardCharsets.UTF_8)); + try (BufferedReader reader = new BufferedReader(new InputStreamReader( + Objects.requireNonNull(RecipeManager.class.getClassLoader().getResourceAsStream(OPEN_REWRITE_CONFIG_JSON_PATH)), StandardCharsets.UTF_8))) { ObjectMapper objectMapper = JsonMapping.create(); - List wrapperList = objectMapper.readValue(reader, objectMapper.getTypeFactory().constructCollectionType(List.class, RecipeWrapper.class)); + java.util.LinkedHashMap map = new java.util.LinkedHashMap<>(); for (RecipeWrapper one : wrapperList) { - recipes.put(one.ideasyCommand, one); + map.put(one.ideasyCommand, one); } - - + this.recipes = java.util.Collections.unmodifiableMap(map); } catch (IOException e) { - throw new RuntimeException("Failed to load " + OPEN_REWRITE_CONFIG_JSON_PATH, e); + throw new CliException("Failed to load " + OPEN_REWRITE_CONFIG_JSON_PATH, e); } } + /** + * Returns the list of all loaded {@link RecipeWrapper} configurations. + * + * @return an unmodifiable list of available recipes. + */ public List listAvailableRecipes() { - return Collections.unmodifiableList(recipes.values().stream().toList()); + + return List.copyOf(recipes.values()); } private Optional findRecipeByName(String rawName) { - return recipes.values().stream().filter(x -> x.originName.equals(rawName)).findAny(); + return recipes.values().stream().filter(x -> x.originName.equals(rawName)).findFirst(); } + /** + * Checks if a recipe with the given original OpenRewrite name exists in the configuration. + * + * @param rawName the original recipe name (e.g. {@code "java.format_autoformat"}). + * @return {@code true} if a matching recipe was found. + */ public boolean isValidRecipeNameRawName(String rawName) { return findRecipeByName(rawName).isPresent(); } + /** + * Checks if a recipe for the given {@link RewriteRecipeEnum} exists in the configuration. + * + * @param recipeEnum the enum constant identifying the recipe. + * @return {@code true} if a matching recipe was found. + */ public boolean isValidRecipeEnum(RewriteRecipeEnum recipeEnum) { return recipes.containsKey(recipeEnum); } + /** + * Returns the {@link RecipeWrapper} for the given {@link RewriteRecipeEnum}. + * + * @param recipeEnum the enum constant identifying the recipe. + * @return the recipe wrapper. + */ public RecipeWrapper getRecipeWrapper(RewriteRecipeEnum recipeEnum) { return recipes.get(recipeEnum); } - } diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java index fd48a1f7c4..a09d87d56b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapperJsonDeserializer.java @@ -2,6 +2,9 @@ import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.devonfw.tools.ide.json.JsonBuilder; import com.devonfw.tools.ide.json.JsonObjectDeserializer; import com.fasterxml.jackson.core.JsonParser; @@ -12,6 +15,8 @@ */ public class RecipeWrapperJsonDeserializer extends JsonObjectDeserializer { + private static final Logger LOG = LoggerFactory.getLogger(RecipeWrapperJsonDeserializer.class); + @Override protected JsonBuilder createBuilder() { @@ -53,6 +58,7 @@ public void setProperty(String property, JsonParser p, DeserializationContext ct this.rawCmd = readValueAsString(p, property, this.rawCmd); } default -> { + LOG.warn("Unknown recipe property: {}", property); super.setProperty(property, p, ctxt); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java new file mode 100644 index 0000000000..2e23d51569 --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java @@ -0,0 +1,160 @@ +package com.devonfw.tools.ide.commandlet; + +import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +import com.devonfw.tools.ide.cli.CliException; +import com.devonfw.tools.ide.context.AbstractIdeContextTest; +import com.devonfw.tools.ide.context.IdeTestContext; +import com.devonfw.tools.ide.tool.openrewrite.RecipeManager; +import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper; +import com.devonfw.tools.ide.tool.openrewrite.RewriteRecipeEnum; + +/** + * Tests for {@link RewriteCommandlet}. + */ +class RewriteCommandletTest extends AbstractIdeContextTest { + + /** + * Tests that the RewriteCommandlet is registered and accessible via the commandlet manager. + */ + @Test + void testCommandletExists() { + IdeTestContext context = newContext("basic"); + RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); + assertThat(commandlet).isNotNull(); + assertThat(commandlet.getName()).isEqualTo("rewrite"); + } + + /** + * Tests that {@link RecipeManager} correctly loads recipes and validates enums. + */ + @Test + void testRecipeManagerLoadsRecipes() { + RecipeManager manager = new RecipeManager(); + assertThat(manager.listAvailableRecipes()).isNotEmpty(); + assertThat(manager.isValidRecipeEnum(RewriteRecipeEnum.FORMAT_JAVA_CODE)).isTrue(); + assertThat(manager.isValidRecipeEnum(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)).isFalse(); + } + + /** + * Tests that {@link RecipeManager} validates raw recipe names. + */ + @Test + void testRecipeManagerValidatesRawName() { + RecipeManager manager = new RecipeManager(); + assertThat(manager.isValidRecipeNameRawName("NONSENSE")).isFalse(); + RecipeWrapper wrapper = manager.getRecipeWrapper(RewriteRecipeEnum.FORMAT_JAVA_CODE); + assertThat(manager.isValidRecipeNameRawName(wrapper.originName)).isTrue(); + } + + /** + * Tests that the dry-run conversion correctly replaces :run with :dryRun. + */ + @Test + void testDryRunConversion() { + RecipeManager manager = new RecipeManager(); + RecipeWrapper wrapper = manager.getRecipeWrapper(RewriteRecipeEnum.FORMAT_JAVA_CODE); + assertThat(wrapper.rawCmd).contains(":run"); + + String dryRunCmd = wrapper.rawCmd.replace(":run", ":dryRun"); + assertThat(dryRunCmd).contains(":dryRun"); + assertThat(dryRunCmd).doesNotContain(":run"); + } + + /** + * Tests that the dry-run conversion fails when no :run goal is present. + */ + @Test + void testDryRunConversionFailsWithoutRunGoal() { + String commandWithoutRun = "mvn -U some:otherGoal -Dfoo=bar"; + String result = commandWithoutRun.replace(":run", ":dryRun"); + // No replacement happened + assertThat(result).isEqualTo(commandWithoutRun); + } + + /** + * Tests that the commandlet properly parses MVN commands by stripping the "mvn" prefix. + */ + @Test + void testAdaptMvnCommand() { + RecipeManager manager = new RecipeManager(); + RecipeWrapper wrapper = manager.getRecipeWrapper(RewriteRecipeEnum.FORMAT_JAVA_CODE); + + // Verify the raw command starts with "mvn" + assertThat(wrapper.rawCmd).startsWith("mvn"); + + String trimmed = wrapper.rawCmd.trim(); + String withoutPrefix = trimmed.substring(4); // strip "mvn " + List args = List.of(withoutPrefix.split("\\s+")); + assertThat(args).isNotEmpty(); + assertThat(args.getFirst()).startsWith("-"); // should be a Maven flag + } + + /** + * Tests that ideHome is not required for the RewriteCommandlet. + */ + @Test + void testIdeHomeNotRequired() { + IdeTestContext context = newContext("basic"); + RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); + assertThat(commandlet.isIdeHomeRequired()).isFalse(); + } + + /** + * Tests that {@link RewriteCommandlet#doRun()} throws a {@link CliException} when an invalid recipe enum is provided, exercising the error handling path. + */ + @Test + void testDoRunThrowsForInvalidRecipe() { + IdeTestContext context = newContext("basic"); + RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); + commandlet.command.setValue(RewriteRecipeEnum.UNRECOGNIZED_RECIPE); + CliException e = assertThrows(CliException.class, commandlet::doRun); + assertThat(e.getMessage()).contains("Invalid recipe name"); + } + + /** + * Tests that {@link RewriteCommandlet#findProjectRoot()} locates the nearest pom.xml when the current working directory contains one. + */ + @Test + void testFindProjectRootFindsPomInCurrentDirectory() { + IdeTestContext context = newContext("release"); + RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); + // mvn directory contains pom.xml + Path mvnDir = context.getWorkspacePath().resolve("mvn"); + context.setCwd(mvnDir, "main", context.getIdeHome()); + Path projectRoot = commandlet.findProjectRoot(); + assertThat(projectRoot).isEqualTo(mvnDir); + } + + /** + * Tests that {@link RewriteCommandlet#findProjectRoot()} walks up the directory tree to find the nearest pom.xml. + */ + @Test + void testFindProjectRootWalksUpDirectoryTree() { + IdeTestContext context = newContext("release"); + RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); + // empty directory does NOT contain pom.xml - should walk up to find it + Path emptyDir = context.getWorkspacePath().resolve("empty"); + context.setCwd(emptyDir, "main", context.getIdeHome()); + Path projectRoot = commandlet.findProjectRoot(); + // Should find the pom.xml in the parent workspaces/main directory or above + assertThat(projectRoot.resolve("pom.xml")).exists(); + } + + /** + * Tests that {@link RewriteCommandlet#findProjectRoot()} throws when cwd is not set. + */ + @Test + void testFindProjectRootThrowsWhenNoCwd() { + IdeTestContext context = newContext("basic"); + RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); + context.setCwd(null, "main", context.getIdeHome()); + CliException e = assertThrows(CliException.class, commandlet::findProjectRoot); + assertThat(e.getMessage()).contains("current working directory"); + } +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java index 2607211649..1cd32bd0c5 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java @@ -1,14 +1,13 @@ package com.devonfw.tools.ide.tool.openrewrite; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Arrays; - +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -class RecipeManagerTest { +/** + * Tests for {@link RecipeManager}. + */ +class RecipeManagerTest extends Assertions { static RecipeManager manager; @@ -18,21 +17,22 @@ static void init() { } @Test - public void testCreation() { - assertFalse(manager.listAvailableRecipes().isEmpty()); + void testCreation() { + assertThat(manager.listAvailableRecipes()).isNotEmpty(); } @Test - public void testStringValidation() { - assertFalse(manager.isValidRecipeNameRawName("NONSENSE")); - assertTrue(manager.isValidRecipeNameRawName(manager.listAvailableRecipes().stream().findAny().get().originName)); + void testStringValidation() { + assertThat(manager.isValidRecipeNameRawName("NONSENSE")).isFalse(); + var anyRecipe = manager.listAvailableRecipes().stream().findAny().get(); + assertThat(manager.isValidRecipeNameRawName(anyRecipe.originName)).isTrue(); } @Test - public void testEnumValidation() { - assertFalse(manager.isValidRecipeEnum(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)); - assertTrue(manager.isValidRecipeEnum( - Arrays.stream(RewriteRecipeEnum.values()) - .filter(x -> !x.equals(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)).findAny().get())); + void testEnumValidation() { + assertThat(manager.isValidRecipeEnum(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)).isFalse(); + var validRecipe = java.util.Arrays.stream(RewriteRecipeEnum.values()) + .filter(x -> x != RewriteRecipeEnum.UNRECOGNIZED_RECIPE).findAny().get(); + assertThat(manager.isValidRecipeEnum(validRecipe)).isTrue(); } } From c58b4b1b5f667b5779ed6523bb2295275a88fb94 Mon Sep 17 00:00:00 2001 From: samuelkos17 Date: Mon, 10 Aug 2026 10:41:16 +0200 Subject: [PATCH 16/17] #1031: applied spotless --- .../devonfw/tools/ide/commandlet/RewriteCommandletTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java index 2e23d51569..1c8230e622 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java @@ -1,10 +1,10 @@ package com.devonfw.tools.ide.commandlet; +import static org.junit.jupiter.api.Assertions.assertThrows; + import java.nio.file.Path; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertThrows; - import org.junit.jupiter.api.Test; import com.devonfw.tools.ide.cli.CliException; From c849851bd8506a2e87090a51b3a4a1e689e33470 Mon Sep 17 00:00:00 2001 From: samuelkos17 Date: Tue, 18 Aug 2026 13:54:41 +0200 Subject: [PATCH 17/17] #1031: Code clean up --- CHANGELOG.adoc | 3 +++ .../ide/commandlet/RewriteCommandlet.java | 15 +++++------- .../ide/tool/openrewrite/RecipeManager.java | 24 +++++-------------- .../ide/tool/openrewrite/RecipeWrapper.java | 5 ---- cli/src/main/resources/nls/Help.properties | 3 +-- cli/src/main/resources/nls/Help_de.properties | 3 +-- .../ide/commandlet/RewriteCommandletTest.java | 18 ++------------ .../tool/openrewrite/RecipeManagerTest.java | 7 ------ 8 files changed, 19 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8866a010de..5a417be254 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,6 +6,9 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE Release with new features and bugfixes: +* https://github.com/devonfw/IDEasy/issues/1031[#1031]: Added OpenRewrite commandlet + + The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/49?closed=1[milestone 2026.08.002]. diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java index 02acfa6933..7ece1bb5f5 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RewriteCommandlet.java @@ -145,15 +145,12 @@ public void doRun() { LOG.info("Actual command line: {}", commandLine); - try { - List args = adaptMVNCommand(commandLine); - // Inject -f so Maven runs in the correct project - args.add(0, "-f"); - args.add(1, projectRoot.toString()); - getCommandlet(Mvn.class).runTool(args); - } catch (Exception e) { - throw new CliException("OpenRewrite execution failed for recipe '" + wrapper.ideasyCommand.name() + "': " + e.getMessage(), e); - } + List args = adaptMVNCommand(commandLine); + // Inject -f so Maven runs in the correct project + args.add(0, "-f"); + args.add(1, projectRoot.toString()); + getCommandlet(Mvn.class).runTool(args); + } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java index 168cf0fb16..74e9ff4b69 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java @@ -2,12 +2,11 @@ import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Optional; import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.json.JsonMapping; @@ -23,8 +22,11 @@ public class RecipeManager { private final Map recipes; public RecipeManager() { - try (BufferedReader reader = new BufferedReader(new InputStreamReader( - Objects.requireNonNull(RecipeManager.class.getClassLoader().getResourceAsStream(OPEN_REWRITE_CONFIG_JSON_PATH)), StandardCharsets.UTF_8))) { + InputStream is = RecipeManager.class.getClassLoader().getResourceAsStream(OPEN_REWRITE_CONFIG_JSON_PATH); + if (is == null) { + throw new CliException("Failed to load " + OPEN_REWRITE_CONFIG_JSON_PATH + " from classpath"); + } + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { ObjectMapper objectMapper = JsonMapping.create(); List wrapperList = objectMapper.readValue(reader, objectMapper.getTypeFactory().constructCollectionType(List.class, RecipeWrapper.class)); @@ -48,20 +50,6 @@ public List listAvailableRecipes() { return List.copyOf(recipes.values()); } - private Optional findRecipeByName(String rawName) { - return recipes.values().stream().filter(x -> x.originName.equals(rawName)).findFirst(); - } - - /** - * Checks if a recipe with the given original OpenRewrite name exists in the configuration. - * - * @param rawName the original recipe name (e.g. {@code "java.format_autoformat"}). - * @return {@code true} if a matching recipe was found. - */ - public boolean isValidRecipeNameRawName(String rawName) { - return findRecipeByName(rawName).isPresent(); - } - /** * Checks if a recipe for the given {@link RewriteRecipeEnum} exists in the configuration. * diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java index 53ea3cdc7e..ae365c5b02 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java @@ -18,9 +18,4 @@ public RecipeWrapper(String description, String originName, String url, RewriteR this.rawCmd = rawCmd; } - //in case of future need - public String getName() { - return this.originName; - } - } diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index f9e0e448c3..12f8a6a233 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -127,7 +127,7 @@ cmd.repository.detail=Without further arguments this will set up all pre-configu cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories. cmd.rewrite=Refactor existing code base with specific recipes provided by OpenRewrite cmd.rewrite.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/ -cmd.rewrite.val.recipe_name=Rewrite recipe names (RECIPE_1|RECIPE_2|RECIPE_3) +cmd.rewrite.val.recipe_name=Rewrite recipe names (FORMAT_JAVA_CODE|REMOVE_BLANK_LINES) cmd.ruff=Tool commandlet for Ruff. cmd.ruff.detail=Ruff is an extremely fast Python linter and code formatter. Detailed documentation can be found at https://docs.astral.sh/ruff/ cmd.rust=Tool commandlet for Rust (programming language). @@ -212,7 +212,6 @@ val.commandlet=The selected commandlet (use 'ide help' to list all commandlets). val.edition=The tool edition. val.link=The path where the link is created. val.plugin=The plugin to select -val.recipe-extra-arguments=possible additional arguments for the recipe val.settingsRepository=The settings git repository with the IDEasy configuration for the project. val.source=The source path the link points to (existing file or directory). val.tool=The tool commandlet to select. diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 7483febdbf..2b7f77213a 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -127,7 +127,7 @@ cmd.repository.detail=Dies wird alle vorkonfigurierten Repositories einrichten. cmd.repository.val.repository=Der Name der Properties-Datei des vorkonfigurierten Git Repositories zum Einrichten. Falls nicht angegeben, werden alle aktiven Projekte eingerichtet. cmd.rewrite=Refaktorieren Sie die vorhandene Codebasis mit spezifischen Rezepten von OpenRewrite cmd.rewrite.detail=OpenRewrite ist ein beliebtes Tool für Refactoring (Metaprogrammierung). Eine ausführliche Dokumentation finden Sie unter https://docs.openrewrite.org/ -cmd.rewrite.val.recipe_name=Rezeptnamen umgestalten (RECIPE_1|RECIPE_2|RECIPE_3) +cmd.rewrite.val.recipe_name=Rezeptnamen umgestalten (FORMAT_JAVA_CODE|REMOVE_BLANK_LINES) cmd.ruff=Werkzeug Kommando für Ruff. cmd.ruff.detail=Ruff ist ein extrem schneller Python-Linter und Code-Formatter. Detaillierte Dokumentation findet sich unter https://docs.astral.sh/ruff/ cmd.rust=Werkzeug Kommando für Rust (Programmiersprache). @@ -212,7 +212,6 @@ val.commandlet=Das ausgewählte Commandlet ("ide help" verwenden, um alle Comman val.edition=Die Werkzeug Edition. val.link=Pfad des zu erstellenden Links. val.plugin=Die zu selektierende Erweiterung. -val.recipe-extra-arguments=Mögliche zusätzliche Argumente für das Rezept. val.settingsRepository=Das settings git Repository mit den IDEasy Einstellungen für das Projekt. val.source=Ziel des Links (existierender Pfad). val.tool=Das zu selektierende Werkzeug Kommando. diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java index 1c8230e622..5c905cbc95 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/RewriteCommandletTest.java @@ -1,6 +1,5 @@ package com.devonfw.tools.ide.commandlet; -import static org.junit.jupiter.api.Assertions.assertThrows; import java.nio.file.Path; import java.util.List; @@ -41,17 +40,6 @@ void testRecipeManagerLoadsRecipes() { assertThat(manager.isValidRecipeEnum(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)).isFalse(); } - /** - * Tests that {@link RecipeManager} validates raw recipe names. - */ - @Test - void testRecipeManagerValidatesRawName() { - RecipeManager manager = new RecipeManager(); - assertThat(manager.isValidRecipeNameRawName("NONSENSE")).isFalse(); - RecipeWrapper wrapper = manager.getRecipeWrapper(RewriteRecipeEnum.FORMAT_JAVA_CODE); - assertThat(manager.isValidRecipeNameRawName(wrapper.originName)).isTrue(); - } - /** * Tests that the dry-run conversion correctly replaces :run with :dryRun. */ @@ -113,8 +101,7 @@ void testDoRunThrowsForInvalidRecipe() { IdeTestContext context = newContext("basic"); RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); commandlet.command.setValue(RewriteRecipeEnum.UNRECOGNIZED_RECIPE); - CliException e = assertThrows(CliException.class, commandlet::doRun); - assertThat(e.getMessage()).contains("Invalid recipe name"); + assertThatThrownBy(commandlet::doRun).isInstanceOf(CliException.class).hasMessageContaining("Invalid recipe name"); } /** @@ -154,7 +141,6 @@ void testFindProjectRootThrowsWhenNoCwd() { IdeTestContext context = newContext("basic"); RewriteCommandlet commandlet = context.getCommandletManager().getCommandlet(RewriteCommandlet.class); context.setCwd(null, "main", context.getIdeHome()); - CliException e = assertThrows(CliException.class, commandlet::findProjectRoot); - assertThat(e.getMessage()).contains("current working directory"); + assertThatThrownBy(commandlet::findProjectRoot).isInstanceOf(CliException.class).hasMessageContaining("current working directory"); } } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java index 1cd32bd0c5..5a5e5b4ad8 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java @@ -21,13 +21,6 @@ void testCreation() { assertThat(manager.listAvailableRecipes()).isNotEmpty(); } - @Test - void testStringValidation() { - assertThat(manager.isValidRecipeNameRawName("NONSENSE")).isFalse(); - var anyRecipe = manager.listAvailableRecipes().stream().findAny().get(); - assertThat(manager.isValidRecipeNameRawName(anyRecipe.originName)).isTrue(); - } - @Test void testEnumValidation() { assertThat(manager.isValidRecipeEnum(RewriteRecipeEnum.UNRECOGNIZED_RECIPE)).isFalse();