]> source.dussan.org Git - sonarqube.git/commitdiff
Unwrap MessageException
authorJulien HENRY <julien.henry@sonarsource.com>
Tue, 7 May 2024 10:39:16 +0000 (12:39 +0200)
committersonartech <sonartech@sonarsource.com>
Mon, 13 May 2024 20:02:41 +0000 (20:02 +0000)
sonar-scanner-engine/src/it/java/org/sonar/scanner/mediumtest/bootstrap/BootstrapMediumIT.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java

index d7e0f7fc758963f5d105cc7e3db6d700e8495be8..06033ba21dd50eed5f325d2976750f1596c12065 100644 (file)
@@ -26,6 +26,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.slf4j.event.Level;
 import org.sonar.api.testfixtures.log.LogTesterJUnit5;
 import org.sonar.scanner.bootstrap.ScannerMain;
@@ -39,7 +41,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
 import static com.github.tomakehurst.wiremock.client.WireMock.post;
 import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static testutils.TestUtils.protobufBody;
 
 class BootstrapMediumIT {
@@ -104,37 +105,37 @@ class BootstrapMediumIT {
   @Test
   void should_fail_if_invalid_json_input() {
     var in = new ByteArrayInputStream("}".getBytes());
-    var e = assertThrows(IllegalArgumentException.class, () -> ScannerMain.run(in));
-    assertThat(e).hasMessage("Failed to parse JSON input");
 
-    assertThat(logTester.logs()).contains("Starting SonarScanner Engine...");
+    var exitCode = ScannerMain.run(in);
+
+    assertThat(exitCode).isEqualTo(1);
+    assertThat(logTester.getLogs(Level.ERROR)).hasSize(1);
+    assertThat(logTester.getLogs(Level.ERROR).get(0).getFormattedMsg()).isEqualTo("Error during SonarScanner Engine execution");
+    assertThat(logTester.getLogs(Level.ERROR).get(0).getThrowable()).isInstanceOf(IllegalArgumentException.class).hasMessage("Failed to parse JSON input");
   }
 
   @Test
   void should_warn_if_null_property_key() {
-    try {
-      ScannerMain.run(new ByteArrayInputStream("{\"scannerProperties\": [{\"value\": \"aValueWithoutKey\"}]}".getBytes()));
-    } catch (Exception ignored) {
-    }
-    assertThat(logTester.logs()).contains("Ignoring property with null key: 'aValueWithoutKey'");
+    ScannerMain.run(new ByteArrayInputStream("""
+      {"scannerProperties": [{"value": "aValueWithoutKey"}]}""".getBytes()));
+
+    assertThat(logTester.logs(Level.WARN)).contains("Ignoring property with null key: 'aValueWithoutKey'");
   }
 
   @Test
   void should_warn_if_duplicate_property_keys() {
-    try {
-      ScannerMain.run(new ByteArrayInputStream("{\"scannerProperties\": [{\"key\": \"aKey\"}, {\"key\": \"aKey\"}]}".getBytes()));
-    } catch (Exception ignored) {
-    }
-    assertThat(logTester.logs()).contains("Duplicated properties with key: 'aKey'");
+    ScannerMain.run(new ByteArrayInputStream("""
+      {"scannerProperties": [{"key": "aKey"}, {"key": "aKey"}]}""".getBytes()));
+
+    assertThat(logTester.logs(Level.WARN)).contains("Duplicated properties with key: 'aKey'");
   }
 
   @Test
   void should_warn_if_null_property() {
-    try {
-      ScannerMain.run(new ByteArrayInputStream("{\"scannerProperties\": [{\"key\": \"aKey\", \"value\": \"aValue\"},]}".getBytes()));
-    } catch (Exception ignored) {
-    }
-    assertThat(logTester.logs()).contains("Ignoring null property");
+    ScannerMain.run(new ByteArrayInputStream("""
+      {"scannerProperties": [{"key": "aKey", "value": "aValue"},]}""".getBytes()));
+
+    assertThat(logTester.logs(Level.WARN)).contains("Ignoring null property");
   }
 
   /**
@@ -142,16 +143,43 @@ class BootstrapMediumIT {
    */
   @Test
   void should_complete_successfully(@TempDir Path baseDir) {
-
-    ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
+    var exitCode = ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
       + "{\"key\": \"sonar.host.url\", \"value\": \"" + sonarqube.baseUrl() + "\"},"
       + "{\"key\": \"sonar.projectKey\", \"value\": \"" + PROJECT_KEY + "\"},"
       + "{\"key\": \"sonar.projectBaseDir\", \"value\": \"" + baseDir + "\"}"
       + "]}").getBytes()));
 
