From fe1bba7f89a9826a6ca0bddfe3794dbc29802060 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Thu, 24 Aug 2023 15:43:53 +0200 Subject: [PATCH] Significantly improve the output of the update command When having an error, it was extremely confusing, you had confusing error messages, a lot of nested exceptions... This will improve the output, make sure we have proper colors for the log levels and avoid having two levels logged. Also avoid a couple of nested exceptions and make the error messages more actionable. (cherry picked from commit 815013827669d358049c5710f0a4e12a79d58abb) --- .../java/io/quarkus/maven/UpdateMojo.java | 7 +- .../handlers/UpdateProjectCommandHandler.java | 3 - .../update/rewrite/QuarkusUpdateCommand.java | 95 +++++++++++++++++-- .../rewrite/QuarkusUpdateException.java | 2 +- .../QuarkusUpdateExitErrorException.java | 14 +++ 5 files changed, 105 insertions(+), 16 deletions(-) create mode 100644 independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateExitErrorException.java diff --git a/devtools/maven/src/main/java/io/quarkus/maven/UpdateMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/UpdateMojo.java index 113ca35670cdb..4bc790ec24f7f 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/UpdateMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/UpdateMojo.java @@ -16,6 +16,7 @@ import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.devtools.project.update.rewrite.QuarkusUpdateExitErrorException; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.registry.RegistryResolutionException; import io.quarkus.registry.catalog.ExtensionCatalog; @@ -129,10 +130,12 @@ protected void processProjectState(QuarkusProject quarkusProject) throws MojoExe final QuarkusCommandOutcome result = invoker.execute(); if (!result.isSuccess()) { throw new MojoExecutionException( - "The command did not succeed."); + "Failed to apply the updates."); } + } catch (QuarkusUpdateExitErrorException e) { + throw new MojoExecutionException(e.getMessage()); } catch (QuarkusCommandException e) { - throw new MojoExecutionException("Failed to resolve the available updates", e); + throw new MojoExecutionException("Failed to apply the updates", e); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/UpdateProjectCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/UpdateProjectCommandHandler.java index 3b1b268de1d07..3a0895b31e170 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/UpdateProjectCommandHandler.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/UpdateProjectCommandHandler.java @@ -30,7 +30,6 @@ import io.quarkus.devtools.project.update.ProjectPlatformUpdateInfo; import io.quarkus.devtools.project.update.ProjectUpdateInfos; import io.quarkus.devtools.project.update.rewrite.QuarkusUpdateCommand; -import io.quarkus.devtools.project.update.rewrite.QuarkusUpdateException; import io.quarkus.devtools.project.update.rewrite.QuarkusUpdates; import io.quarkus.devtools.project.update.rewrite.QuarkusUpdatesRepository; import io.quarkus.maven.dependency.ArtifactCoords; @@ -117,8 +116,6 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws rewriteDryRun); } catch (IOException e) { throw new QuarkusCommandException("Error while generating the project update script", e); - } catch (QuarkusUpdateException e) { - throw new QuarkusCommandException("Error while running the project update script", e); } } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java index 41d4c6ccf6c17..f8d252621bb8f 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java @@ -12,7 +12,9 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -39,7 +41,7 @@ public static String goal(boolean dryRun) { } public static void handle(MessageWriter log, BuildTool buildTool, Path baseDir, - String rewritePluginVersion, String recipesGAV, Path recipe, boolean dryRun) throws QuarkusUpdateException { + String rewritePluginVersion, String recipesGAV, Path recipe, boolean dryRun) { switch (buildTool) { case MAVEN: runMavenUpdate(log, baseDir, rewritePluginVersion, recipesGAV, recipe, dryRun); @@ -53,7 +55,7 @@ public static void handle(MessageWriter log, BuildTool buildTool, Path baseDir, } private static void runGradleUpdate(MessageWriter log, Path baseDir, String rewritePluginVersion, String recipesGAV, - Path recipe, boolean dryRun) throws QuarkusUpdateException { + Path recipe, boolean dryRun) { Path tempInit = null; try { tempInit = Files.createTempFile("openrewrite-init", "gradle"); @@ -77,8 +79,11 @@ private static void runGradleUpdate(MessageWriter log, Path baseDir, String rewr "--init-script", tempInit.toAbsolutePath().toString(), dryRun ? "rewriteDryRun" : "rewriteRun" }; executeCommand(baseDir, command, log); + } catch (QuarkusUpdateException e) { + throw e; } catch (Exception e) { - throw new QuarkusUpdateException("Error while running Gradle rewrite command", e); + throw new QuarkusUpdateException( + "Error while running Gradle rewrite command, see the execution logs above for more details", e); } finally { if (tempInit != null) { try { @@ -93,7 +98,7 @@ private static void runGradleUpdate(MessageWriter log, Path baseDir, String rewr private static void runMavenUpdate(MessageWriter log, Path baseDir, String rewritePluginVersion, String recipesGAV, Path recipe, - boolean dryRun) throws QuarkusUpdateException { + boolean dryRun) { final String mvnBinary = findMvnBinary(baseDir); executeCommand(baseDir, getMavenUpdateCommand(mvnBinary, rewritePluginVersion, recipesGAV, recipe, dryRun), log); @@ -118,7 +123,7 @@ private static String[] getMavenUpdateCommand(String mvnBinary, String rewritePl "-Drewrite.pomCacheEnabled=false" }; } - private static void executeCommand(Path baseDir, String[] command, MessageWriter log) throws QuarkusUpdateException { + private static void executeCommand(Path baseDir, String[] command, MessageWriter log) { ProcessBuilder processBuilder = new ProcessBuilder(); log.info(""); log.info(""); @@ -136,8 +141,28 @@ private static void executeCommand(Path baseDir, String[] command, MessageWriter BufferedReader errorReader = new BufferedReader(new java.io.InputStreamReader(process.getErrorStream())); String line; + LogLevel currentLogLevel = LogLevel.UNKNOWN; + while ((line = inputReader.readLine()) != null) { - log.info(line); + Optional detectedLogLevel = LogLevel.of(line); + if (detectedLogLevel.isPresent()) { + currentLogLevel = detectedLogLevel.get(); + } + switch (currentLogLevel) { + case ERROR: + log.error(currentLogLevel.clean(line)); + break; + case WARNING: + log.warn(currentLogLevel.clean(line)); + break; + case INFO: + log.info(currentLogLevel.clean(line)); + break; + case UNKNOWN: + default: + log.info(line); + break; + } } while ((line = errorReader.readLine()) != null) { log.error(line); @@ -149,14 +174,19 @@ private static void executeCommand(Path baseDir, String[] command, MessageWriter int exitCode = process.waitFor(); if (exitCode != 0) { - throw new QuarkusUpdateException("The command to update the project exited with an error: " + exitCode); + throw new QuarkusUpdateExitErrorException( + "The command to update the project exited with an error, see the execution logs above for more details"); } + } catch (QuarkusUpdateException e) { + throw e; } catch (Exception e) { - throw new QuarkusUpdateException("Error while executing command to udpate the project", e); + throw new QuarkusUpdateException( + "Error while executing the command to update the project, see the execution logs above for more details", + e); } } - static String findMvnBinary(Path baseDir) throws QuarkusUpdateException { + static String findMvnBinary(Path baseDir) { Path mavenCmd = findWrapperOrBinary(baseDir, "mvnw", "mvn"); if (mavenCmd == null) { throw new QuarkusUpdateException("Cannot locate mvnw or mvn" @@ -165,7 +195,7 @@ static String findMvnBinary(Path baseDir) throws QuarkusUpdateException { return mavenCmd.toString(); } - static String findGradleBinary(Path baseDir) throws QuarkusUpdateException { + static String findGradleBinary(Path baseDir) { Path gradleCmd = findWrapperOrBinary(baseDir, "gradlew", "gradle"); if (gradleCmd == null) { throw new QuarkusUpdateException("Cannot gradlew mvnw or gradle" @@ -247,4 +277,49 @@ private static boolean hasMaven(Path dir) { return Files.exists(dir.resolve("pom.xml")); } + private enum LogLevel { + + ERROR, + WARNING, + INFO, + UNKNOWN; + + private static final Pattern LEVEL_PATTERN = Pattern.compile("^\\[[A-Z]+\\].*"); + + private static Optional of(String line) { + if (line == null || line.isBlank()) { + return Optional.empty(); + } + + for (LogLevel level : LogLevel.values()) { + if (level.matches(line)) { + return Optional.of(level); + } + } + + if (LEVEL_PATTERN.matcher(line).matches()) { + return Optional.of(UNKNOWN); + } + + return Optional.empty(); + } + + private String clean(String line) { + if (line == null || line.isBlank()) { + return line; + } + + String pattern = "[" + name() + "]"; + + if (line.length() < pattern.length()) { + return line; + } + + return line.substring(pattern.length()).trim(); + } + + private boolean matches(String line) { + return line != null && line.startsWith("[" + name() + "]"); + } + } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateException.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateException.java index 755c396fdbe39..ed5ac4f6160cd 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateException.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateException.java @@ -1,6 +1,6 @@ package io.quarkus.devtools.project.update.rewrite; -public class QuarkusUpdateException extends Exception { +public class QuarkusUpdateException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateExitErrorException.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateExitErrorException.java new file mode 100644 index 0000000000000..8625594a8d8a1 --- /dev/null +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateExitErrorException.java @@ -0,0 +1,14 @@ +package io.quarkus.devtools.project.update.rewrite; + +public class QuarkusUpdateExitErrorException extends QuarkusUpdateException { + + private static final long serialVersionUID = 1L; + + public QuarkusUpdateExitErrorException(String message, Throwable cause) { + super(message, cause); + } + + public QuarkusUpdateExitErrorException(String message) { + super(message); + } +}