Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
deb7f46
add: add help information for the rewrite command
yurii-yu Feb 26, 2025
0b18f92
add: add help information for the rewrite command
yurii-yu Mar 3, 2025
2eecccc
add: add help information for the rewrite command
yurii-yu Mar 6, 2025
d746c6a
add: add help information for the rewrite command
yurii-yu Mar 6, 2025
a7a0312
update: add necessary commandlet and property
yurii-yu Mar 6, 2025
6e5baf1
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
yurii-yu Apr 25, 2025
1568f82
Merge branch 'main' into feature/1031_intergrate_with_openrewrite
yurii-yu Apr 25, 2025
1963978
Merge branch 'main' into feature/1031_intergrate_with_openrewrite
jan-vcapgemini Apr 28, 2025
276d69f
Merge branch 'main' into feature/1031_intergrate_with_openrewrite
yurii-yu May 21, 2025
9212855
Merge remote-tracking branch 'origin/feature/1031_intergrate_with_ope…
yurii-yu May 21, 2025
6ea329a
Merge branch 'main' into feature/1031_intergrate_with_openrewrite
hohwille Aug 22, 2025
6970443
add: help message for RefactorCommandlet
yurii-yu Aug 26, 2025
10f82d7
add: wrapper of the configurable recipe
yurii-yu Aug 26, 2025
5e29a3a
update: two configuration files (more recipes can be added in this way)
yurii-yu Aug 26, 2025
3f843e3
update: keep names consistent with the names in the config file
yurii-yu Aug 26, 2025
faa40be
add: placeholder enum
yurii-yu Aug 26, 2025
35eb98c
update: finish the implementation
yurii-yu Aug 26, 2025
7bffb92
update: finish the feature
yurii-yu Aug 26, 2025
631037c
Merge branch 'main' into feature/1031_intergrate_with_openrewrite
yurii-yu Oct 24, 2025
c32d2a1
fix: fix failed errors by correcting the text
yurii-yu Oct 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public CommandletManagerImpl(IdeContext context) {
add(new Node(context));
add(new Npm(context));
add(new Mvn(context));
add(new RefactorCommandlet(context));
add(new GcViewer(context));
add(new Gradle(context));
add(new Eclipse(context));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
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 <a href="https://docs.openrewrite.org/">Refactor</a>.
*/
public class RefactorCommandlet extends Commandlet {

public final EnumProperty<RefactorRecipeEnum> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<String> {

public RefactorRecipeProperty(String name) {

this(name, null);
}

public RefactorRecipeProperty(String name, PropertyValidator<String> validator) {

super(name, true, null, true, validator);
}

@Override
public Class<String> 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);
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -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<RefactorRecipeEnum, RecipeWrapper> 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<RecipeWrapper> 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<RecipeWrapper> listAvailableRecipes() {
return Collections.unmodifiableList(recipes.values().stream().toList());
}

private Optional<RecipeWrapper> 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);
}

}
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.devonfw.tools.ide.tool.openrewrite;

public enum RefactorRecipeEnum {
FORMAT_JAVA_CODE, REMOVE_BLANK_LINES, UNRECOGNIZED_RECIPE
}
4 changes: 4 additions & 0 deletions cli/src/main/resources/nls/Help.properties
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ 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.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 <repository>'
cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `<repository>` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/<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.
Expand Down Expand Up @@ -155,6 +158,7 @@ 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.
Expand Down
4 changes: 4 additions & 0 deletions cli/src/main/resources/nls/Help_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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 <repository>'.
cmd.repository.detail=Dies wird alle vorkonfigurierten Repositories einrichten. Rufen Sie einfach 'ide repository setup <your_project_name>' auf, ersetzen Sie <your_project_name> 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.
Expand Down Expand Up @@ -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.
Expand Down
16 changes: 16 additions & 0 deletions cli/src/main/resources/refactor/openrewrite.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
Original file line number Diff line number Diff line change
@@ -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()));
}
}
16 changes: 16 additions & 0 deletions cli/src/test/resources/refactor/openrewrite.json
Original file line number Diff line number Diff line change
@@ -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"
}
]