+    assertThat(exitCode).isZero();
     assertThat(logTester.logs()).contains("SonarScanner Engine completed successfully");
   }
 
+  @Test
+  void should_unwrap_message_exception_without_stacktrace(@TempDir Path baseDir) {
+    var exitCode = ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
+      + "{\"key\": \"sonar.host.url\", \"value\": \"" + sonarqube.baseUrl() + "\"},"
+      + "{\"key\": \"sonar.projectBaseDir\", \"value\": \"" + baseDir + "\"}"
+      + "]}").getBytes()));
+
+    assertThat(exitCode).isEqualTo(1);
+    assertThat(logTester.getLogs(Level.ERROR)).hasSize(1);
+    assertThat(logTester.getLogs(Level.ERROR).get(0).getFormattedMsg()).isEqualTo("You must define the following mandatory properties for 'Unknown': sonar.projectKey");
+    assertThat(logTester.getLogs(Level.ERROR).get(0).getThrowable()).isNull();
+  }
+
+  @Test
+  void should_show_message_exception_stacktrace_in_debug(@TempDir Path baseDir) {
+    var exitCode = ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
+      + "{\"key\": \"sonar.host.url\", \"value\": \"" + sonarqube.baseUrl() + "\"},"
+      + "{\"key\": \"sonar.projectBaseDir\", \"value\": \"" + baseDir + "\"},"
+      + "{\"key\": \"sonar.verbose\", \"value\": \"true\"}"
+      + "]}").getBytes()));
+
+    assertThat(exitCode).isEqualTo(1);
+    assertThat(logTester.getLogs(Level.ERROR)).hasSize(1);
+    assertThat(logTester.getLogs(Level.ERROR).get(0).getFormattedMsg()).isEqualTo("You must define the following mandatory properties for 'Unknown': sonar.projectKey");
+    assertThat(logTester.getLogs(Level.ERROR).get(0).getThrowable()).isNotNull();
+  }
+
   @Test
   void should_enable_verbose(@TempDir Path baseDir) {
 
index 044b42fd62009f182bd1a4f9ae75cdf48462c78f..1dbafef4ce9abe8f2df02950378124497f4e6e06 100644 (file)
@@ -30,9 +30,11 @@ import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import javax.annotation.CheckForNull;
 import org.jetbrains.annotations.NotNull;
 import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.MessageException;
 import org.sonar.batch.bootstrapper.EnvironmentInformation;
 import org.sonar.batch.bootstrapper.LoggingConfiguration;
 
@@ -47,26 +49,53 @@ public class ScannerMain {
   private static final String SCANNER_APP_VERSION_KEY = "sonar.scanner.appVersion";
 
   public static void main(String... args) {
-    try {
-      run(System.in);
-    } catch (Exception e) {
-      LOG.error("Error during SonarScanner Engine execution", e);
-      System.exit(1);
-    }
+    System.exit(run(System.in));
   }
 
-  public static void run(InputStream in) {
-    LOG.info("Starting SonarScanner Engine...");
+  public static int run(InputStream in) {
+    try {
+      LOG.info("Starting SonarScanner Engine...");
+
+      var properties = parseInputProperties(in);
+
+      EnvironmentConfig.processEnvVariables(properties);
 
-    var properties = parseInputProperties(in);
+      configureLogLevel(properties);
 
-    EnvironmentConfig.processEnvVariables(properties);
+      runScannerEngine(properties);
 
-    configureLogLevel(properties);
+      LOG.info("SonarScanner Engine completed successfully");
+      return 0;
+    } catch (Exception e) {
+      handleException(e);
+      return 1;
+    }
+  }
+
+  private static void handleException(Exception e) {
+    var messageException = unwrapMessageException(e);
+    if (messageException.isPresent()) {
+      // Don't show the stacktrace for a message exception to not pollute the logs
+      if (LoggerFactory.getLogger(ScannerMain.class).isDebugEnabled()) {
+        LOG.error(messageException.get(), e);
+      } else {
+        LOG.error(messageException.get());
+      }
+    } else {
+      LOG.error("Error during SonarScanner Engine execution", e);
+    }
+  }
 
-    runScannerEngine(properties);
+  private static Optional<String> unwrapMessageException(Exception t) {
+    Throwable y = t;
+    do {
+      if (y instanceof MessageException messageException) {
+        return Optional.of(messageException.getMessage());
+      }
+      y = y.getCause();
+    } while (y != null);
 
-    LOG.info("SonarScanner Engine completed successfully");
+    return Optional.empty();
   }
 
   private static @NotNull Map<String, String> parseInputProperties(InputStream in) {