From fe2c657052361cc0edef25d5d2873c96a2f588c0 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Thu, 9 Jan 2025 10:40:12 +0100 Subject: [PATCH 1/2] SCANJLIB-250 Preserve stderr/stdout when the command fails early --- .../scanner/lib/internal/facade/forked/JavaRunner.java | 10 +++++----- .../lib/internal/facade/forked/JavaRunnerTest.java | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java b/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java index 848738d6..35636b18 100644 --- a/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java +++ b/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java @@ -56,15 +56,15 @@ public boolean execute(List args, @Nullable String input, Consumer LOG.error("[stderr] {}", stderr)); stdErrConsummer.start(); stdoutConsummer.start(); + if (input != null && process.isAlive()) { + try (var stdin = process.getOutputStream(); var osw = new OutputStreamWriter(stdin, StandardCharsets.UTF_8)) { + osw.write(input); + } + } var exitCode = process.waitFor(); stdoutConsummer.join(); stdErrConsummer.join(); diff --git a/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java b/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java index be8bfdce..241f234b 100644 --- a/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java +++ b/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java @@ -59,6 +59,15 @@ void execute_shouldLogProcessStdError() { assertThat(logTester.logs(Level.ERROR)).isNotEmpty().allMatch(s -> s.startsWith("[stderr] ")); } + @Test + void execute_shouldLogProcessStdError_and_skip_writing_to_stdin_when_process_fails_early() { + JavaRunner runner = new JavaRunner(Paths.get("java"), JreCacheHit.DISABLED); + List command = List.of("-xyz"); + assertThat(runner.execute(command, "test", stdOut::add)).isFalse(); + + assertThat(logTester.logs(Level.ERROR)).anyMatch(s -> s.startsWith("[stderr] Unrecognized option: -xyz")); + } + @Test void execute_whenInvalidRunner_shouldFail() { JavaRunner runner = new JavaRunner(Paths.get("invalid-runner"), JreCacheHit.DISABLED); From 79cc4c9b4f970b21a575638dd06c0ec3ca5a412b Mon Sep 17 00:00:00 2001 From: Antoine Vinot Date: Fri, 10 Jan 2025 11:03:23 +0100 Subject: [PATCH 2/2] =?UTF-8?q?SCANJLIB-246=20Improve=20the=20error=20mess?= =?UTF-8?q?age=20when=20the=20JRE=20provisioning=20is=20b=E2=80=A6=20(#223?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../internal/facade/forked/JavaRunner.java | 13 ++++++++++- .../lib/ScannerEngineBootstrapperTest.java | 8 +++---- .../facade/forked/JavaRunnerTest.java | 23 +++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java b/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java index 35636b18..a212c5de 100644 --- a/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java +++ b/lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunner.java @@ -36,6 +36,10 @@ public class JavaRunner { private static final Logger LOG = LoggerFactory.getLogger(JavaRunner.class); + static final String JRE_VERSION_ERROR = "The version of the custom JRE provided to the SonarScanner using the 'sonar.scanner.javaExePath' parameter is incompatible " + + "with your SonarQube target. You may need to upgrade the version of Java that executes the scanner. " + + "Refer to https://docs.sonarsource.com/sonarqube-community-build/analyzing-source-code/scanners/scanner-environment/general-requirements/ for more details."; + private final Path javaExecutable; private final JreCacheHit jreCacheHit; @@ -68,6 +72,7 @@ public boolean execute(List args, @Nullable String input, Consumer consumer) { @Override public void run() { new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .forEach(consumer); + .forEach(line -> { + consumer.accept(line); + if (line.contains("UnsupportedClassVersionError")) { + LOG.error(JRE_VERSION_ERROR); + } + }); } + } } diff --git a/lib/src/test/java/org/sonarsource/scanner/lib/ScannerEngineBootstrapperTest.java b/lib/src/test/java/org/sonarsource/scanner/lib/ScannerEngineBootstrapperTest.java index 78ab433e..31602e8c 100644 --- a/lib/src/test/java/org/sonarsource/scanner/lib/ScannerEngineBootstrapperTest.java +++ b/lib/src/test/java/org/sonarsource/scanner/lib/ScannerEngineBootstrapperTest.java @@ -403,15 +403,15 @@ void should_set_deprecated_ssl_properties() { when(httpConfig.getSslConfig()) .thenReturn(new SslConfig( - new CertificateStore(Paths.get("some/keystore.p12"), "keystorePass"), - new CertificateStore(Paths.get("some/truststore.p12"), "truststorePass"))); + new CertificateStore(Paths.get("some", "keystore.p12"), "keystorePass"), + new CertificateStore(Paths.get("some", "truststore.p12"), "truststorePass"))); underTest.adaptDeprecatedPropertiesForInProcessBootstrapping(Map.of(), httpConfig); assertThat(System.getProperties()).contains( - entry("javax.net.ssl.keyStore", "some/keystore.p12"), + entry("javax.net.ssl.keyStore", Paths.get("some", "keystore.p12").toString()), entry("javax.net.ssl.keyStorePassword", "keystorePass"), - entry("javax.net.ssl.trustStore", "some/truststore.p12"), + entry("javax.net.ssl.trustStore", Paths.get("some", "truststore.p12").toString()), entry("javax.net.ssl.trustStorePassword", "truststorePass")); } diff --git a/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java b/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java index 241f234b..1c52a010 100644 --- a/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java +++ b/lib/src/test/java/org/sonarsource/scanner/lib/internal/facade/forked/JavaRunnerTest.java @@ -23,12 +23,15 @@ import java.util.List; import java.util.concurrent.ConcurrentLinkedDeque; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.RegisterExtension; import org.slf4j.event.Level; import testutils.LogTester; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.sonarsource.scanner.lib.internal.facade.forked.JavaRunner.JRE_VERSION_ERROR; class JavaRunnerTest { @@ -84,4 +87,24 @@ void execute_shouldReturnFalseWhenNonZeroExitCode() { assertThat(runner.execute(command, null, stdOut::add)).isFalse(); } + @Test + @EnabledOnOs(OS.WINDOWS) + void execute_shouldLogUnsupportedClassVersionError_whenOsIsWindows() { + JavaRunner runner = new JavaRunner(Paths.get("cmd.exe"), JreCacheHit.DISABLED); + List command = List.of("/c", "echo UnsupportedClassVersionError 1>&2"); + + assertThat(runner.execute(command, null, stdOut::add)).isTrue(); + assertThat(logTester.logs(Level.ERROR)).contains(JRE_VERSION_ERROR); + } + + @Test + @EnabledOnOs(OS.LINUX) + void execute_shouldLogUnsupportedClassVersionError_whenOsIsLinux() { + JavaRunner runner = new JavaRunner(Paths.get("sh"), JreCacheHit.DISABLED); + List command = List.of("-c", ">&2 echo UnsupportedClassVersionError"); + + assertThat(runner.execute(command, null, stdOut::add)).isTrue(); + assertThat(logTester.logs(Level.ERROR)).contains(JRE_VERSION_ERROR); + } + }