diff options
54 files changed, 415 insertions, 197 deletions
diff --git a/server/sonar-auth-github/src/test/java/org/sonar/auth/github/GitHubSettingsTest.java b/server/sonar-auth-github/src/test/java/org/sonar/auth/github/GitHubSettingsTest.java index b960bdd81ff..f15933e922a 100644 --- a/server/sonar-auth-github/src/test/java/org/sonar/auth/github/GitHubSettingsTest.java +++ b/server/sonar-auth-github/src/test/java/org/sonar/auth/github/GitHubSettingsTest.java @@ -22,12 +22,13 @@ package org.sonar.auth.github; import org.junit.Test; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import static org.assertj.core.api.Assertions.assertThat; public class GitHubSettingsTest { - private MapSettings settings = new MapSettings(new PropertyDefinitions(GitHubSettings.definitions())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitHubSettings.definitions())); private GitHubSettings underTest = new GitHubSettings(settings.asConfig()); diff --git a/server/sonar-auth-github/src/test/java/org/sonar/auth/github/IntegrationTest.java b/server/sonar-auth-github/src/test/java/org/sonar/auth/github/IntegrationTest.java index 780213bd459..6c134d5be6a 100644 --- a/server/sonar-auth-github/src/test/java/org/sonar/auth/github/IntegrationTest.java +++ b/server/sonar-auth-github/src/test/java/org/sonar/auth/github/IntegrationTest.java @@ -37,6 +37,7 @@ import org.sonar.api.config.internal.MapSettings; import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; +import org.sonar.api.utils.System2; import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; @@ -52,7 +53,7 @@ public class IntegrationTest { public MockWebServer github = new MockWebServer(); // load settings with default values - private MapSettings settings = new MapSettings(new PropertyDefinitions(GitHubSettings.definitions())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitHubSettings.definitions())); private GitHubSettings gitHubSettings = new GitHubSettings(settings.asConfig()); private UserIdentityFactoryImpl userIdentityFactory = new UserIdentityFactoryImpl(); private ScribeGitHubApi scribeApi = new ScribeGitHubApi(gitHubSettings); diff --git a/server/sonar-auth-github/src/test/java/org/sonar/auth/github/UserIdentityFactoryImplTest.java b/server/sonar-auth-github/src/test/java/org/sonar/auth/github/UserIdentityFactoryImplTest.java index 0913d1ee808..7e3cd01ceeb 100644 --- a/server/sonar-auth-github/src/test/java/org/sonar/auth/github/UserIdentityFactoryImplTest.java +++ b/server/sonar-auth-github/src/test/java/org/sonar/auth/github/UserIdentityFactoryImplTest.java @@ -25,6 +25,7 @@ import org.junit.rules.ExpectedException; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.server.authentication.UserIdentity; +import org.sonar.api.utils.System2; import static org.assertj.core.api.Assertions.assertThat; @@ -33,7 +34,7 @@ public class UserIdentityFactoryImplTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - private MapSettings settings = new MapSettings(new PropertyDefinitions(GitHubSettings.definitions())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitHubSettings.definitions())); private UserIdentityFactoryImpl underTest = new UserIdentityFactoryImpl(); @Test diff --git a/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabSettingsTest.java b/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabSettingsTest.java index 0517f0e55c9..523594dc7dc 100644 --- a/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabSettingsTest.java +++ b/server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabSettingsTest.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.auth.gitlab.GitLabSettings.GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP; @@ -44,7 +45,7 @@ public class GitLabSettingsTest { @Before public void prepare() { - settings = new MapSettings(new PropertyDefinitions(GitLabSettings.definitions())); + settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitLabSettings.definitions())); config = new GitLabSettings(settings.asConfig()); } @@ -55,7 +56,6 @@ public class GitLabSettingsTest { settings.setProperty(GITLAB_AUTH_URL, "https://gitlab.com/api/"); assertThat(config.url()).isEqualTo("https://gitlab.com/api"); - settings.setProperty(GITLAB_AUTH_URL, "https://gitlab.com/api"); assertThat(config.url()).isEqualTo("https://gitlab.com/api"); diff --git a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlIdentityProviderTest.java b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlIdentityProviderTest.java index 6f285db5456..58f3e87a0ab 100644 --- a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlIdentityProviderTest.java +++ b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlIdentityProviderTest.java @@ -27,15 +27,16 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; -import org.apache.commons.io.IOUtils; import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; +import org.sonar.api.utils.System2; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; @@ -48,7 +49,7 @@ public class SamlIdentityProviderTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - private MapSettings settings = new MapSettings(new PropertyDefinitions(SamlSettings.definitions())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, SamlSettings.definitions())); private SamlIdentityProvider underTest = new SamlIdentityProvider(new SamlSettings(settings.asConfig())); diff --git a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlSettingsTest.java b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlSettingsTest.java index b0cdf4e4539..5968416ea3a 100644 --- a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlSettingsTest.java +++ b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlSettingsTest.java @@ -28,6 +28,7 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import static org.assertj.core.api.Assertions.assertThat; @@ -37,7 +38,7 @@ public class SamlSettingsTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - private MapSettings settings = new MapSettings(new PropertyDefinitions(SamlSettings.definitions())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, SamlSettings.definitions())); private SamlSettings underTest = new SamlSettings(settings.asConfig()); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java index d79e1e39739..f725b0056fa 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java @@ -21,9 +21,9 @@ package org.sonar.ce.task.projectanalysis.purge; import org.junit.Before; import org.junit.Test; -import org.sonar.api.CoreProperties; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import org.sonar.core.config.PurgeConstants; import org.sonar.core.config.PurgeProperties; import org.sonar.db.DbSession; @@ -34,9 +34,7 @@ import org.sonar.db.purge.period.DefaultPeriodCleaner; import static java.util.Collections.emptySet; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; public class ProjectCleanerTest { @@ -46,7 +44,7 @@ public class ProjectCleanerTest { private PurgeProfiler profiler = mock(PurgeProfiler.class); private DefaultPeriodCleaner periodCleaner = mock(DefaultPeriodCleaner.class); private PurgeListener purgeListener = mock(PurgeListener.class); - private MapSettings settings = new MapSettings(new PropertyDefinitions(PurgeProperties.all())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, PurgeProperties.all())); @Before public void before() { diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/RatingSettingsTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/RatingSettingsTest.java index b866b423783..8ba5bd1041b 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/RatingSettingsTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/RatingSettingsTest.java @@ -27,6 +27,7 @@ import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.System2; import org.sonar.core.config.CorePropertyDefinitions; import static org.assertj.core.api.Assertions.assertThat; @@ -37,7 +38,7 @@ import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS public class RatingSettingsTest { - private MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all())); @Rule public ExpectedException expectedException = ExpectedException.none(); diff --git a/server/sonar-main/src/main/java/org/sonar/application/command/CommandFactoryImpl.java b/server/sonar-main/src/main/java/org/sonar/application/command/CommandFactoryImpl.java index 13f0b3a6101..2ad11760b3d 100644 --- a/server/sonar-main/src/main/java/org/sonar/application/command/CommandFactoryImpl.java +++ b/server/sonar-main/src/main/java/org/sonar/application/command/CommandFactoryImpl.java @@ -39,7 +39,7 @@ import static org.sonar.process.ProcessProperties.Property.CE_JAVA_ADDITIONAL_OP import static org.sonar.process.ProcessProperties.Property.CE_JAVA_OPTS; import static org.sonar.process.ProcessProperties.Property.HTTPS_PROXY_HOST; import static org.sonar.process.ProcessProperties.Property.HTTPS_PROXY_PORT; -import static org.sonar.process.ProcessProperties.Property.HTTP_AUTH_NLM_DOMAN; +import static org.sonar.process.ProcessProperties.Property.HTTP_AUTH_NTLM_DOMAIN; import static org.sonar.process.ProcessProperties.Property.HTTP_NON_PROXY_HOSTS; import static org.sonar.process.ProcessProperties.Property.HTTP_PROXY_HOST; import static org.sonar.process.ProcessProperties.Property.HTTP_PROXY_PORT; @@ -65,7 +65,7 @@ public class CommandFactoryImpl implements CommandFactory { HTTP_NON_PROXY_HOSTS.getKey(), HTTPS_PROXY_HOST.getKey(), HTTPS_PROXY_PORT.getKey(), - HTTP_AUTH_NLM_DOMAN.getKey(), + HTTP_AUTH_NTLM_DOMAIN.getKey(), SOCKS_PROXY_HOST.getKey(), SOCKS_PROXY_PORT.getKey()}; diff --git a/server/sonar-main/src/main/java/org/sonar/application/config/AppSettingsLoaderImpl.java b/server/sonar-main/src/main/java/org/sonar/application/config/AppSettingsLoaderImpl.java index 3ba85f8e606..d3124e4aa20 100644 --- a/server/sonar-main/src/main/java/org/sonar/application/config/AppSettingsLoaderImpl.java +++ b/server/sonar-main/src/main/java/org/sonar/application/config/AppSettingsLoaderImpl.java @@ -25,7 +25,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.URISyntaxException; -import java.util.Arrays; +import java.util.HashSet; import java.util.Optional; import java.util.Properties; import java.util.Set; @@ -33,6 +33,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import org.slf4j.LoggerFactory; import org.sonar.core.extension.ServiceLoaderWrapper; +import org.sonar.core.util.SettingFormatter; import org.sonar.process.ConfigurationUtils; import org.sonar.process.NetworkUtilsImpl; import org.sonar.process.ProcessProperties; @@ -40,8 +41,11 @@ import org.sonar.process.Props; import org.sonar.process.System2; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Arrays.stream; import static java.util.Optional.ofNullable; import static org.sonar.core.util.SettingFormatter.fromJavaPropertyToEnvVariable; +import static org.sonar.process.ProcessProperties.Property.LDAP_SERVERS; +import static org.sonar.process.ProcessProperties.Property.MULTI_SERVER_LDAP_SETTINGS; import static org.sonar.process.ProcessProperties.Property.PATH_HOME; public class AppSettingsLoaderImpl implements AppSettingsLoader { @@ -73,7 +77,37 @@ public class AppSettingsLoaderImpl implements AppSettingsLoader { @Override public AppSettings load() { Properties p = loadPropertiesFile(homeDir); - fetchSettingsFromEnvironment(system, p); + Set<String> keysOverridableFromEnv = stream(ProcessProperties.Property.values()).map(ProcessProperties.Property::getKey) + .collect(Collectors.toSet()); + keysOverridableFromEnv.addAll(p.stringPropertyNames()); + + // 1st pass to load static properties + Props staticProps = reloadProperties(keysOverridableFromEnv, p); + keysOverridableFromEnv.addAll(getDynamicPropertiesKeys(staticProps)); + + // 2nd pass to load dynamic properties like `ldap.*.url` or `ldap.*.baseDn` which keys depend on values of static + // properties loaded in 1st step + Props props = reloadProperties(keysOverridableFromEnv, p); + + new ProcessProperties(serviceLoaderWrapper).completeDefaults(props); + stream(consumers).forEach(c -> c.accept(props)); + return new AppSettingsImpl(props); + } + + private static Set<String> getDynamicPropertiesKeys(Props p) { + Set<String> dynamicPropertiesKeys = new HashSet<>(); + String ldapServersValue = p.value(LDAP_SERVERS.getKey()); + if (ldapServersValue != null) { + stream(SettingFormatter.getStringArrayBySeparator(ldapServersValue, ",")).forEach( + ldapServer -> MULTI_SERVER_LDAP_SETTINGS.forEach( + multiLdapSetting -> dynamicPropertiesKeys.add(multiLdapSetting.replace("*", ldapServer)))); + } + + return dynamicPropertiesKeys; + } + + private Props reloadProperties(Set<String> keysOverridableFromEnv, Properties p) { + loadPropertiesFromEnvironment(system, p, keysOverridableFromEnv); p.putAll(CommandLineParser.parseArguments(cliArguments)); p.setProperty(PATH_HOME.getKey(), homeDir.getAbsolutePath()); p = ConfigurationUtils.interpolateVariables(p, system.getenv()); @@ -81,18 +115,11 @@ public class AppSettingsLoaderImpl implements AppSettingsLoader { // the difference between Properties and Props is that the latter // supports decryption of values, so it must be used when values // are accessed - Props props = new Props(p); - new ProcessProperties(serviceLoaderWrapper).completeDefaults(props); - Arrays.stream(consumers).forEach(c -> c.accept(props)); - - return new AppSettingsImpl(props); + return new Props(p); } - private static void fetchSettingsFromEnvironment(System2 system, Properties properties) { - Set<String> possibleSettings = Arrays.stream(ProcessProperties.Property.values()).map(ProcessProperties.Property::getKey) - .collect(Collectors.toSet()); - possibleSettings.addAll(properties.stringPropertyNames()); - possibleSettings.forEach(key -> { + private static void loadPropertiesFromEnvironment(System2 system, Properties properties, Set<String> overridableSettings) { + overridableSettings.forEach(key -> { String environmentVarName = fromJavaPropertyToEnvVariable(key); Optional<String> envVarValue = ofNullable(system.getenv(environmentVarName)); envVarValue.ifPresent(value -> properties.put(key, value)); diff --git a/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java b/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java index d6c4aa8f9c5..d66029f6ec9 100644 --- a/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java +++ b/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java @@ -23,15 +23,16 @@ import ch.qos.logback.classic.Level; import java.io.File; import java.util.Properties; import org.sonar.process.ProcessId; +import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import org.sonar.process.logging.Log4JPropertiesBuilder; import org.sonar.process.logging.LogLevelConfig; import org.sonar.process.logging.RootLoggerConfig; +import static org.sonar.process.ProcessProperties.Property.LOG_CONSOLE; import static org.sonar.process.logging.RootLoggerConfig.newRootLoggerConfigBuilder; public class EsLogging { - private static final String ALL_LOGS_TO_CONSOLE_PROPERTY = "sonar.log.console"; public Properties createProperties(Props props, File logDir) { Log4JPropertiesBuilder log4JPropertiesBuilder = new Log4JPropertiesBuilder(props); @@ -51,12 +52,11 @@ public class EsLogging { return log4JPropertiesBuilder.get(); } - /** * Finds out whether we are in testing environment (usually ITs) and logs of all processes must be forward to - * App's System.out. This is specified by the value of property {@link #ALL_LOGS_TO_CONSOLE_PROPERTY}. + * App's System.out. This is specified by the value of property {@link ProcessProperties.Property#LOG_CONSOLE}. */ private static boolean isAllLogsToConsoleEnabled(Props props) { - return props.valueAsBoolean(ALL_LOGS_TO_CONSOLE_PROPERTY, false); + return props.valueAsBoolean(LOG_CONSOLE.getKey(), false); } } diff --git a/server/sonar-main/src/test/java/org/sonar/application/config/AppSettingsLoaderImplTest.java b/server/sonar-main/src/test/java/org/sonar/application/config/AppSettingsLoaderImplTest.java index 988107a6150..db8aa65047c 100644 --- a/server/sonar-main/src/test/java/org/sonar/application/config/AppSettingsLoaderImplTest.java +++ b/server/sonar-main/src/test/java/org/sonar/application/config/AppSettingsLoaderImplTest.java @@ -88,6 +88,27 @@ public class AppSettingsLoaderImplTest { } @Test + public void load_multi_ldap_settings() throws IOException { + when(system.getenv()).thenReturn(ImmutableMap.of( + "LDAP_FOO_URL", "url1", + "LDAP_RANDOM_PROP", "5")); + when(system.getenv("LDAP_FOO_URL")).thenReturn("url1"); + when(system.getenv("LDAP_RANDOM_PROP")).thenReturn("5"); + File homeDir = temp.newFolder(); + File propsFile = new File(homeDir, "conf/sonar.properties"); + FileUtils.write(propsFile, "ldap.servers=foo,bar\n" + + "ldap.bar.url=url2", UTF_8); + AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(system, new String[0], homeDir, serviceLoaderWrapper); + + AppSettings settings = underTest.load(); + + assertThat(settings.getProps().rawProperties()).contains( + entry("ldap.servers", "foo,bar"), + entry("ldap.foo.url", "url1"), + entry("ldap.bar.url", "url2")); + } + + @Test public void throws_ISE_if_file_fails_to_be_loaded() throws Exception { File homeDir = temp.newFolder(); File propsFileAsDir = new File(homeDir, "conf/sonar.properties"); diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java index f643c4a744c..45d01f448f2 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java @@ -19,6 +19,7 @@ */ package org.sonar.process; +import com.google.common.collect.ImmutableSet; import java.net.InetAddress; import java.util.Arrays; import java.util.HashMap; @@ -62,10 +63,14 @@ public class ProcessProperties { PATH_TEMP("sonar.path.temp", "temp"), PATH_WEB("sonar.path.web", "web"), + LOG_LEVEL("sonar.log.level"), LOG_LEVEL_APP("sonar.log.level.app"), LOG_LEVEL_WEB("sonar.log.level.web"), LOG_LEVEL_CE("sonar.log.level.ce"), LOG_LEVEL_ES("sonar.log.level.es"), + LOG_ROLLING_POLICY("sonar.log.rollingPolicy"), + LOG_MAX_FILES("sonar.log.maxFiles"), + LOG_CONSOLE("sonar.log.console"), SEARCH_HOST("sonar.search.host", InetAddress.getLoopbackAddress().getHostAddress()), SEARCH_PORT("sonar.search.port", "9001"), @@ -76,10 +81,19 @@ public class ProcessProperties { SEARCH_MINIMUM_MASTER_NODES("sonar.search.minimumMasterNodes"), SEARCH_INITIAL_STATE_TIMEOUT("sonar.search.initialStateTimeout"), + WEB_HOST("sonar.web.host"), WEB_JAVA_OPTS("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"), WEB_JAVA_ADDITIONAL_OPTS("sonar.web.javaAdditionalOpts", ""), + WEB_CONTEXT("sonar.web.context"), WEB_PORT("sonar.web.port"), WEB_GRACEFUL_STOP_TIMEOUT("sonar.web.gracefulStopTimeOutInMs", "" + 4 * 60 * 1_000L), + WEB_HTTP_MIN_THREADS("sonar.web.http.minThreads"), + WEB_HTTP_MAX_THREADS("sonar.web.http.maxThreads"), + WEB_HTTP_ACCEPT_COUNT("sonar.web.http.acceptCount"), + WEB_SESSION_TIMEOUT_IN_MIN("sonar.web.sessionTimeoutInMinutes"), + WEB_SYSTEM_PASS_CODE("sonar.web.systemPasscode"), + WEB_ACCESSLOGS_ENABLE("sonar.web.accessLogs.enable"), + WEB_ACCESSLOGS_PATTERN("sonar.web.accessLogs.pattern"), CE_JAVA_OPTS("sonar.ce.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"), CE_JAVA_ADDITIONAL_OPTS("sonar.ce.javaAdditionalOpts", ""), @@ -92,7 +106,7 @@ public class ProcessProperties { HTTP_PROXY_USER("http.proxyUser"), HTTP_PROXY_PASSWORD("http.proxyPassword"), HTTP_NON_PROXY_HOSTS("http.nonProxyHosts", "localhost|127.*|[::1]"), - HTTP_AUTH_NLM_DOMAN("http.auth.ntlm.domain"), + HTTP_AUTH_NTLM_DOMAIN("http.auth.ntlm.domain"), SOCKS_PROXY_HOST("socksProxyHost"), SOCKS_PROXY_PORT("socksProxyPort"), @@ -116,6 +130,23 @@ public class ProcessProperties { SONAR_SECURITY_REALM("sonar.security.realm"), SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE("sonar.authenticator.ignoreStartupFailure", "false"), + LDAP_SERVERS("ldap.servers"), + LDAP_URL("ldap.url"), + LDAP_BIND_DN("ldap.bindDn"), + LDAP_BIND_PASSWORD("ldap.bindPassword"), + LDAP_AUTHENTICATION("ldap.authentication"), + LDAP_REALM("ldap.realm"), + LDAP_CONTEXT_FACTORY_CLASS("ldap.contextFactoryClass"), + LDAP_START_TLS("ldap.StartTLS"), + LDAP_FOLLOW_REFERRALS("ldap.followReferrals"), + LDAP_USER_BASE_DN("ldap.user.baseDn"), + LDAP_USER_REQUEST("ldap.user.request"), + LDAP_USER_REAL_NAME_ATTRIBUTE("ldap.user.realNameAttribute"), + LDAP_USER_EMAIL_ATTRIBUTE("ldap.user.emailAttribute"), + LDAP_GROUP_BASE_DN("ldap.group.baseDn"), + LDAP_GROUP_REQUEST("ldap.group.request"), + LDAP_GROUP_ID_ATTRIBUTE("ldap.group.idAttribute"), + SONAR_TELEMETRY_ENABLE("sonar.telemetry.enable", "true"), SONAR_TELEMETRY_URL("sonar.telemetry.url", "https://telemetry.sonarsource.com/sonarqube"), SONAR_TELEMETRY_FREQUENCY_IN_SECONDS("sonar.telemetry.frequencyInSeconds", "21600"), @@ -136,6 +167,26 @@ public class ProcessProperties { // whether the blue/green deployment of server is enabled BLUE_GREEN_ENABLED("sonar.blueGreenEnabled", "false"); + /** + * Properties that are defined for each LDAP server from the `ldap.servers` property + */ + public static final Set<String> MULTI_SERVER_LDAP_SETTINGS = ImmutableSet.of( + "ldap.*.url", + "ldap.*.bindDn", + "ldap.*.bindPassword", + "ldap.*.authentication", + "ldap.*.realm", + "ldap.*.contextFactoryClass", + "ldap.*.StartTLS", + "ldap.*.followReferrals", + "ldap.*.user.baseDn", + "ldap.*.user.request", + "ldap.*.user.realNameAttribute", + "ldap.*.user.emailAttribute", + "ldap.*.group.baseDn", + "ldap.*.group.request", + "ldap.*.group.idAttribute"); + private final String key; private final String defaultValue; diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java b/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java index 87ca0edb8be..e2f256a751c 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java @@ -28,9 +28,6 @@ import static java.lang.String.format; public abstract class AbstractLogHelper { static final Level[] ALLOWED_ROOT_LOG_LEVELS = new Level[] {Level.TRACE, Level.DEBUG, Level.INFO}; - static final String SONAR_LOG_LEVEL_PROPERTY = "sonar.log.level"; - static final String ROLLING_POLICY_PROPERTY = "sonar.log.rollingPolicy"; - static final String MAX_FILES_PROPERTY = "sonar.log.maxFiles"; private static final String PROCESS_NAME_PLACEHOLDER = "XXXX"; private static final String THREAD_ID_PLACEHOLDER = "ZZZZ"; diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java b/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java index fe5e7f9845b..d7dde9b2974 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java @@ -28,10 +28,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang.StringUtils; import org.sonar.process.MessageException; +import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import static java.lang.String.format; import static java.lang.String.valueOf; +import static org.sonar.process.ProcessProperties.Property.LOG_LEVEL; +import static org.sonar.process.ProcessProperties.Property.LOG_MAX_FILES; +import static org.sonar.process.ProcessProperties.Property.LOG_ROLLING_POLICY; public class Log4JPropertiesBuilder extends AbstractLogHelper { private static final String ROOT_LOGGER_NAME = "rootLogger"; @@ -70,8 +74,8 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper { * <p> * <ul> * <li>the file's name will use the prefix defined in {@link RootLoggerConfig#getProcessId()#getLogFilenamePrefix()}.</li> - * <li>the file will follow the rotation policy defined in property {@link #ROLLING_POLICY_PROPERTY} and - * the max number of files defined in property {@link #MAX_FILES_PROPERTY}</li> + * <li>the file will follow the rotation policy defined in property {@link ProcessProperties.Property#LOG_ROLLING_POLICY} and + * the max number of files defined in property {@link org.sonar.process.ProcessProperties.Property#LOG_MAX_FILES}</li> * <li>the logs will follow the specified log pattern</li> * </ul> * </p> @@ -106,8 +110,8 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper { } private RollingPolicy createRollingPolicy(File logDir, String filenamePrefix) { - String rollingPolicy = props.value(ROLLING_POLICY_PROPERTY, "time:yyyy-MM-dd"); - int maxFiles = props.valueAsInt(MAX_FILES_PROPERTY, 7); + String rollingPolicy = props.value(LOG_ROLLING_POLICY.getKey(), "time:yyyy-MM-dd"); + int maxFiles = props.valueAsInt(LOG_MAX_FILES.getKey(), 7); if (maxFiles <= 0) { maxFiles = UNLIMITED_MAX_FILES; } @@ -119,7 +123,7 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper { } else if ("none".equals(rollingPolicy)) { return new NoRollingPolicy(filenamePrefix, logDir); } else { - throw new MessageException(format("Unsupported value for property %s: %s", ROLLING_POLICY_PROPERTY, rollingPolicy)); + throw new MessageException(format("Unsupported value for property %s: %s", LOG_ROLLING_POLICY.getKey(), rollingPolicy)); } } @@ -128,7 +132,7 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper { throw new IllegalArgumentException("Value of LogLevelConfig#rootLoggerName must be \"" + ROOT_LOGGER_NAME + "\""); } - Level propertyValueAsLevel = getPropertyValueAsLevel(props, SONAR_LOG_LEVEL_PROPERTY); + Level propertyValueAsLevel = getPropertyValueAsLevel(props, LOG_LEVEL.getKey()); boolean traceGloballyEnabled = propertyValueAsLevel == Level.TRACE; List<String> loggerNames = Stream.of( diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/LogLevelConfig.java b/server/sonar-process/src/main/java/org/sonar/process/logging/LogLevelConfig.java index 8e508f8fd06..c130f06cc2f 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/LogLevelConfig.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/LogLevelConfig.java @@ -32,11 +32,12 @@ import java.util.stream.Stream; import org.sonar.process.ProcessId; import static java.util.Objects.requireNonNull; +import static org.sonar.process.ProcessProperties.Property.LOG_LEVEL; public final class LogLevelConfig { - private static final String SONAR_LOG_LEVEL_PROPERTY = "sonar.log.level"; + private static final String SONAR_LOG_LEVEL_PROPERTY = LOG_LEVEL.getKey(); private static final String PROCESS_NAME_PLACEHOLDER = "XXXX"; - private static final String SONAR_PROCESS_LOG_LEVEL_PROPERTY = "sonar.log.level." + PROCESS_NAME_PLACEHOLDER; + private static final String SONAR_PROCESS_LOG_LEVEL_PROPERTY = SONAR_LOG_LEVEL_PROPERTY + "." + PROCESS_NAME_PLACEHOLDER; private final Map<String, List<String>> configuredByProperties; private final Map<String, Level> configuredByHardcodedLevel; diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java b/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java index 785730b78ac..85bb1a40779 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java @@ -47,10 +47,15 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.LoggerFactory; import org.slf4j.bridge.SLF4JBridgeHandler; import org.sonar.process.MessageException; +import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import static java.lang.String.format; import static org.slf4j.Logger.ROOT_LOGGER_NAME; +import static org.sonar.process.ProcessProperties.Property.LOG_CONSOLE; +import static org.sonar.process.ProcessProperties.Property.LOG_LEVEL; +import static org.sonar.process.ProcessProperties.Property.LOG_MAX_FILES; +import static org.sonar.process.ProcessProperties.Property.LOG_ROLLING_POLICY; import static org.sonar.process.ProcessProperties.Property.PATH_LOGS; /** @@ -58,7 +63,6 @@ import static org.sonar.process.ProcessProperties.Property.PATH_LOGS; */ public class LogbackHelper extends AbstractLogHelper { - private static final String ALL_LOGS_TO_CONSOLE_PROPERTY = "sonar.log.console"; private static final String LOGBACK_LOGGER_NAME_PATTERN = "%logger{20}"; public LogbackHelper() { @@ -118,7 +122,7 @@ public class LogbackHelper extends AbstractLogHelper { LoggerContext rootContext = getRootContext(); logLevelConfig.getConfiguredByProperties().forEach((key, value) -> applyLevelByProperty(props, rootContext.getLogger(key), value)); logLevelConfig.getConfiguredByHardcodedLevel().forEach((key, value) -> applyHardcodedLevel(rootContext, key, value)); - Level propertyValueAsLevel = getPropertyValueAsLevel(props, SONAR_LOG_LEVEL_PROPERTY); + Level propertyValueAsLevel = getPropertyValueAsLevel(props, LOG_LEVEL.getKey()); boolean traceGloballyEnabled = propertyValueAsLevel == Level.TRACE; logLevelConfig.getOffUnlessTrace().forEach(logger -> applyHardUnlessTrace(rootContext, logger, traceGloballyEnabled)); return rootContext; @@ -169,8 +173,8 @@ public class LogbackHelper extends AbstractLogHelper { * <p> * <ul> * <li>the file's name will use the prefix defined in {@link RootLoggerConfig#getProcessId()#getLogFilenamePrefix()}.</li> - * <li>the file will follow the rotation policy defined in property {@link #ROLLING_POLICY_PROPERTY} and - * the max number of files defined in property {@link #MAX_FILES_PROPERTY}</li> + * <li>the file will follow the rotation policy defined in property {@link ProcessProperties.Property#LOG_ROLLING_POLICY} and + * the max number of files defined in property {@link org.sonar.process.ProcessProperties.Property#LOG_MAX_FILES}</li> * <li>the logs will follow the specified log encoder</li> * </ul> * </p> @@ -204,10 +208,10 @@ public class LogbackHelper extends AbstractLogHelper { /** * Finds out whether we are in testing environment (usually ITs) and logs of all processes must be forward to - * App's System.out. This is specified by the value of property {@link #ALL_LOGS_TO_CONSOLE_PROPERTY}. + * App's System.out. This is specified by the value of property {@link ProcessProperties.Property#LOG_CONSOLE}. */ public boolean isAllLogsToConsoleEnabled(Props props) { - return props.valueAsBoolean(ALL_LOGS_TO_CONSOLE_PROPERTY, false); + return props.valueAsBoolean(LOG_CONSOLE.getKey(), false); } public Level getLoggerLevel(String loggerName) { @@ -241,8 +245,8 @@ public class LogbackHelper extends AbstractLogHelper { } public RollingPolicy createRollingPolicy(Context ctx, Props props, String filenamePrefix) { - String rollingPolicy = props.value(ROLLING_POLICY_PROPERTY, "time:yyyy-MM-dd"); - int maxFiles = props.valueAsInt(MAX_FILES_PROPERTY, 7); + String rollingPolicy = props.value(LOG_ROLLING_POLICY.getKey(), "time:yyyy-MM-dd"); + int maxFiles = props.valueAsInt(LOG_MAX_FILES.getKey(), 7); File logsDir = props.nonNullValueAsFile(PATH_LOGS.getKey()); if (rollingPolicy.startsWith("time:")) { @@ -255,7 +259,7 @@ public class LogbackHelper extends AbstractLogHelper { return new NoRollingPolicy(ctx, filenamePrefix, logsDir, maxFiles); } else { - throw new MessageException(format("Unsupported value for property %s: %s", ROLLING_POLICY_PROPERTY, rollingPolicy)); + throw new MessageException(format("Unsupported value for property %s: %s", LOG_ROLLING_POLICY.getKey(), rollingPolicy)); } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java b/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java index 5f6abff54c6..6603260c9ad 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java @@ -502,7 +502,7 @@ public class LogbackHelperTest { assertThat(encoder).isInstanceOf(LayoutWrappingEncoder.class); Layout layout = ((LayoutWrappingEncoder) encoder).getLayout(); assertThat(layout).isInstanceOf(LogbackJsonLayout.class); - assertThat(((LogbackJsonLayout)layout).getProcessKey()).isEqualTo("web"); + assertThat(((LogbackJsonLayout) layout).getProcessKey()).isEqualTo("web"); } private LogLevelConfig.Builder newLogLevelConfig() { @@ -531,6 +531,25 @@ public class LogbackHelperTest { }; } + @Test + public void log_to_console_setting_missing() { + assertThat(underTest.isAllLogsToConsoleEnabled(new Props(new Properties()))).isFalse(); + } + + @Test + public void log_to_console_setting_enabled() { + Properties properties = new Properties(); + properties.setProperty("sonar.log.console", "true"); + assertThat(underTest.isAllLogsToConsoleEnabled(new Props(properties))).isTrue(); + } + + @Test + public void log_to_console_setting_disabled() { + Properties properties = new Properties(); + properties.setProperty("sonar.log.console", "false"); + assertThat(underTest.isAllLogsToConsoleEnabled(new Props(properties))).isFalse(); + } + public static class MemoryAppender extends AppenderBase<ILoggingEvent> { private static final List<ILoggingEvent> LOGS = new ArrayList<>(); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/platform/UrlSettings.java b/server/sonar-server-common/src/main/java/org/sonar/server/platform/UrlSettings.java index 559c251bc36..efd7254f7e1 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/platform/UrlSettings.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/platform/UrlSettings.java @@ -27,12 +27,12 @@ import org.sonar.api.server.ServerSide; import static org.apache.commons.lang.StringUtils.isEmpty; import static org.apache.commons.lang.StringUtils.isNotEmpty; import static org.sonar.api.CoreProperties.SERVER_BASE_URL; +import static org.sonar.process.ProcessProperties.Property.WEB_CONTEXT; +import static org.sonar.process.ProcessProperties.Property.WEB_HOST; @ComputeEngineSide @ServerSide public class UrlSettings { - private static final String PROPERTY_CONTEXT = "sonar.web.context"; - private static final int DEFAULT_PORT = 9000; private static final int DEFAULT_HTTP_PORT = 80; private static final String ALL_IPS_HOST = "0.0.0.0"; @@ -43,7 +43,7 @@ public class UrlSettings { public UrlSettings(Configuration config) { this.config = config; - this.contextPath = config.get(PROPERTY_CONTEXT).orElse("") + this.contextPath = config.get(WEB_CONTEXT.getKey()).orElse("") // Remove trailing slashes .replaceFirst("(\\/+)$", ""); } @@ -66,9 +66,9 @@ public class UrlSettings { } private String computeBaseUrl() { - String host = config.get("sonar.web.host").orElse(""); + String host = config.get(WEB_HOST.getKey()).orElse(""); int port = config.getInt("sonar.web.port").orElse(0); - String context = config.get(PROPERTY_CONTEXT).orElse(""); + String context = config.get(WEB_CONTEXT.getKey()).orElse(""); StringBuilder res = new StringBuilder(); res.append("http://"); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/setting/ThreadLocalSettings.java b/server/sonar-server-common/src/main/java/org/sonar/server/setting/ThreadLocalSettings.java index 74c7affdf53..0b55727ce58 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/setting/ThreadLocalSettings.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/setting/ThreadLocalSettings.java @@ -20,25 +20,19 @@ package org.sonar.server.setting; import com.google.common.annotations.VisibleForTesting; -import java.util.AbstractMap; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Properties; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.ibatis.exceptions.PersistenceException; import org.sonar.api.CoreProperties; import org.sonar.api.ce.ComputeEngineSide; -import org.sonar.api.config.internal.Encryption; -import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.internal.Encryption; import org.sonar.api.config.internal.Settings; import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.System2; -import org.sonar.core.util.SettingFormatter; import static java.util.Collections.unmodifiableMap; import static java.util.Objects.requireNonNull; @@ -61,24 +55,19 @@ import static java.util.Objects.requireNonNull; @ServerSide public class ThreadLocalSettings extends Settings { private final Properties systemProps = new Properties(); - private final Properties corePropsFromEnvVariables = new Properties(); private static final ThreadLocal<Map<String, String>> CACHE = new ThreadLocal<>(); private Map<String, String> getPropertyDbFailureCache = Collections.emptyMap(); private Map<String, String> getPropertiesDbFailureCache = Collections.emptyMap(); private SettingLoader settingLoader; - private System2 system2; - public ThreadLocalSettings(System2 system2, PropertyDefinitions definitions, Properties props) { - this(system2, definitions, props, new NopSettingLoader()); + public ThreadLocalSettings(PropertyDefinitions definitions, Properties props) { + this(definitions, props, new NopSettingLoader()); } @VisibleForTesting - ThreadLocalSettings(System2 system2, PropertyDefinitions definitions, Properties props, SettingLoader settingLoader) { + ThreadLocalSettings(PropertyDefinitions definitions, Properties props, SettingLoader settingLoader) { super(definitions, new Encryption(null)); - this.system2 = system2; this.settingLoader = settingLoader; - - resolveCorePropertiesFromEnvironment(); props.forEach((k, v) -> systemProps.put(k, v == null ? null : v.toString().trim())); // TODO something wrong about lifecycle here. It could be improved @@ -107,9 +96,9 @@ public class ThreadLocalSettings extends Settings { return Optional.of(value); } - value = corePropsFromEnvVariables.getProperty(key); - if (value != null) { - return Optional.of(value); + Optional<String> envVal = getDefinitions().getValueFromEnv(key); + if (envVal.isPresent()) { + return envVal; } Map<String, String> dbProps = CACHE.get(); @@ -183,7 +172,7 @@ public class ThreadLocalSettings extends Settings { public Map<String, String> getProperties() { Map<String, String> result = new HashMap<>(); loadAll(result); - corePropsFromEnvVariables.forEach((k, v) -> result.put((String) k, (String) v)); + getDefinitions().getAllPropertiesSetInEnv().forEach(result::put); systemProps.forEach((key, value) -> result.put((String) key, (String) value)); return unmodifiableMap(result); } @@ -197,20 +186,4 @@ public class ThreadLocalSettings extends Settings { appendTo.putAll(getPropertiesDbFailureCache); } } - - private void resolveCorePropertiesFromEnvironment() { - corePropsFromEnvVariables.putAll(this.getDefinitions().getAll() - .stream() - .map(PropertyDefinition::key) - .flatMap(p -> { - String envVar = SettingFormatter.fromJavaPropertyToEnvVariable(p); - String envVarValue = system2.envVariable(envVar); - if (envVarValue != null) { - return Stream.of(new AbstractMap.SimpleEntry<>(p, envVarValue)); - } else { - return Stream.empty(); - } - }) - .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue))); - } } diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/config/ConfigurationProviderTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/config/ConfigurationProviderTest.java index 833f447f52d..29957eaa22d 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/config/ConfigurationProviderTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/config/ConfigurationProviderTest.java @@ -28,6 +28,7 @@ import org.junit.runner.RunWith; import org.sonar.api.config.Configuration; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.api.config.PropertyDefinition.builder; @@ -38,7 +39,7 @@ public class ConfigurationProviderTest { private final String nonDeclaredKey = RandomStringUtils.randomAlphabetic(3); private final String nonMultivalueKey = RandomStringUtils.randomAlphabetic(3); private final String multivalueKey = RandomStringUtils.randomAlphabetic(3); - private final MapSettings settings = new MapSettings(new PropertyDefinitions( + private final MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, builder(nonMultivalueKey).multiValues(false).build(), builder(multivalueKey).multiValues(true).build())); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/platform/UrlSettingsTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/platform/UrlSettingsTest.java index 1a2c451d633..ea842bc515b 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/platform/UrlSettingsTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/platform/UrlSettingsTest.java @@ -24,6 +24,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import org.sonar.core.config.CorePropertyDefinitions; import static org.assertj.core.api.Assertions.assertThat; @@ -38,7 +39,7 @@ public class UrlSettingsTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - private MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all())); + private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all())); @Test public void use_default_context_path() { diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/setting/ChildSettingsTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/setting/ChildSettingsTest.java index 2964925628e..4e2858e70dd 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/setting/ChildSettingsTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/setting/ChildSettingsTest.java @@ -29,6 +29,7 @@ import org.junit.rules.ExpectedException; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Assertions.assertThat; @@ -46,7 +47,7 @@ public class ChildSettingsTest { public void childSettings_should_retrieve_parent_settings() { String multipleValuesKey = randomAlphanumeric(19); PropertyDefinition multipleValues = PropertyDefinition.builder(multipleValuesKey).multiValues(true).build(); - MapSettings parent = new MapSettings(new PropertyDefinitions(Collections.singletonList(multipleValues))); + MapSettings parent = new MapSettings(new PropertyDefinitions(System2.INSTANCE, Collections.singletonList(multipleValues))); ChildSettings underTest = new ChildSettings(parent); parent.setProperty(randomAlphanumeric(10), randomAlphanumeric(20)); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java index 90624314c4a..859c0ae4c20 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java @@ -33,6 +33,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.sonar.api.Property; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.utils.System2; import org.sonar.core.config.CorePropertyDefinitions; @@ -70,7 +71,7 @@ public class ThreadLocalSettingsTest { @Test public void can_not_add_property_if_no_cache() { - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); underTest.set("foo", "wiz"); @@ -79,7 +80,7 @@ public class ThreadLocalSettingsTest { @Test public void can_not_remove_system_property_if_no_cache() { - underTest = create(ImmutableMap.of("foo", "bar")); + underTest = create(system, ImmutableMap.of("foo", "bar")); underTest.remove("foo"); @@ -88,7 +89,7 @@ public class ThreadLocalSettingsTest { @Test public void add_property_to_cache() { - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); underTest.load(); underTest.set("foo", "bar"); @@ -101,7 +102,7 @@ public class ThreadLocalSettingsTest { @Test public void remove_property_from_cache() { - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); underTest.load(); underTest.set("foo", "bar"); @@ -120,7 +121,7 @@ public class ThreadLocalSettingsTest { @Test public void getProperties_does_not_fail_on_duplicated_key() { insertPropertyIntoDb("foo", "from_db"); - underTest = create(ImmutableMap.of("foo", "from_system")); + underTest = create(system, ImmutableMap.of("foo", "from_system")); assertThat(underTest.get("foo")).hasValue("from_system"); assertThat(underTest.getProperties().get("foo")).isEqualTo("from_system"); @@ -130,27 +131,31 @@ public class ThreadLocalSettingsTest { public void load_encryption_secret_key_from_system_properties() throws Exception { File secretKey = temp.newFile(); - underTest = create(ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", secretKey.getAbsolutePath())); + underTest = create(system, ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", secretKey.getAbsolutePath())); assertThat(underTest.getEncryption().hasSecretKey()).isTrue(); } @Test public void encryption_secret_key_is_undefined_by_default() { - underTest = create(ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", "unknown/path/to/sonar-secret.txt")); + underTest = create(system, ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", "unknown/path/to/sonar-secret.txt")); assertThat(underTest.getEncryption().hasSecretKey()).isFalse(); } - private ThreadLocalSettings create(Map<String, String> systemProps) { + private ThreadLocalSettings create(System2 system, Map<String, String> systemProps) { + PropertyDefinitions definitions = new PropertyDefinitions(system); + definitions.addComponents(CorePropertyDefinitions.all()); + definitions.addComponent(new AnnotatedTestClass()); + Properties p = new Properties(); p.putAll(systemProps); - return new ThreadLocalSettings(system, new PropertyDefinitions(CorePropertyDefinitions.all()), p, dbSettingLoader); + return new ThreadLocalSettings(definitions, p, dbSettingLoader); } @Test public void load_system_properties() { - underTest = create(ImmutableMap.of("foo", "1", "bar", "2")); + underTest = create(system, ImmutableMap.of("foo", "1", "bar", "2")); assertThat(underTest.get("foo")).hasValue("1"); assertThat(underTest.get("missing")).isNotPresent(); @@ -160,17 +165,19 @@ public class ThreadLocalSettingsTest { @Test public void load_core_properties_from_environment() { when(system.envVariable("SONAR_FORCEAUTHENTICATION")).thenReturn("true"); - underTest = create(ImmutableMap.of()); + when(system.envVariable("SONAR_ANNOTATION_TEST_PROP")).thenReturn("113"); + underTest = create(system, ImmutableMap.of()); assertThat(underTest.get("sonar.forceAuthentication")).hasValue("true"); + assertThat(underTest.get("sonar.annotation.test.prop")).hasValue("113"); assertThat(underTest.get("missing")).isNotPresent(); - assertThat(underTest.getProperties()).containsOnly(entry("sonar.forceAuthentication", "true")); + assertThat(underTest.getProperties()).containsOnly(entry("sonar.forceAuthentication", "true"), entry("sonar.annotation.test.prop", "113")); } @Test public void database_properties_are_not_cached_by_default() { insertPropertyIntoDb("foo", "from db"); - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); assertThat(underTest.get("foo")).hasValue("from db"); @@ -182,7 +189,7 @@ public class ThreadLocalSettingsTest { @Test public void system_settings_have_precedence_over_database() { insertPropertyIntoDb("foo", "from db"); - underTest = create(ImmutableMap.of("foo", "from system")); + underTest = create(system, ImmutableMap.of("foo", "from system")); assertThat(underTest.get("foo")).hasValue("from system"); } @@ -191,7 +198,7 @@ public class ThreadLocalSettingsTest { public void getProperties_are_all_properties_with_value() { insertPropertyIntoDb("db", "from db"); insertPropertyIntoDb("empty", ""); - underTest = create(ImmutableMap.of("system", "from system")); + underTest = create(system, ImmutableMap.of("system", "from system")); assertThat(underTest.getProperties()).containsOnly(entry("system", "from system"), entry("db", "from db"), entry("empty", "")); } @@ -199,7 +206,7 @@ public class ThreadLocalSettingsTest { @Test public void getProperties_is_not_cached_in_thread_cache() { insertPropertyIntoDb("foo", "bar"); - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); underTest.load(); assertThat(underTest.getProperties()) @@ -219,7 +226,7 @@ public class ThreadLocalSettingsTest { public void load_creates_a_thread_specific_cache() throws InterruptedException { insertPropertyIntoDb(A_KEY, "v1"); - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); underTest.load(); assertThat(underTest.get(A_KEY)).hasValue("v1"); @@ -239,7 +246,7 @@ public class ThreadLocalSettingsTest { @Test public void load_invalidates_cache_if_unload_has_not_been_called() { - underTest = create(emptyMap()); + underTest = create(system, emptyMap()); underTest.load(); underTest.set("foo", "bar"); // unload() is not called @@ -250,7 +257,7 @@ public class ThreadLocalSettingsTest { @Test public void keep_in_thread_cache_the_fact_that_a_property_is_not_in_db() { - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); underTest.load(); assertThat(underTest.get(A_KEY)).isNotPresent(); @@ -263,7 +270,7 @@ public class ThreadLocalSettingsTest { @Test public void change_setting_loader() { - underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties()); + underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties()); assertThat(underTest.getSettingLoader()).isNotNull(); @@ -274,7 +281,7 @@ public class ThreadLocalSettingsTest { @Test public void cache_db_calls_if_property_is_not_persisted() { - underTest = create(Collections.emptyMap()); + underTest = create(system, Collections.emptyMap()); underTest.load(); assertThat(underTest.get(A_KEY)).isNotPresent(); assertThat(underTest.get(A_KEY)).isNotPresent(); @@ -286,7 +293,7 @@ public class ThreadLocalSettingsTest { SettingLoader settingLoaderMock = mock(SettingLoader.class); PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB"); doThrow(toBeThrown).when(settingLoaderMock).loadAll(); - underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock); + underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock); assertThat(underTest.getProperties()) .isEmpty(); @@ -297,7 +304,7 @@ public class ThreadLocalSettingsTest { SettingLoader settingLoaderMock = mock(SettingLoader.class); PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB"); doThrow(toBeThrown).when(settingLoaderMock).loadAll(); - underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock); + underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock); underTest.load(); assertThat(underTest.getProperties()) @@ -316,7 +323,7 @@ public class ThreadLocalSettingsTest { .doAnswer(invocationOnMock -> ImmutableMap.of(key, value2)) .when(settingLoaderMock) .loadAll(); - underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock); + underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock); underTest.load(); assertThat(underTest.getProperties()) @@ -340,7 +347,7 @@ public class ThreadLocalSettingsTest { PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB"); String key = randomAlphanumeric(3); doThrow(toBeThrown).when(settingLoaderMock).load(key); - underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock); + underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock); assertThat(underTest.get(key)).isEmpty(); } @@ -351,7 +358,7 @@ public class ThreadLocalSettingsTest { PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB"); String key = randomAlphanumeric(3); doThrow(toBeThrown).when(settingLoaderMock).load(key); - underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock); + underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock); underTest.load(); assertThat(underTest.get(key)).isEmpty(); @@ -417,4 +424,14 @@ public class ThreadLocalSettingsTest { return unmodifiableMap(map); } } + + @org.sonar.api.Properties({ + @Property( + key = "sonar.annotation.test.prop", + defaultValue = "60", + name = "Test annotation property", + global = false) + }) + class AnnotatedTestClass { + } } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java index 9c9eb212450..a46245a0ab0 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java @@ -40,13 +40,12 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; import static org.apache.commons.lang.StringUtils.isEmpty; import static org.apache.commons.lang.time.DateUtils.addSeconds; +import static org.sonar.process.ProcessProperties.Property.WEB_SESSION_TIMEOUT_IN_MIN; import static org.sonar.server.authentication.Cookies.findCookie; import static org.sonar.server.authentication.Cookies.newCookieBuilder; @ServerSide public class JwtHttpHandler { - - private static final String SESSION_TIMEOUT_IN_MINUTES_PROPERTY = "sonar.web.sessionTimeoutInMinutes"; private static final int SESSION_TIMEOUT_DEFAULT_VALUE_IN_MINUTES = 3 * 24 * 60; private static final int MAX_SESSION_TIMEOUT_IN_MINUTES = 3 * 30 * 24 * 60; @@ -175,10 +174,11 @@ public class JwtHttpHandler { } private static int getSessionTimeoutInSeconds(Configuration config) { - int minutes = config.getInt(SESSION_TIMEOUT_IN_MINUTES_PROPERTY).orElse(SESSION_TIMEOUT_DEFAULT_VALUE_IN_MINUTES); - checkArgument(minutes > 0, "Property %s must be strictly positive. Got %s", SESSION_TIMEOUT_IN_MINUTES_PROPERTY, minutes); - checkArgument(minutes <= MAX_SESSION_TIMEOUT_IN_MINUTES, "Property %s must not be greater than 3 months (%s minutes). Got %s minutes", - SESSION_TIMEOUT_IN_MINUTES_PROPERTY, MAX_SESSION_TIMEOUT_IN_MINUTES, minutes); + int minutes = config.getInt(WEB_SESSION_TIMEOUT_IN_MIN.getKey()).orElse(SESSION_TIMEOUT_DEFAULT_VALUE_IN_MINUTES); + checkArgument(minutes > 0, "Property %s must be strictly positive. Got %s", WEB_SESSION_TIMEOUT_IN_MIN.getKey(), minutes); + checkArgument(minutes <= MAX_SESSION_TIMEOUT_IN_MINUTES, + "Property %s must not be greater than 3 months (%s minutes). Got %s minutes", WEB_SESSION_TIMEOUT_IN_MIN.getKey(), + MAX_SESSION_TIMEOUT_IN_MINUTES, minutes); return minutes * 60; } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java index 43c4551e4e5..8511de7a7ac 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java @@ -27,11 +27,12 @@ import org.sonar.api.server.ServerSide; import org.sonar.api.server.ws.Request; import org.sonar.api.utils.log.Loggers; +import static org.sonar.process.ProcessProperties.Property.WEB_SYSTEM_PASS_CODE; + @ServerSide public class SystemPasscodeImpl implements SystemPasscode, Startable { public static final String PASSCODE_HTTP_HEADER = "X-Sonar-Passcode"; - public static final String PASSCODE_CONF_PROPERTY = "sonar.web.systemPasscode"; private final Configuration configuration; private String configuredPasscode; @@ -52,7 +53,7 @@ public class SystemPasscodeImpl implements SystemPasscode, Startable { @Override public void start() { - Optional<String> passcodeOpt = configuration.get(PASSCODE_CONF_PROPERTY) + Optional<String> passcodeOpt = configuration.get(WEB_SYSTEM_PASS_CODE.getKey()) // if present, result is never empty string .map(StringUtils::trimToNull); diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java index 8eca155c47d..79486378771 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java @@ -28,6 +28,7 @@ import org.mockito.verification.Timeout; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.notifications.Notification; +import org.sonar.api.utils.System2; import static java.util.Collections.singleton; import static org.mockito.ArgumentMatchers.anyCollection; @@ -43,7 +44,7 @@ public class NotificationDaemonTest { @Before public void setUp() { - MapSettings settings = new MapSettings(new PropertyDefinitions(NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L); + MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L); underTest = new NotificationDaemon(settings.asConfig(), manager, notificationService); inOrder = Mockito.inOrder(notificationService); diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationMediumTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationMediumTest.java index fb8b5001af5..39a67cee288 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationMediumTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationMediumTest.java @@ -23,10 +23,11 @@ import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.sonar.api.config.PropertyDefinitions; -import org.sonar.api.config.internal.Settings; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.config.internal.Settings; import org.sonar.api.notifications.Notification; import org.sonar.api.notifications.NotificationChannel; +import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import static org.assertj.core.api.Assertions.assertThat; @@ -68,7 +69,7 @@ public class NotificationMediumTest { when(qualityGateChange.getType()).thenReturn("qgate-changes"); when(manager.getFromQueue()).thenReturn(notification).thenReturn(null); - MapSettings settings = new MapSettings(new PropertyDefinitions(NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L); + MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L); underTest = new NotificationDaemon(settings.asConfig(), manager, service); } diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/SettingsSectionTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/SettingsSectionTest.java index 3790efa3c01..b9f9252341b 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/SettingsSectionTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/SettingsSectionTest.java @@ -23,8 +23,9 @@ import org.junit.Test; import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; -import org.sonar.api.config.internal.Settings; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.config.internal.Settings; +import org.sonar.api.utils.System2; import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import static org.apache.commons.lang.StringUtils.repeat; @@ -36,7 +37,7 @@ public class SettingsSectionTest { private static final String PASSWORD_PROPERTY = "sonar.password"; - private PropertyDefinitions defs = new PropertyDefinitions(PropertyDefinition.builder(PASSWORD_PROPERTY).type(PropertyType.PASSWORD).build()); + private PropertyDefinitions defs = new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder(PASSWORD_PROPERTY).type(PropertyType.PASSWORD).build()); private Settings settings = new MapSettings(defs); private SettingsSection underTest = new SettingsSection(settings); diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/startup/RenameDeprecatedPropertyKeysTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/startup/RenameDeprecatedPropertyKeysTest.java index fd68ea0a0c3..5ed9547504a 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/startup/RenameDeprecatedPropertyKeysTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/startup/RenameDeprecatedPropertyKeysTest.java @@ -23,15 +23,18 @@ import org.junit.Test; import org.sonar.api.Properties; import org.sonar.api.Property; import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.utils.System2; import org.sonar.db.property.PropertiesDao; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; public class RenameDeprecatedPropertyKeysTest { @Test public void should_rename_deprecated_keys() { PropertiesDao dao = mock(PropertiesDao.class); - PropertyDefinitions definitions = new PropertyDefinitions(FakeExtension.class); + PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE, FakeExtension.class); RenameDeprecatedPropertyKeys task = new RenameDeprecatedPropertyKeys(dao, definitions); task.start(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/InfoAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/InfoAction.java index 04867d6b08c..532698f1479 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/InfoAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/InfoAction.java @@ -23,9 +23,9 @@ import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.ce.queue.CeQueue; +import org.sonar.process.ProcessProperties; import org.sonar.server.user.AbstractUserSession; import org.sonar.server.user.SystemPasscode; -import org.sonar.server.user.SystemPasscodeImpl; import org.sonar.server.user.UserSession; import org.sonar.server.ws.WsUtils; import org.sonarqube.ws.Ce; @@ -46,7 +46,7 @@ public class InfoAction implements CeWsAction { public void define(WebService.NewController controller) { controller.createAction("info") .setDescription("Gets information about Compute Engine. Requires the system administration permission or " + - "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).") + "system passcode (see " + ProcessProperties.Property.WEB_SYSTEM_PASS_CODE + " in sonar.properties).") .setSince("7.2") .setInternal(true) .setHandler(this) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/PauseAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/PauseAction.java index 66ea01bebbc..22d1ceb1852 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/PauseAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/PauseAction.java @@ -23,9 +23,9 @@ import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.ce.queue.CeQueue; +import org.sonar.process.ProcessProperties; import org.sonar.server.user.AbstractUserSession; import org.sonar.server.user.SystemPasscode; -import org.sonar.server.user.SystemPasscodeImpl; import org.sonar.server.user.UserSession; public class PauseAction implements CeWsAction { @@ -44,7 +44,7 @@ public class PauseAction implements CeWsAction { public void define(WebService.NewController controller) { controller.createAction("pause") .setDescription("Requests pause of Compute Engine workers. Requires the system administration permission or " + - "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).") + "system passcode (see " + ProcessProperties.Property.WEB_SYSTEM_PASS_CODE + " in sonar.properties).") .setSince("7.2") .setInternal(true) .setHandler(this) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/ResumeAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/ResumeAction.java index 41955dcd95b..0599e9ab03b 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/ResumeAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/ResumeAction.java @@ -23,9 +23,9 @@ import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.ce.queue.CeQueue; +import org.sonar.process.ProcessProperties; import org.sonar.server.user.AbstractUserSession; import org.sonar.server.user.SystemPasscode; -import org.sonar.server.user.SystemPasscodeImpl; import org.sonar.server.user.UserSession; public class ResumeAction implements CeWsAction { @@ -44,7 +44,7 @@ public class ResumeAction implements CeWsAction { public void define(WebService.NewController controller) { controller.createAction("resume") .setDescription("Resumes pause of Compute Engine workers. Requires the system administration permission or " + - "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).") + "system passcode (see " + ProcessProperties.Property.WEB_SYSTEM_PASS_CODE + " in sonar.properties).") .setSince("7.2") .setInternal(true) .setHandler(this) diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java index 9a64112913c..29a13e09864 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java @@ -39,6 +39,7 @@ import org.sonar.api.config.internal.MapSettings; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Qualifiers; +import org.sonar.api.utils.System2; import org.sonar.core.config.CorePropertyDefinitions; import org.sonar.db.DbSession; import org.sonar.db.DbTester; @@ -399,7 +400,7 @@ public class LiveMeasureComputerImplTest { when(qGateComputer.getMetricsRelatedTo(qualityGate)).thenReturn(singleton(CoreMetrics.ALERT_STATUS_KEY)); when(qGateComputer.refreshGateStatus(eq(project), same(qualityGate), any(MeasureMatrix.class))) .thenReturn(newQualityGate); - MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all())); + MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all())); ProjectConfigurationLoader configurationLoader = new TestProjectConfigurationLoader(settings.asConfig()); LiveMeasureComputerImpl underTest = new LiveMeasureComputerImpl(db.getDbClient(), formulaFactory, qGateComputer, configurationLoader, projectIndexer); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ListDefinitionsActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ListDefinitionsActionTest.java index 841248d8618..e724e52cd72 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ListDefinitionsActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ListDefinitionsActionTest.java @@ -85,7 +85,7 @@ public class ListDefinitionsActionTest { private DbClient dbClient = db.getDbClient(); private ComponentDbTester componentDb = new ComponentDbTester(db); private ComponentDto project; - private PropertyDefinitions propertyDefinitions = new PropertyDefinitions(); + private PropertyDefinitions propertyDefinitions = new PropertyDefinitions(System2.INSTANCE); private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); private SettingsWsSupport support = new SettingsWsSupport(defaultOrganizationProvider, userSession); private WsActionTester ws = new WsActionTester( diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ResetActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ResetActionTest.java index f44cebed3f9..6fc1b274231 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ResetActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ResetActionTest.java @@ -81,7 +81,7 @@ public class ResetActionTest { private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); private ComponentFinder componentFinder = TestComponentFinder.from(db); - private PropertyDefinitions definitions = new PropertyDefinitions(); + private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions); private SettingValidations settingValidations = new SettingValidations(definitions, dbClient, i18n); private ComponentDto project; diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java index c25c8bb11d2..734869d66f9 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java @@ -91,7 +91,7 @@ public class SetActionTest { private ComponentFinder componentFinder = TestComponentFinder.from(db); private I18nRule i18n = new I18nRule(); - private PropertyDefinitions definitions = new PropertyDefinitions(); + private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private FakeSettingsNotifier settingsChangeNotifier = new FakeSettingsNotifier(dbClient); private SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions); private SettingValidations validations = new SettingValidations(definitions, dbClient, i18n); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsUpdaterTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsUpdaterTest.java index bf12663030e..f41c559f670 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsUpdaterTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsUpdaterTest.java @@ -59,7 +59,7 @@ public class SettingsUpdaterTest { PropertyDbTester propertyDb = new PropertyDbTester(db); ComponentDbTester componentDb = new ComponentDbTester(db); - PropertyDefinitions definitions = new PropertyDefinitions(); + PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); ComponentDto project; SettingsUpdater underTest= new SettingsUpdater(dbClient, definitions); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java index 48f8a7a73f3..efb439b13d2 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java @@ -89,7 +89,7 @@ public class ValuesActionTest { private DbClient dbClient = db.getDbClient(); private PropertyDbTester propertyDb = new PropertyDbTester(db); private ComponentDbTester componentDb = new ComponentDbTester(db); - private PropertyDefinitions definitions = new PropertyDefinitions(); + private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); private SettingsWsSupport support = new SettingsWsSupport(defaultOrganizationProvider, userSession); private ComponentDto project; diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatConnectors.java b/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatConnectors.java index 5a43767f460..dc55d7bbd9c 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatConnectors.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatConnectors.java @@ -25,6 +25,10 @@ import org.apache.catalina.startup.Tomcat; import org.sonar.process.Props; import static java.lang.String.format; +import static org.sonar.process.ProcessProperties.Property.WEB_HOST; +import static org.sonar.process.ProcessProperties.Property.WEB_HTTP_ACCEPT_COUNT; +import static org.sonar.process.ProcessProperties.Property.WEB_HTTP_MAX_THREADS; +import static org.sonar.process.ProcessProperties.Property.WEB_HTTP_MIN_THREADS; /** * Configuration of Tomcat connectors @@ -53,7 +57,7 @@ class TomcatConnectors { Connector connector = new Connector(HTTP_PROTOCOL); connector.setURIEncoding("UTF-8"); - connector.setProperty("address", props.value("sonar.web.host", "0.0.0.0")); + connector.setProperty("address", props.value(WEB_HOST.getKey(), "0.0.0.0")); connector.setProperty("socket.soReuseAddress", "true"); // see https://tomcat.apache.org/tomcat-8.5-doc/config/http.html connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}"); @@ -75,9 +79,9 @@ class TomcatConnectors { private static void configurePool(Props props, Connector connector) { connector.setProperty("acceptorThreadCount", String.valueOf(2)); - connector.setProperty("minSpareThreads", String.valueOf(props.valueAsInt("sonar.web.http.minThreads", 5))); - connector.setProperty("maxThreads", String.valueOf(props.valueAsInt("sonar.web.http.maxThreads", 50))); - connector.setProperty("acceptCount", String.valueOf(props.valueAsInt("sonar.web.http.acceptCount", 25))); + connector.setProperty("minSpareThreads", String.valueOf(props.valueAsInt(WEB_HTTP_MIN_THREADS.getKey(), 5))); + connector.setProperty("maxThreads", String.valueOf(props.valueAsInt(WEB_HTTP_MAX_THREADS.getKey(), 50))); + connector.setProperty("acceptCount", String.valueOf(props.valueAsInt(WEB_HTTP_ACCEPT_COUNT.getKey(), 25))); } private static void configureCompression(Connector connector) { diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatContexts.java b/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatContexts.java index 48eb59b495b..b1afee1dd83 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatContexts.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatContexts.java @@ -32,6 +32,7 @@ import org.sonar.process.Props; import static java.lang.String.format; import static org.sonar.process.ProcessProperties.Property.PATH_DATA; import static org.sonar.process.ProcessProperties.Property.PATH_HOME; +import static org.sonar.process.ProcessProperties.Property.WEB_CONTEXT; /** * Configures Tomcat contexts: @@ -41,8 +42,6 @@ import static org.sonar.process.ProcessProperties.Property.PATH_HOME; * </ul> */ public class TomcatContexts { - - private static final String PROPERTY_CONTEXT = "sonar.web.context"; private static final String WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR = "web/deploy"; private final Fs fs; @@ -68,11 +67,11 @@ public class TomcatContexts { } static String getContextPath(Props props) { - String context = props.value(PROPERTY_CONTEXT, ""); + String context = props.value(WEB_CONTEXT.getKey(), ""); if ("/".equals(context)) { context = ""; } else if (!"".equals(context) && context != null && !context.startsWith("/")) { - throw MessageException.of(format("Value of '%s' must start with a forward slash: '%s'", PROPERTY_CONTEXT, context)); + throw MessageException.of(format("Value of '%s' must start with a forward slash: '%s'", WEB_CONTEXT.getKey(), context)); } return context; } diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java index 71b214b4684..98e952f52db 100644 --- a/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java +++ b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java @@ -40,6 +40,7 @@ import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.scanner.ScannerSide; import org.sonar.api.server.ServerSide; +import org.sonar.api.utils.System2; import static com.google.common.collect.ImmutableList.copyOf; import static java.util.Objects.requireNonNull; @@ -88,7 +89,7 @@ public class ComponentContainer implements ContainerPopulator.Container { } protected ComponentContainer(MutablePicoContainer picoContainer) { - this(picoContainer, new PropertyDefinitions()); + this(picoContainer, new PropertyDefinitions(System2.INSTANCE)); } protected ComponentContainer(MutablePicoContainer picoContainer, PropertyDefinitions propertyDefinitions) { diff --git a/sonar-core/src/main/java/org/sonar/core/util/SettingFormatter.java b/sonar-core/src/main/java/org/sonar/core/util/SettingFormatter.java index 7233a79cbbb..74b3eb06886 100644 --- a/sonar-core/src/main/java/org/sonar/core/util/SettingFormatter.java +++ b/sonar-core/src/main/java/org/sonar/core/util/SettingFormatter.java @@ -20,6 +20,9 @@ package org.sonar.core.util; import java.util.Locale; +import org.apache.commons.lang.StringUtils; + +import static org.apache.commons.lang.StringUtils.trim; public final class SettingFormatter { private SettingFormatter() { @@ -29,4 +32,16 @@ public final class SettingFormatter { public static String fromJavaPropertyToEnvVariable(String property) { return property.toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_'); } + + /** + * Value is split and trimmed. + */ + public static String[] getStringArrayBySeparator(String value, String separator) { + String[] strings = StringUtils.splitByWholeSeparator(value, separator); + String[] result = new String[strings.length]; + for (int index = 0; index < strings.length; index++) { + result[index] = trim(strings[index]); + } + return result; + } } diff --git a/sonar-core/src/test/java/org/sonar/core/util/SettingFormatterTest.java b/sonar-core/src/test/java/org/sonar/core/util/SettingFormatterTest.java index d9aed76edf9..608e4c5ed56 100644 --- a/sonar-core/src/test/java/org/sonar/core/util/SettingFormatterTest.java +++ b/sonar-core/src/test/java/org/sonar/core/util/SettingFormatterTest.java @@ -30,4 +30,16 @@ public class SettingFormatterTest { String output = SettingFormatter.fromJavaPropertyToEnvVariable("some.randomProperty-123.test"); assertThat(output).isEqualTo("SOME_RANDOMPROPERTY_123_TEST"); } + + @Test + public void test_getStringArrayBySeparator_on_input_with_separator() { + String[] result = SettingFormatter.getStringArrayBySeparator(" abc, DeF , ghi", ","); + assertThat(result).containsExactly("abc", "DeF", "ghi"); + } + + @Test + public void test_getStringArrayBySeparator_on_input_without_separator() { + String[] result = SettingFormatter.getStringArrayBySeparator(" abc, DeF , ghi", ";"); + assertThat(result).containsExactly("abc, DeF , ghi"); + } } diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/config/internal/MapSettings.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/config/internal/MapSettings.java index 764eef2812d..4ca59b06733 100644 --- a/sonar-plugin-api-impl/src/main/java/org/sonar/api/config/internal/MapSettings.java +++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/config/internal/MapSettings.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Optional; import org.sonar.api.config.Configuration; import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.utils.System2; import static java.util.Collections.unmodifiableMap; import static java.util.Objects.requireNonNull; @@ -42,7 +43,7 @@ public class MapSettings extends Settings { private final ConfigurationBridge configurationBridge; public MapSettings() { - this(new PropertyDefinitions()); + this(new PropertyDefinitions(System2.INSTANCE)); } public MapSettings(PropertyDefinitions definitions) { diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/config/internal/MapSettingsTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/config/internal/MapSettingsTest.java index 89845b01dbb..6cf2c86c021 100644 --- a/sonar-plugin-api-impl/src/test/java/org/sonar/api/config/internal/MapSettingsTest.java +++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/config/internal/MapSettingsTest.java @@ -41,6 +41,7 @@ import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.utils.DateUtils; +import org.sonar.api.utils.System2; import static java.util.Collections.singletonList; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; @@ -75,7 +76,7 @@ public class MapSettingsTest { @Before public void init_definitions() { - definitions = new PropertyDefinitions(); + definitions = new PropertyDefinitions(System2.INSTANCE); definitions.addComponent(Init.class); } @@ -129,7 +130,7 @@ public class MapSettingsTest { public void set_property_string_throws_NPE_if_key_is_null() { String key = randomAlphanumeric(3); - Settings underTest = new MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build()))); + Settings underTest = new MapSettings(new PropertyDefinitions(System2.INSTANCE, singletonList(PropertyDefinition.builder(key).multiValues(true).build()))); expectKeyNullNPE(); @@ -160,7 +161,7 @@ public class MapSettingsTest { public void set_property_string_array_trims_key() { String key = randomAlphanumeric(3); - Settings underTest = new MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build()))); + Settings underTest = new MapSettings(new PropertyDefinitions(System2.INSTANCE, singletonList(PropertyDefinition.builder(key).multiValues(true).build()))); Random random = new Random(); String blankBefore = blank(random); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java index f76de7ebae3..2bc87e54510 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java @@ -23,19 +23,23 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import java.util.Optional; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.sonar.api.CoreProperties; import org.sonar.api.Properties; import org.sonar.api.Property; -import org.sonar.api.scanner.ScannerSide; import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.api.scanner.ScannerSide; import org.sonar.api.server.ServerSide; import org.sonar.api.utils.AnnotationUtils; +import org.sonar.api.utils.System2; import static java.util.Objects.requireNonNull; +import static java.util.Optional.ofNullable; /** * Metadata of all the properties declared by plugins @@ -48,17 +52,22 @@ import static java.util.Objects.requireNonNull; public final class PropertyDefinitions { private final Map<String, PropertyDefinition> definitions = new HashMap<>(); + private final Map<String, String> propertyValueFromEnvironment = new HashMap<>(); private final Map<String, Category> categories = new HashMap<>(); private final Map<String, SubCategory> subcategories = new HashMap<>(); // deprecated key -> new key private final Map<String, String> deprecatedKeys = new HashMap<>(); - public PropertyDefinitions(Object... components) { + private final System2 system; + + public PropertyDefinitions(System2 system, Object... components) { + this.system = system; addComponents(Arrays.asList(components)); } - public PropertyDefinitions(Collection<PropertyDefinition> components) { + public PropertyDefinitions(System2 system, Collection<PropertyDefinition> components) { + this.system = system; addComponents(components); } @@ -108,6 +117,8 @@ public final class PropertyDefinitions { private PropertyDefinitions add(PropertyDefinition definition, String defaultCategory) { if (!definitions.containsKey(definition.key())) { definitions.put(definition.key(), definition); + String envVar = definition.key().toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_'); + ofNullable(system.envVariable(envVar)).ifPresent(value -> propertyValueFromEnvironment.put(definition.key(), value)); String category = StringUtils.defaultIfBlank(definition.category(), defaultCategory); categories.put(definition.key(), new Category(category)); String subcategory = StringUtils.defaultIfBlank(definition.subCategory(), category); @@ -124,6 +135,14 @@ public final class PropertyDefinitions { return definitions.get(validKey(key)); } + public Optional<String> getValueFromEnv(String key) { + return ofNullable(propertyValueFromEnvironment.get(key)); + } + + public Map<String, String> getAllPropertiesSetInEnv() { + return new HashMap<>(propertyValueFromEnvironment); + } + public Collection<PropertyDefinition> getAll() { return definitions.values(); } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java index d7555cc3701..fa915935f0f 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java @@ -19,6 +19,7 @@ */ package org.sonar.api.config; +import com.google.common.collect.ImmutableMap; import java.util.Arrays; import java.util.List; import java.util.Random; @@ -30,9 +31,12 @@ import org.junit.rules.ExpectedException; import org.sonar.api.Properties; import org.sonar.api.Property; import org.sonar.api.resources.Qualifiers; +import org.sonar.api.utils.System2; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class PropertyDefinitionsTest { @Rule @@ -44,14 +48,14 @@ public class PropertyDefinitionsTest { PropertyDefinition.builder("foo").name("Foo").build(), PropertyDefinition.builder("one").name("One").build(), PropertyDefinition.builder("two").name("Two").defaultValue("2").build()); - PropertyDefinitions def = new PropertyDefinitions(list); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, list); assertProperties(def); } @Test public void should_inspect_plugin_objects() { - PropertyDefinitions def = new PropertyDefinitions( + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder("foo").name("Foo").build(), PropertyDefinition.builder("one").name("One").build(), PropertyDefinition.builder("two").name("Two").defaultValue("2").build()); @@ -61,21 +65,21 @@ public class PropertyDefinitionsTest { @Test public void should_inspect_annotation_plugin_objects() { - PropertyDefinitions def = new PropertyDefinitions(new PluginWithProperty(), new PluginWithProperties()); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, new PluginWithProperty(), new PluginWithProperties()); assertProperties(def); } @Test public void should_inspect_plugin_classes() { - PropertyDefinitions def = new PropertyDefinitions(PluginWithProperty.class, PluginWithProperties.class); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, PluginWithProperty.class, PluginWithProperties.class); assertProperties(def); } @Test public void test_categories() { - PropertyDefinitions def = new PropertyDefinitions( + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder("inCateg").name("In Categ").category("categ").build(), PropertyDefinition.builder("noCateg").name("No categ").build()); @@ -85,7 +89,7 @@ public class PropertyDefinitionsTest { @Test public void test_categories_on_annotation_plugin() { - PropertyDefinitions def = new PropertyDefinitions(Categories.class); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, Categories.class); assertThat(def.getCategory("inCateg")).isEqualTo("categ"); assertThat(def.getCategory("noCateg")).isEqualTo(""); @@ -93,7 +97,7 @@ public class PropertyDefinitionsTest { @Test public void test_default_category() { - PropertyDefinitions def = new PropertyDefinitions(); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE); def.addComponent(PropertyDefinition.builder("inCateg").name("In Categ").category("categ").build(), "default"); def.addComponent(PropertyDefinition.builder("noCateg").name("No categ").build(), "default"); @@ -103,7 +107,7 @@ public class PropertyDefinitionsTest { @Test public void test_default_category_on_annotation_plugin() { - PropertyDefinitions def = new PropertyDefinitions(); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE); def.addComponent(Categories.class, "default"); assertThat(def.getCategory("inCateg")).isEqualTo("categ"); assertThat(def.getCategory("noCateg")).isEqualTo("default"); @@ -111,7 +115,7 @@ public class PropertyDefinitionsTest { @Test public void should_return_special_categories() { - PropertyDefinitions def = new PropertyDefinitions(); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE); assertThat(def.propertiesByCategory(null).get(new Category("general")).keySet()).containsOnly(new SubCategory("email")); assertThat(def.propertiesByCategory(null).get(new Category("general")).keySet().iterator().next().isSpecial()).isTrue(); @@ -123,7 +127,7 @@ public class PropertyDefinitionsTest { @Test public void should_group_by_category() { - PropertyDefinitions def = new PropertyDefinitions( + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder("global1").name("Global1").category("catGlobal1").build(), PropertyDefinition.builder("global2").name("Global2").category("catGlobal1").build(), PropertyDefinition.builder("global3").name("Global3").category("catGlobal2").build(), @@ -142,7 +146,7 @@ public class PropertyDefinitionsTest { @Test public void should_group_by_subcategory() { - PropertyDefinitions def = new PropertyDefinitions( + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder("global1").name("Global1").category("catGlobal1").subCategory("sub1").build(), PropertyDefinition.builder("global2").name("Global2").category("catGlobal1").subCategory("sub2").build(), PropertyDefinition.builder("global3").name("Global3").category("catGlobal1").build(), @@ -155,7 +159,7 @@ public class PropertyDefinitionsTest { @Test public void should_group_by_category_on_annotation_plugin() { - PropertyDefinitions def = new PropertyDefinitions(ByCategory.class); + PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, ByCategory.class); assertThat(def.propertiesByCategory(null).keySet()).contains(new Category("catglobal1"), new Category("catglobal2")); assertThat(def.propertiesByCategory(Qualifiers.PROJECT).keySet()).containsOnly(new Category("catproject")); @@ -176,7 +180,7 @@ public class PropertyDefinitionsTest { @Test public void validKey_throws_NPE_if_key_is_null() { - PropertyDefinitions underTest = new PropertyDefinitions(); + PropertyDefinitions underTest = new PropertyDefinitions(System2.INSTANCE); expectedException.expect(NullPointerException.class); expectedException.expectMessage("key can't be null"); @@ -186,7 +190,7 @@ public class PropertyDefinitionsTest { @Test public void get_throws_NPE_if_key_is_null() { - PropertyDefinitions underTest = new PropertyDefinitions(); + PropertyDefinitions underTest = new PropertyDefinitions(System2.INSTANCE); expectedException.expect(NullPointerException.class); expectedException.expectMessage("key can't be null"); @@ -199,15 +203,15 @@ public class PropertyDefinitionsTest { Random random = new Random(); String key = RandomStringUtils.randomAlphanumeric(4); String deprecatedKey = RandomStringUtils.randomAlphanumeric(4); - PropertyDefinitions underTest = new PropertyDefinitions(singletonList( + PropertyDefinitions underTest = new PropertyDefinitions(System2.INSTANCE, singletonList( PropertyDefinition.builder(key) .deprecatedKey(deprecatedKey) .build())); String untrimmedKey = blank(random) + deprecatedKey + blank(random); assertThat(underTest.get(untrimmedKey).key()) - .describedAs("expecting key %s being returned for get(%s)", key, untrimmedKey) - .isEqualTo(key); + .describedAs("expecting key %s being returned for get(%s)", key, untrimmedKey) + .isEqualTo(key); } private static String blank(Random random) { @@ -216,6 +220,33 @@ public class PropertyDefinitionsTest { return b.toString(); } + @Test + public void get_value_from_env() { + System2 system = mock(System2.class); + when(system.envVariable("FOO")).thenReturn("777"); + when(system.envVariable("ONE")).thenReturn("888"); + when(system.envVariable("SOME_COMPLETELY_RANDOM_ENV_VAR")).thenReturn("999"); + + PropertyDefinitions underTest = new PropertyDefinitions(system, new PluginWithProperty(), new PluginWithProperties()); + + assertThat(underTest.getValueFromEnv("foo")).hasValue("777"); + assertThat(underTest.getValueFromEnv("one")).hasValue("888"); + assertThat(underTest.getValueFromEnv("two")).isEmpty(); + assertThat(underTest.getValueFromEnv("some.unrecognizable.prop")).isEmpty(); + } + + @Test + public void get_all_properties_set_in_env() { + System2 system = mock(System2.class); + when(system.envVariable("FOO")).thenReturn("777"); + when(system.envVariable("ONE")).thenReturn("888"); + when(system.envVariable("SOME_COMPLETELY_RANDOM_ENV_VAR")).thenReturn("999"); + + PropertyDefinitions underTest = new PropertyDefinitions(system, new PluginWithProperty(), new PluginWithProperties()); + + assertThat(underTest.getAllPropertiesSetInEnv()).containsExactlyInAnyOrderEntriesOf(ImmutableMap.of("foo", "777", "one", "888")); + } + @Property(key = "foo", name = "Foo") static final class PluginWithProperty { } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalConfigurationProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalConfigurationProviderTest.java index 1ec4a238abb..2b57667e501 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalConfigurationProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalConfigurationProviderTest.java @@ -26,6 +26,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.utils.System2; import org.sonar.api.utils.log.LogTester; import static org.assertj.core.api.Assertions.assertThat; @@ -34,7 +35,6 @@ import static org.mockito.Mockito.when; public class GlobalConfigurationProviderTest { - public static final String SOME_VALUE = "some_value"; @Rule public ExpectedException thrown = ExpectedException.none(); @Rule @@ -53,7 +53,7 @@ public class GlobalConfigurationProviderTest { public void should_load_global_settings() { when(globalServerSettings.properties()).thenReturn(ImmutableMap.of("sonar.cpd.cross", "true")); - GlobalConfiguration globalConfig = new GlobalConfigurationProvider().provide(globalServerSettings, scannerProps, new PropertyDefinitions()); + GlobalConfiguration globalConfig = new GlobalConfigurationProvider().provide(globalServerSettings, scannerProps, new PropertyDefinitions(System2.INSTANCE)); assertThat(globalConfig.get("sonar.cpd.cross")).hasValue("true"); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/config/DefaultConfigurationTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/config/DefaultConfigurationTest.java index 1646722b2ce..c840607ff7b 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/config/DefaultConfigurationTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/config/DefaultConfigurationTest.java @@ -24,13 +24,15 @@ import java.util.Arrays; import org.junit.Rule; import org.junit.Test; import org.sonar.api.config.Configuration; -import org.sonar.api.config.internal.Encryption; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.PropertyFieldDefinition; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.utils.System2; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -41,7 +43,7 @@ public class DefaultConfigurationTest { @Test public void accessingMultiValuedPropertiesShouldBeConsistentWithDeclaration() { - Configuration config = new DefaultConfiguration(new PropertyDefinitions(Arrays.asList( + Configuration config = new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, Arrays.asList( PropertyDefinition.builder("single").multiValues(false).build(), PropertyDefinition.builder("multiA").multiValues(true).build())), new Encryption(null), ImmutableMap.of("single", "foo", "multiA", "a,b", "notDeclared", "c,d")) { @@ -68,7 +70,7 @@ public class DefaultConfigurationTest { @Test public void accessingPropertySetPropertiesShouldBeConsistentWithDeclaration() { - Configuration config = new DefaultConfiguration(new PropertyDefinitions(Arrays.asList( + Configuration config = new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, Arrays.asList( PropertyDefinition.builder("props").fields(PropertyFieldDefinition.build("foo1").name("Foo1").build(), PropertyFieldDefinition.build("foo2").name("Foo2").build()).build())), new Encryption(null), ImmutableMap.of("props", "1,2", "props.1.foo1", "a", "props.1.foo2", "b")) { @@ -87,7 +89,7 @@ public class DefaultConfigurationTest { @Test public void getDefaultValues() { - Configuration config = new DefaultConfiguration(new PropertyDefinitions(Arrays.asList( + Configuration config = new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, Arrays.asList( PropertyDefinition.builder("single").multiValues(false).defaultValue("default").build(), PropertyDefinition.builder("multiA").multiValues(true).defaultValue("foo,bar").build())), new Encryption(null), ImmutableMap.of()) { @@ -114,7 +116,7 @@ public class DefaultConfigurationTest { assertThat(getStringArray("a\n,b\n")).containsExactly("a", "b"); assertThat(getStringArray("a\n,b\n,\"\"")).containsExactly("a", "b", ""); assertThat(getStringArray("a\n, \" \" ,b\n")).containsExactly("a", " ", "b"); - assertThat(getStringArray(" \" , ,, \", a\n,b\n")).containsExactly(" , ,, ", "a","b"); + assertThat(getStringArray(" \" , ,, \", a\n,b\n")).containsExactly(" , ,, ", "a", "b"); assertThat(getStringArray("a\n,,b\n")).containsExactly("a", "b"); assertThat(getStringArray("a,\n\nb,c")).containsExactly("a", "b", "c"); assertThat(getStringArray("a,b\n\nc,d")).containsExactly("a", "b\nc", "d"); @@ -127,7 +129,7 @@ public class DefaultConfigurationTest { } private String[] getStringArray(String value) { - return new DefaultConfiguration(new PropertyDefinitions(Arrays.asList( + return new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, singletonList( PropertyDefinition.builder("multi").multiValues(true).build())), new Encryption(null), ImmutableMap.of("multi", value)) { }.getStringArray("multi"); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericCoverageSensorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericCoverageSensorTest.java index 4fde4372d75..a8073090a33 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericCoverageSensorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericCoverageSensorTest.java @@ -24,8 +24,9 @@ import java.util.Map; import java.util.Set; import org.junit.Rule; import org.junit.Test; -import org.sonar.api.config.internal.Encryption; import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.utils.System2; import org.sonar.api.utils.log.LogTester; import org.sonar.scanner.config.DefaultConfiguration; import org.sonar.scanner.scan.ProjectConfiguration; @@ -41,7 +42,7 @@ public class GenericCoverageSensorTest { public void loadAllReportPaths() { Map<String, String> settings = new HashMap<>(); settings.put(GenericCoverageSensor.REPORT_PATHS_PROPERTY_KEY, "report.xml,report2.xml"); - PropertyDefinitions defs = new PropertyDefinitions(GenericCoverageSensor.properties()); + PropertyDefinitions defs = new PropertyDefinitions(System2.INSTANCE, GenericCoverageSensor.properties()); DefaultConfiguration config = new ProjectConfiguration(defs, new Encryption(null), settings); Set<String> reportPaths = new GenericCoverageSensor(config).loadReportPaths(); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericTestExecutionSensorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericTestExecutionSensorTest.java index c5e9427f88d..ed4802bc321 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericTestExecutionSensorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericTestExecutionSensorTest.java @@ -28,14 +28,15 @@ import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.sonar.api.config.internal.Encryption; +import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.internal.Encryption; +import org.sonar.api.utils.System2; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.scanner.config.DefaultConfiguration; import org.sonar.scanner.deprecated.test.TestPlanBuilder; import org.sonar.scanner.scan.ProjectConfiguration; -import org.sonar.api.batch.sensor.internal.SensorContextTester; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -57,7 +58,7 @@ public class GenericTestExecutionSensorTest { Map<String, String> settings = new HashMap<>(); settings.put(GenericTestExecutionSensor.OLD_UNIT_TEST_REPORT_PATHS_PROPERTY_KEY, "report.xml"); - PropertyDefinitions defs = new PropertyDefinitions(GenericTestExecutionSensor.properties()); + PropertyDefinitions defs = new PropertyDefinitions(System2.INSTANCE, GenericTestExecutionSensor.properties()); DefaultConfiguration config = new ProjectConfiguration(defs, new Encryption(null), settings); new GenericTestExecutionSensor(mock(TestPlanBuilder.class), config).execute(context); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java index d29ffe745f7..cbb6acfb109 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java @@ -24,6 +24,7 @@ import org.junit.Test; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.System2; import org.sonar.core.config.IssueExclusionProperties; import static org.assertj.core.api.Assertions.assertThat; @@ -34,7 +35,7 @@ public class IssueExclusionPatternInitializerTest { @Before public void init() { - settings = new MapSettings(new PropertyDefinitions(IssueExclusionProperties.all())); + settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, IssueExclusionProperties.all())); } @Test diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java index 5055af6b15d..4d1d6bb3387 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.System2; import org.sonar.core.config.IssueExclusionProperties; import static org.assertj.core.api.Assertions.assertThat; @@ -34,7 +35,7 @@ public class IssueInclusionPatternInitializerTest { @Before public void init() { - settings = new MapSettings(new PropertyDefinitions(IssueExclusionProperties.all())); + settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, IssueExclusionProperties.all())); patternsInitializer = new IssueInclusionPatternInitializer(settings.asConfig()); } |