From e34b39f3b24bb7c7268f2c77e86e19e948a21431 Mon Sep 17 00:00:00 2001 From: aboyko Date: Wed, 3 Jan 2024 16:52:58 -0500 Subject: [PATCH] Prompt for changes preview when applying OR recipes --- .../commands/RewriteRefactoringsHandler.java | 5 +- .../vscode/commons/rewrite/ORDocUtils.java | 9 +- .../java/rewrite/RewriteRecipeRepository.java | 139 +++++++++++------- .../java/rewrite/RewriteRefactorings.java | 67 ++------- .../boot/java/rewrite/SpringBootUpgrade.java | 6 +- .../generations/UpdateBootVersion.java | 8 +- .../vscode-spring-boot/lib/rewrite.ts | 30 +--- 7 files changed, 109 insertions(+), 155 deletions(-) diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/RewriteRefactoringsHandler.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/RewriteRefactoringsHandler.java index 113e599ad..cd601e785 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/RewriteRefactoringsHandler.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/RewriteRefactoringsHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 VMware, Inc. + * Copyright (c) 2022, 2024 VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -101,7 +101,8 @@ public class RewriteRefactoringsHandler extends AbstractHandler { cmdParams.setCommand(REWRITE_REFACTORINGS_EXEC); cmdParams.setArguments(List.of( uri, - SERIALIZATION_GSON.toJsonTree(recipeSelection) + SERIALIZATION_GSON.toJsonTree(recipeSelection), + true // ask for preview )); ls.getWorkspaceService().executeCommand(cmdParams).get(); diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/ORDocUtils.java b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/ORDocUtils.java index 45b1d6273..4ae2c8115 100644 --- a/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/ORDocUtils.java +++ b/headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/ORDocUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,12 +12,9 @@ package org.springframework.ide.vscode.commons.rewrite; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.UUID; import org.eclipse.lsp4j.AnnotatedTextEdit; -import org.eclipse.lsp4j.ChangeAnnotation; import org.eclipse.lsp4j.CreateFile; import org.eclipse.lsp4j.DeleteFile; import org.eclipse.lsp4j.Position; @@ -157,14 +154,12 @@ public class ORDocUtils { return 0; } - public static Optional createWorkspaceEdit(SimpleTextDocumentService documents, List results, ChangeAnnotation changeAnnotation) { + public static Optional createWorkspaceEdit(SimpleTextDocumentService documents, List results, String changeAnnotationId) { if (results.isEmpty()) { return Optional.empty(); } WorkspaceEdit we = new WorkspaceEdit(); we.setDocumentChanges(new ArrayList<>()); - final String changeAnnotationId = UUID.randomUUID().toString(); - we.setChangeAnnotations(Map.of(changeAnnotationId, changeAnnotation)); for (Result result : results) { if (result.getBefore() == null) { String docUri = result.getAfter().getSourcePath().toUri().toASCIIString(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java index 75cb6b76e..be5cac2ac 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRecipeRepository.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 VMware, Inc. + * Copyright (c) 2022, 2024 VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -36,8 +36,12 @@ import java.util.stream.Collectors; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.ChangeAnnotation; +import org.eclipse.lsp4j.MessageActionItem; +import org.eclipse.lsp4j.MessageType; +import org.eclipse.lsp4j.ShowMessageRequestParams; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.WorkspaceEditChangeAnnotationSupportCapabilities; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.ParseExceptionResult; import org.openrewrite.Parser; @@ -102,7 +106,6 @@ public class RewriteRecipeRepository { private static final String CMD_REWRITE_EXECUTE = "sts/rewrite/execute"; private static final String CMD_REWRITE_LIST = "sts/rewrite/list"; private static final String CMD_REWRITE_SUBLIST = "sts/rewrite/sublist"; - private static final String CMD_REWRITE_RECIPE_EXECUTE = "sts/rewrite/recipe/execute"; private static final Logger log = LoggerFactory.getLogger(RewriteRecipeRepository.class); private static final Set UNINITIALIZED_SET = Collections.emptySet(); @@ -356,7 +359,7 @@ public class RewriteRecipeRepository { return recipes().thenCompose(recipesMap -> { String uri = ((JsonElement) params.getArguments().get(0)).getAsString(); JsonElement recipesJson = ((JsonElement) params.getArguments().get(1)); - boolean needsConfirmation = params.getArguments().size() > 2 ? ((JsonElement) params.getArguments().get(2)).getAsBoolean() : false; + boolean askForPreview = params.getArguments().size() > 2 ? ((JsonElement) params.getArguments().get(2)).getAsBoolean() : false; RecipeSelectionDescriptor[] descriptors = serializationGson.fromJson(recipesJson, RecipeSelectionDescriptor[].class); List recipes = Arrays.stream(descriptors).map(d -> createRecipeFromSelection(recipesMap.get(d.id()), d.subselection())).collect(Collectors.toList()); @@ -366,7 +369,7 @@ public class RewriteRecipeRepository { || params.getWorkDoneToken().getLeft() == null ? (r.getName() == null ? UUID.randomUUID().toString() : r.getName()) : params.getWorkDoneToken().getLeft(); - return apply(r, uri, progressToken, needsConfirmation); + return apply(r, uri, progressToken, askForPreview); } else { String name = recipes.size() + " recipes"; DeclarativeRecipe aggregateRecipe = new DeclarativeRecipe( @@ -385,7 +388,7 @@ public class RewriteRecipeRepository { ? (aggregateRecipe.getName() == null ? UUID.randomUUID().toString() : aggregateRecipe.getName()) : params.getWorkDoneToken().getLeft(); - return apply(aggregateRecipe, uri, progressToken, needsConfirmation); + return apply(aggregateRecipe, uri, progressToken, askForPreview); } }); }); @@ -395,72 +398,98 @@ public class RewriteRecipeRepository { return CompletableFuture.completedFuture("executed"); }); - server.onCommand(CMD_REWRITE_RECIPE_EXECUTE, params -> { - String recipeId = ((JsonElement) params.getArguments().get(0)).getAsString(); - boolean needsConfirmation = params.getArguments().size() > 1 ? ((JsonElement) params.getArguments().get(1)).getAsBoolean() : false; - return getRecipe(recipeId).thenCompose(optRecipe -> { - Recipe r = optRecipe.orElseThrow(() -> new IllegalArgumentException("No such recipe exists with name " + recipeId)); - final String progressToken = params.getWorkDoneToken() == null || params.getWorkDoneToken().getLeft() == null ? r.getName() : params.getWorkDoneToken().getLeft(); - String uri = ((JsonElement) params.getArguments().get(1)).getAsString(); - return apply(r, uri, progressToken, needsConfirmation); - }); - }); } - CompletableFuture apply(Recipe r, String uri, String progressToken, boolean needsConfirmation) { + CompletableFuture apply(Recipe r, String uri, String progressToken, boolean askForPreview) { final IndefiniteProgressTask progressTask = server.getProgressService().createIndefiniteProgressTask(progressToken, r.getDisplayName(), "Initiated..."); return CompletableFuture.supplyAsync(() -> { return projectFinder.find(new TextDocumentIdentifier(uri)); }).thenCompose(p -> { if (p.isPresent()) { - try { - Optional edit = computeWorkspaceEdit(r, p.get(), progressTask, needsConfirmation); - return CompletableFuture.completedFuture(edit).thenCompose(we -> { - if (we.isPresent()) { - progressTask.progressEvent("Applying document changes..."); - return server.getClient().applyEdit(new ApplyWorkspaceEditParams(we.get(), r.getDisplayName())).thenCompose(res -> { - if (res.isApplied()) { - progressTask.done(); - return CompletableFuture.completedFuture("success"); - } else { - progressTask.done(); - return CompletableFuture.completedFuture(null); - } - }); - } else { - progressTask.done(); - return CompletableFuture.completedFuture(null); - } - }); - } catch (Throwable t) { - progressTask.done(); - throw t; - } + IJavaProject project = p.get(); + Path absoluteProjectDir = Paths.get(project.getLocationUri()); + progressTask.progressEvent("Parsing files..."); + ProjectParser projectParser = createRewriteProjectParser(project, + pr -> { + TextDocument doc = server.getTextDocumentService().getLatestSnapshot(pr.toUri().toASCIIString()); + if (doc != null) { + return new Parser.Input(pr, () -> new ByteArrayInputStream(doc.get().getBytes())); + } + return null; + }); + List sources = projectParser.parse(absoluteProjectDir, new InMemoryExecutionContext(e -> log.error("Project Parsing error:", e))); + + return computeWorkspaceEditAwareOfPreview(r, sources, progressTask, askForPreview) + .thenCompose(we -> applyEdit(we, progressTask, r.getDisplayName())); } else { return CompletableFuture.failedFuture(new IllegalArgumentException("Cannot find Spring Boot project for uri: " + uri)); } + }).whenComplete((o,t) -> progressTask.done()); + } + + CompletableFuture> computeWorkspaceEditAwareOfPreview(Recipe r, List sources, IndefiniteProgressTask progressTask, boolean askForPreview) { + String changeAnnotationId = UUID.randomUUID().toString(); + Optional we = computeWorkspaceEdit(r, sources, progressTask, changeAnnotationId); + if (we.isPresent()) { + CompletableFuture editFuture = askForPreview ? askForPreview(we.get(), changeAnnotationId) : CompletableFuture.completedFuture(we.get()); + return editFuture.thenApply(Optional::of); + } + return CompletableFuture.completedFuture(Optional.empty()); + } + + private CompletableFuture askForPreview(WorkspaceEdit workspaceEdit, String changeAnnotationId) { + return server.getClientCapabilities().thenApply(capabilities -> { + WorkspaceEditChangeAnnotationSupportCapabilities changeAnnotationSupport = capabilities.getWorkspace().getWorkspaceEdit().getChangeAnnotationSupport(); + return changeAnnotationSupport != null && changeAnnotationSupport.getGroupsOnLabel() != null && changeAnnotationSupport.getGroupsOnLabel().booleanValue(); + }).thenCompose(supportsChangeAnnotation -> { + if (supportsChangeAnnotation) { + final MessageActionItem previewChanges = new MessageActionItem("Preview"); + final MessageActionItem applyChanges = new MessageActionItem("Apply"); + ShowMessageRequestParams messageParams = new ShowMessageRequestParams(); + messageParams.setType(MessageType.Info); + messageParams.setMessage("Do you want to preview chnages before applying or apply right away?"); + messageParams.setActions(List.of(applyChanges, previewChanges)); + return server.getClient().showMessageRequest(messageParams).thenApply(previewChanges::equals); + } else { + return CompletableFuture.completedFuture(false); + } + }).thenApply(needsConfirmation -> { + ChangeAnnotation changeAnnotation = workspaceEdit.getChangeAnnotations().get(changeAnnotationId); + changeAnnotation.setNeedsConfirmation(needsConfirmation); + return workspaceEdit; }); } - private Optional computeWorkspaceEdit(Recipe r, IJavaProject project, IndefiniteProgressTask progressTask, boolean needsConfirmation) { - Path absoluteProjectDir = Paths.get(project.getLocationUri()); - progressTask.progressEvent("Parsing files..."); - ProjectParser projectParser = createRewriteProjectParser(project, - p -> { - TextDocument doc = server.getTextDocumentService().getLatestSnapshot(p.toUri().toASCIIString()); - if (doc != null) { - return new Parser.Input(p, () -> new ByteArrayInputStream(doc.get().getBytes())); - } - return null; - }); - List sources = projectParser.parse(absoluteProjectDir, new InMemoryExecutionContext(e -> log.error("Project Parsing error:", e))); + private CompletableFuture applyEdit(Optional we, IndefiniteProgressTask progressTask, String title) { + if (we.isPresent()) { + WorkspaceEdit workspaceEdit = we.get(); + if (progressTask != null) { + progressTask.progressEvent("Applying document changes..."); + } + return server.getClient().applyEdit(new ApplyWorkspaceEditParams(workspaceEdit, title)).thenCompose(res -> { + if (res.isApplied()) { + return CompletableFuture.completedFuture("success"); + } else { + return CompletableFuture.completedFuture(null); + } + }); + } else { + return CompletableFuture.completedFuture(null); + } + } + + Optional computeWorkspaceEdit(Recipe r, List sources, IndefiniteProgressTask progressTask, String changeAnnotationId) { reportParseErrors(sources.stream().filter(ParseError.class::isInstance).map(ParseError.class::cast).collect(Collectors.toList())); - progressTask.progressEvent("Computing changes..."); + if (progressTask != null) { + progressTask.progressEvent("Computing changes..."); + } RecipeRun reciperun = r.run(new InMemoryLargeSourceSet(sources), new InMemoryExecutionContext(e -> log.error("Recipe execution failed", e))); List results = reciperun.getChangeset().getAllResults(); - ChangeAnnotation changeAnnotation = new ChangeAnnotation("Apply Recipe '" + r.getDisplayName() + "'"); - changeAnnotation.setNeedsConfirmation(needsConfirmation); - return ORDocUtils.createWorkspaceEdit(server.getTextDocumentService(), results, changeAnnotation); + return ORDocUtils.createWorkspaceEdit(server.getTextDocumentService(), results, changeAnnotationId).map(we -> { + ChangeAnnotation changeAnnotation = new ChangeAnnotation(r.getDisplayName()); + we.setChangeAnnotations(Map.of(changeAnnotationId, changeAnnotation)); + return we; + }); } private void reportParseErrors(List parseErrors) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRefactorings.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRefactorings.java index e1a19584c..2419f85c7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRefactorings.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteRefactorings.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 VMware, Inc. + * Copyright (c) 2022, 2024 VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -13,49 +13,36 @@ package org.springframework.ide.vscode.boot.java.rewrite; import java.lang.reflect.Field; import java.net.URI; import java.nio.file.Paths; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import org.eclipse.lsp4j.ChangeAnnotation; import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.ResourceOperation; -import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; -import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Parser.Input; import org.openrewrite.Recipe; -import org.openrewrite.RecipeRun; -import org.openrewrite.Result; import org.openrewrite.SourceFile; -import org.openrewrite.internal.InMemoryLargeSourceSet; import org.openrewrite.internal.RecipeIntrospectionUtils; import org.openrewrite.java.JavaParser; -import org.openrewrite.java.tree.J.CompilationUnit; import org.openrewrite.marker.Range; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.languageserver.PercentageProgressTask; +import org.springframework.ide.vscode.commons.languageserver.IndefiniteProgressTask; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEdit; import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixHandler; import org.springframework.ide.vscode.commons.languageserver.util.CodeActionResolver; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; -import org.springframework.ide.vscode.commons.rewrite.ORDocUtils; import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope; import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor; import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils; import org.springframework.ide.vscode.commons.rewrite.java.RangeScopedRecipe; -import org.springframework.ide.vscode.commons.util.text.LanguageId; -import org.springframework.ide.vscode.commons.util.text.TextDocument; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -117,64 +104,34 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler public CompletableFuture createEdit(JsonElement o) { FixDescriptor data = gson.fromJson(o, FixDescriptor.class); if (data != null && data.getRecipeId() != null) { - return perform(data); + return perform(data).thenApply(we -> we.orElse(null)); } return null; } - private WorkspaceEdit applyRecipe(Recipe r, IJavaProject project, List cus, boolean needsConfirmation) { - List sources = cus.stream().map(cu -> (SourceFile) cu).collect(Collectors.toList()); - RecipeRun reciperun = r.run(new InMemoryLargeSourceSet(sources), new InMemoryExecutionContext()); - List results = reciperun.getChangeset().getAllResults(); - final String changeAnnotationId = UUID.randomUUID().toString(); - List> edits = results.stream().filter(res -> res.getAfter() != null).map(res -> { - URI docUri = res.getAfter().getSourcePath().isAbsolute() ? res.getAfter().getSourcePath().toUri() : project.getLocationUri().resolve(res.getAfter().getSourcePath().toString()); - TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docUri.toASCIIString()); - if (doc == null) { - doc = new TextDocument(docUri.toASCIIString(), LanguageId.JAVA, 0, res.getBefore() == null ? "" : res.getBefore().printAll()); - } - return ORDocUtils.computeTextDocEdit(doc, res, changeAnnotationId); - }).filter(e -> e.isPresent()).map(e -> e.get()).map(e -> Either.forLeft(e)).collect(Collectors.toList()); - if (edits.isEmpty()) { - return null; - } - WorkspaceEdit workspaceEdit = new WorkspaceEdit(); - ChangeAnnotation changeAnnotation = new ChangeAnnotation("Applying Recipe '" + r.getDisplayName() + "'"); - changeAnnotation.setNeedsConfirmation(needsConfirmation); - workspaceEdit.setChangeAnnotations(Map.of(changeAnnotationId, changeAnnotation)); - workspaceEdit.setDocumentChanges(edits); - return workspaceEdit; - } - - private CompletableFuture perform(FixDescriptor data) { + private CompletableFuture> perform(FixDescriptor data) { Optional project = projectFinder.find(new TextDocumentIdentifier(data.getDocUris().get(0))); if (project.isPresent()) { boolean projectWide = data.getRecipeScope() == RecipeScope.PROJECT; - return createRecipe(data).thenApply(r -> { + IndefiniteProgressTask progress = server.getProgressService().createIndefiniteProgressTask(UUID.randomUUID().toString(), data.getLabel(), "Parsing files..."); + return createRecipe(data).thenCompose(r -> { if (r == null) { log.warn("Code Action failed to resolve. Could not create recipe created with id '" + data.getRecipeId() + "'."); } - List cus = Collections.emptyList(); + List cus = new ArrayList<>(); if (projectWide) { JavaParser jp = ORAstUtils.createJavaParserBuilder(project.get()).dependsOn(data.getTypeStubs()).build(); List inputs = ORAstUtils.getParserInputs(server.getTextDocumentService(), project.get()); - PercentageProgressTask progress = server.getProgressService().createPercentageProgressTask(UUID.randomUUID().toString(), inputs.size() + 1, data.getLabel()); - try { - cus = ORAstUtils.parseInputs(jp, inputs, s -> progress.increment()); - return applyRecipe(r, project.get(), cus, false); - } finally { - progress.setCurrent(progress.getTotal()); - progress.done(); - } + cus.addAll(ORAstUtils.parseInputs(jp, inputs, null)); } else { JavaParser jp = ORAstUtils.createJavaParserBuilder(project.get()).dependsOn(data.getTypeStubs()).build(); List inputs = data.getDocUris().stream().map(URI::create).map(Paths::get).map(p -> ORAstUtils.getParserInput(server.getTextDocumentService(), p)).collect(Collectors.toList()); - cus = ORAstUtils.parseInputs(jp, inputs, null); - return applyRecipe(r, project.get(), cus, false); + cus.addAll(ORAstUtils.parseInputs(jp, inputs, null)); } + return recipeRepo.computeWorkspaceEditAwareOfPreview(r, cus, progress, projectWide).whenComplete((o, t) -> progress.done()); }); } - return CompletableFuture.completedFuture(null); + return CompletableFuture.completedFuture(Optional.empty()); } private CompletableFuture>> findRecipeClass(String className) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/SpringBootUpgrade.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/SpringBootUpgrade.java index a2f7aae92..6cf880b7d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/SpringBootUpgrade.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/SpringBootUpgrade.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 VMware, Inc. + * Copyright (c) 2022, 2024 VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -58,7 +58,7 @@ public class SpringBootUpgrade { Assert.isLegal(uri != null, "Project URI parameter must not be 'null'"); Version targetVersion = Version.parse(((JsonElement) params.getArguments().get(1)).getAsString()); Assert.isLegal(targetVersion != null, "Target Spring Boot version must not be 'null'"); - boolean needsConfirmation = params.getArguments().size() > 2 ? ((JsonElement) params.getArguments().get(2)).getAsBoolean() : false; + boolean askForPreview = params.getArguments().size() > 2 ? ((JsonElement) params.getArguments().get(2)).getAsBoolean() : false; IJavaProject project = projectFinder.find(new TextDocumentIdentifier(uri)).orElse(null); Assert.isLegal(project != null, "No Spring Boot project found for uri: " + uri); @@ -77,7 +77,7 @@ public class SpringBootUpgrade { createUpgradeRecipe(recipes, version, targetVersion), uri, UUID.randomUUID().toString(), - needsConfirmation + askForPreview )); }); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/validation/generations/UpdateBootVersion.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/validation/generations/UpdateBootVersion.java index c4f14048c..355c452a7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/validation/generations/UpdateBootVersion.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/validation/generations/UpdateBootVersion.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -76,7 +76,7 @@ public class UpdateBootVersion extends AbstractDiagnosticValidator { c.setTitle("Upgrade to Spring Boot " + targetVersion + " (executes the full project conversion recipe from OpenRewrite)"); String commandId = SpringBootUpgrade.CMD_UPGRADE_SPRING_BOOT; c.setCommand(new Command("Upgrade to Version " + targetVersion, commandId, - ImmutableList.of(javaProject.getLocationUri().toASCIIString(), targetVersion))); + ImmutableList.of(javaProject.getLocationUri().toASCIIString(), targetVersion, true))); return c; }).ifPresent(actions::add); @@ -109,7 +109,7 @@ public class UpdateBootVersion extends AbstractDiagnosticValidator { c.setTitle("Upgrade to Spring Boot " + targetVersion + " (executes the full project conversion recipe from OpenRewrite)"); String commandId = SpringBootUpgrade.CMD_UPGRADE_SPRING_BOOT; c.setCommand(new Command("Upgrade to Version " + targetVersion, commandId, - ImmutableList.of(javaProject.getLocationUri().toASCIIString(), targetVersion))); + ImmutableList.of(javaProject.getLocationUri().toASCIIString(), targetVersion, true))); return c; }).ifPresent(actions::add); @@ -138,7 +138,7 @@ public class UpdateBootVersion extends AbstractDiagnosticValidator { c.setTitle("Upgrade to Spring Boot " + latest.toString() + " (Maven dependency version changes only)"); String commandId = SpringBootUpgrade.CMD_UPGRADE_SPRING_BOOT; c.setCommand(new Command("Upgrade to Version " + latest.toString(), commandId, - ImmutableList.of(javaProject.getLocationUri().toASCIIString(), latest.toString()))); + ImmutableList.of(javaProject.getLocationUri().toASCIIString(), latest.toString(), false))); return c; }).ifPresent(actions::add); diff --git a/vscode-extensions/vscode-spring-boot/lib/rewrite.ts b/vscode-extensions/vscode-spring-boot/lib/rewrite.ts index d83d3d1fc..5c77628f3 100644 --- a/vscode-extensions/vscode-spring-boot/lib/rewrite.ts +++ b/vscode-extensions/vscode-spring-boot/lib/rewrite.ts @@ -100,9 +100,8 @@ async function showRefactorings(uri: VSCode.Uri, filter: string) { } const choices = await showCurrentPathQuickPick(VSCode.commands.executeCommand('sts/rewrite/list', filter).then((cmds: RecipeDescriptor[]) => cmds.map(d => convertToQuickPickItem(d, false))), []); const recipeDescriptors = choices.filter(i => i.selected).map(convertToRecipeSelectionDescriptor); - const needsConfirmation = await shwoNeedsConfirmation(); if (recipeDescriptors.length) { - VSCode.commands.executeCommand('sts/rewrite/execute', uri.toString(true), recipeDescriptors, needsConfirmation); + VSCode.commands.executeCommand('sts/rewrite/execute', uri.toString(true), recipeDescriptors, true); } else { VSCode.window.showErrorMessage('No Recipes were selected!'); } @@ -129,33 +128,6 @@ function convertToQuickPickItem(i: RecipeDescriptor, selected?: boolean): Recipe }; } -function shwoNeedsConfirmation(): Thenable { - return new Promise((resolve, reject) => { - const previewPick = VSCode.window.createQuickPick(); - previewPick.title = 'Preview Before Applying?'; - previewPick.canSelectMany = false; - - const applyItem = { - label: "Apply", - description: "Apply changes maded by a recipe" - } - const previewItem = { - label: "Preview", - description: "Preview and confirm changes made by a recipe before applying" - } - previewPick.items = [ - applyItem, - previewItem - ]; - previewPick.show(); - - previewPick.onDidAccept(() => { - previewPick.hide(); - resolve(previewPick.selectedItems[0] === previewItem); - }); - }); -} - function showCurrentPathQuickPick(itemsPromise: Thenable, itemsPath: RecipeQuickPickItem[]): Thenable { const quickPick = VSCode.window.createQuickPick(); quickPick.title = 'Loading Recipes...';