ソースを参照

Unwrap MessageException

pull/3361/head
Julien HENRY 3週間前
コミット
792b34433b

+ 49
- 21
sonar-scanner-engine/src/it/java/org/sonar/scanner/mediumtest/bootstrap/BootstrapMediumIT.java ファイルの表示

@@ -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) {


+ 42
- 13
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java ファイルの表示

@@ -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) {

読み込み中…
キャンセル
保存