diff --git a/its/pom.xml b/its/pom.xml index e8a28480..d23c7ae6 100644 --- a/its/pom.xml +++ b/its/pom.xml @@ -20,10 +20,22 @@ + + org.junit.jupiter + junit-jupiter-api + 5.11.3 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.11.3 + test + org.sonarsource.orchestrator sonar-orchestrator-junit5 - 4.8.0.1898 + 5.0.0.2065 test @@ -41,7 +53,7 @@ org.assertj assertj-core - 3.9.0 + 3.26.3 test diff --git a/its/projects/maven/bootstrap-small-project/pom.xml b/its/projects/maven/bootstrap-small-project/pom.xml index 47913a2e..a7262ddf 100644 --- a/its/projects/maven/bootstrap-small-project/pom.xml +++ b/its/projects/maven/bootstrap-small-project/pom.xml @@ -8,6 +8,22 @@ 11 11 + true + + -Dhttp.proxyUser=my-custom-user-from-pom-xml + + + com.google.code.findbugs + jsr305 + 3.0.2 + provided + + + diff --git a/its/projects/maven/bootstrap-small-project/src/main/java/org/example/Hello.java b/its/projects/maven/bootstrap-small-project/src/main/java/org/example/Hello.java new file mode 100644 index 00000000..b341320b --- /dev/null +++ b/its/projects/maven/bootstrap-small-project/src/main/java/org/example/Hello.java @@ -0,0 +1,4 @@ +package org.example; + +public interface Hello { +} diff --git a/its/src/test/java/com/sonar/maven/it/suite/BootstrapTest.java b/its/src/test/java/com/sonar/maven/it/suite/BootstrapTest.java index 9b88f24e..411f1ff7 100644 --- a/its/src/test/java/com/sonar/maven/it/suite/BootstrapTest.java +++ b/its/src/test/java/com/sonar/maven/it/suite/BootstrapTest.java @@ -28,11 +28,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Properties; +import org.assertj.core.api.SoftAssertions; +import org.assertj.core.api.StringAssert; import org.junit.jupiter.api.Test; +import static com.sonar.maven.it.ItUtils.locateProjectDir; import static org.assertj.core.api.Assertions.assertThat; -public class BootstrapTest extends AbstractMavenTest { +class BootstrapTest extends AbstractMavenTest { @Test void test_unsupported_platform() { @@ -65,28 +68,102 @@ void test_supported_arch_to_assert_jre_used() throws IOException { MavenBuild build = MavenBuild.create(ItUtils.locateProjectPom(projectName)) .setProperty("sonar.login", ORCHESTRATOR.getDefaultAdminToken()) .setProperty("sonar.host.url", ORCHESTRATOR.getServer().getUrl()) + .setEnvironmentVariable("DUMP_SENSOR_PROPERTIES", "" + + "any.property.name," + + "sonar.java.fileByFile," + + "sonar.java.file.suffixes," + + "sonar.projectKey," + + "sonar.projectBaseDir," + + "sonar.sources," + + "sonar.working.directory," + + "sonar.java.libraries," + + "sonar.java.source," + + "sonar.java.target," + + "sonar.java.test.libraries," + + "sonar.java.jdkHome") + .setEnvironmentVariable("DUMP_ENV_PROPERTIES", "" + + "ANY_ENV_VAR") + .setEnvironmentVariable("DUMP_SYSTEM_PROPERTIES", "" + + "http.proxyUser,"+ + "http.nonProxyHosts," + + "java.home") + .setEnvironmentVariable("ANY_ENV_VAR", "42") + // http.nonProxyHosts will only be present in the maven context and not in the provisioned JRE + .setProperty("http.nonProxyHosts", "localhost|my-custom-non-proxy.server.com") + // Any property will be passed to the sensorContext.config() + .setProperty("any.property.name", "foo42") + // This property will be ignored because of the bellow "sonar.scanner.javaOpts" property that has priority + .setEnvironmentVariable("SONAR_SCANNER_JAVA_OPTS", "-Dhttp.proxyUser=my-custom-user-from-env") + // Set system property on the provisioned JRE + .setProperty("sonar.scanner.javaOpts", "-Dhttp.proxyUser=my-custom-user-from-system-properties") .setGoals(cleanSonarGoal()); - BuildResult result = validateBuildWithCE(runner.runQuietly(null, build)); assertThat(result.isSuccess()).isTrue(); Path propertiesFile = ItUtils.locateProjectDir(projectName).toPath().resolve("target/sonar/dumpSensor.system.properties"); Properties props = new Properties(); props.load(Files.newInputStream(propertiesFile)); + Path smallProjectDir = locateProjectDir("maven").getAbsoluteFile().toPath().resolve("bootstrap-small-project"); + + SoftAssertions softly = new SoftAssertions(); + + // Environment variables + softly.assertThat(props.getProperty("ANY_ENV_VAR")).isEqualTo( "42"); + + // User defined in its/projects/maven/bootstrap-small-project/pom.xml properties + softly.assertThat(props.getProperty("sonar.java.fileByFile")).isEqualTo( "true"); + + // SonarQube properties + softly.assertThat(props.getProperty("sonar.java.file.suffixes")).isEqualTo( ".java,.jav"); + + // Project properties + softly.assertThat(props.getProperty("sonar.projectKey")).isEqualTo( "org.sonarsource.maven.its:bootstrap-small-project"); + softly.assertThat(props.getProperty("sonar.projectBaseDir")).isEqualTo( smallProjectDir.toString()); + softly.assertThat(props.getProperty("sonar.sources")).isEqualTo( smallProjectDir.resolve("pom.xml") + "," + smallProjectDir.resolve("src").resolve("main").resolve("java")); + softly.assertThat(props.getProperty("sonar.working.directory")).isEqualTo( smallProjectDir.resolve("target").resolve("sonar").toString()); + + // Any properties are present in the sensor context + softly.assertThat(props.getProperty("any.property.name")).contains("foo42"); + + // Java analyzers properties + softly.assertThat(props.getProperty("sonar.java.libraries")).contains("jsr305-3.0.2.jar"); + softly.assertThat(props.getProperty("sonar.java.source")).isEqualTo( "11"); + softly.assertThat(props.getProperty("sonar.java.target")).isEqualTo( "11"); + softly.assertThat(props.getProperty("sonar.java.test.libraries")).contains("jsr305-3.0.2.jar"); + // sonar.java.jdkHome should be the one used by "mvn sonar:sonar", by default maven uses JAVA_HOME + String javaHome = System.getenv("JAVA_HOME"); + if (javaHome == null) { + javaHome = System.getProperty("java.home"); + } + softly.assertThat(props.getProperty("sonar.java.jdkHome")).isEqualTo( new File(javaHome).getCanonicalPath()); + + StringAssert javaHomeAssertion = softly.assertThat(props.getProperty("java.home")).isNotEmpty(); if (ORCHESTRATOR.getServer().version().isGreaterThanOrEquals(10, 6)) { //we test that we are actually using the JRE downloaded from SQ - assertThat(props.getProperty("java.home")) - .isNotEmpty() + javaHomeAssertion .isNotEqualTo(System.getProperty("java.home")) .contains(".sonar" + File.separator + "cache"); + + // System properties of the initial JRE are intentionally not set on the provisioned JRE + softly.assertThat(props.getProperty("http.nonProxyHosts")) + .isEmpty(); + + // System properties defined in "sonar.scanner.javaOpts" are set on the provisioned JRE + softly.assertThat(props.getProperty("http.proxyUser")).isEqualTo("my-custom-user-from-system-properties"); } else { //we test that we are using the system JRE - assertThat(props.getProperty("java.home")) - .isNotEmpty() + javaHomeAssertion .isEqualTo(System.getProperty("java.home")) .doesNotContain(".sonar" + File.separator + "cache"); + + softly.assertThat(props.getProperty("http.nonProxyHosts")) + .isEqualTo("localhost|my-custom-non-proxy.server.com"); + + // System properties defined in "sonar.scanner.javaOpts" are ignored outside the provisioned JRE + softly.assertThat(props.getProperty("http.proxyUser")).isEmpty(); } + softly.assertAll(); } } diff --git a/pom.xml b/pom.xml index 3697bd07..48d6047a 100644 --- a/pom.xml +++ b/pom.xml @@ -172,7 +172,7 @@ org.assertj assertj-core - 3.24.2 + 3.26.3 test diff --git a/property-dump-plugin/src/main/java/org/sonar/dump/PropertyDumpPlugin.java b/property-dump-plugin/src/main/java/org/sonar/dump/PropertyDumpPlugin.java index 3d49148a..5eb3271c 100644 --- a/property-dump-plugin/src/main/java/org/sonar/dump/PropertyDumpPlugin.java +++ b/property-dump-plugin/src/main/java/org/sonar/dump/PropertyDumpPlugin.java @@ -22,12 +22,17 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.Plugin; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.config.Configuration; public class PropertyDumpPlugin implements Plugin, Sensor { @@ -45,17 +50,37 @@ public void describe(SensorDescriptor sensorDescriptor) { @Override public void execute(SensorContext sensorContext) { - var props = System.getProperties(); try { Path filePath = sensorContext.fileSystem().workDir().toPath().resolve("dumpSensor.system.properties"); - LOG.info("Dumping system properties to {}", filePath); - props.stringPropertyNames().stream() - .filter(key -> key.startsWith("java.")) - .forEach(key -> LOG.info("{}={}", key, props.getProperty(key))); + LOG.info("Dumping sensorContext properties, environment variables, and system properties to {}", filePath); + var props = new Properties(); + Configuration config = sensorContext.config(); + getPropertyKeys("DUMP_SENSOR_PROPERTIES").forEach(key -> props.setProperty(key, nonNull(config.get(key)))); + getPropertyKeys("DUMP_ENV_PROPERTIES").forEach(key -> props.setProperty(key, nonNull(System.getenv(key)))); + getPropertyKeys("DUMP_SYSTEM_PROPERTIES").forEach(key -> props.setProperty(key, nonNull(System.getProperty(key, "")))); + props.stringPropertyNames().forEach(key -> LOG.info("{}={}", key, props.getProperty(key))); props.store(Files.newOutputStream(filePath), null); } catch (IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e.getClass().getSimpleName() + ": " + e.getMessage(), e); } } + private static String nonNull(Object value) { + if (value instanceof Optional opt) { + value = opt.orElse(null); + } + if (value != null) { + return value.toString(); + } + return ""; + } + + private static List getPropertyKeys(String envName) { + String list = System.getenv(envName); + if (list == null) { + return List.of(); + } + return Arrays.asList(list.replace(" ", "").split(",", -1)); + } + }