]> source.dussan.org Git - sonarqube.git/commitdiff
SONARCLOUD-336: Automatically guess the projectKey/organization
authorMichal Duda <michal.duda@sonarsource.com>
Fri, 1 Feb 2019 11:51:32 +0000 (12:51 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 18 Feb 2019 19:20:55 +0000 (20:20 +0100)
56 files changed:
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmDbTester.java
sonar-core/src/main/java/org/sonar/core/config/ScannerProperties.java
sonar-core/src/test/java/org/sonar/core/config/CorePropertyDefinitionsTest.java
sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/DefaultAnalysisMode.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalAnalysisMode.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalServerSettingsProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalTempFolderProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ProcessedScannerProperties.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/RawScannerProperties.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerProperties.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerWsClientProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/AbstractSettingsLoader.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoader.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultProjectSettingsLoader.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultSettingsLoader.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/GlobalSettingsLoader.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/ProjectSettingsLoader.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/SettingsLoader.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/EmptyExternalProjectKeyAndOrganization.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganization.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationLoader.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationProvider.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/DefaultAnalysisModeTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalAnalysisModeTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalConfigurationProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalContainerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalTempFolderProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PluginFilesTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ProcessedScannerPropertiesTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerPropertiesTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerWsClientProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerWsClientTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/index/AbstractCachesTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/log/ExceptionHandlingMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/QualityProfileProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/AbstractSettingsLoaderTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoaderTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultProjectSettingsLoaderTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultSettingsLoaderTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationProviderTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorBuilderTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java

index c42071ea97abb3799d48407cc13065b462e27e5f..a1b5cb3f75ac8a653bbee35b431c3751201208e6 100644 (file)
@@ -123,7 +123,7 @@ public class ComputeEngineContainerImplTest {
           + 26 // level 1
           + 60 // content of DaoModule
           + 3 // content of EsModule
-          + 53 // content of CorePropertyDefinitions
+          + 54 // content of CorePropertyDefinitions
           + 1 // StopFlagContainer
       );
       assertThat(
index 9ff0aa9e17447c5892520265f790c579c5a466d6..eca30f4dcd1eef15c8514446c16e3d38d98b4318 100644 (file)
@@ -430,4 +430,8 @@ public class ComponentDao implements Dao {
     return mapper(dbSession).selectPrivateProjectsWithNcloc(organizationUuid);
   }
 
+  public Optional<ComponentDto> selectByAlmIdAndAlmRepositoryId(DbSession dbSession, String almId, String almRepositoryId) {
+    return Optional.ofNullable(mapper(dbSession).selectByAlmIdAndAlmRepositoryId(almId, almRepositoryId));
+  }
+
 }
index 86cac939a71d0af103575261476642a5e6afdb39..fac6f2c06da9353253df3e49b4890b50d74f251c 100644 (file)
@@ -45,6 +45,9 @@ public interface ComponentMapper {
   @CheckForNull
   ComponentDto selectByUuid(String uuid);
 
+  @CheckForNull
+  ComponentDto selectByAlmIdAndAlmRepositoryId(@Param("almId") String almId, @Param("almRepositoryId") String almRepositoryId);
+
   /**
    * Return sub project of component keys
    */
index fc0a1a5cf3724188aa226cba6796412dbd9f2ce2..cbe0e28ce31cf2d8c0f4f7b4fe68d98fb6417d89 100644 (file)
       p.uuid=#{uuid,jdbcType=VARCHAR}
   </select>
 
+  <select id="selectByAlmIdAndAlmRepositoryId" resultType="Component">
+    select
+    <include refid="componentColumns"/>
+    from
+    projects p
+    inner join
+    project_alm_bindings pab on pab.project_uuid = p.uuid
+    where
+    pab.alm_id = #{almId,jdbcType=VARCHAR} and pab.repo_id = #{almRepositoryId,jdbcType=VARCHAR}
+  </select>
+
   <select id="selectByProjectUuid" parameterType="string" resultType="Component">
     select
     <include refid="componentColumns"/>
index f18767c6db103eb2bd99126be25da28303c8b021..5b015586bf133f37ceedf3980ae84be4f7958790 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.db.alm;
 import java.util.Arrays;
 import java.util.function.Consumer;
 import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.user.UserDto;
 
@@ -44,6 +45,13 @@ public class AlmDbTester {
     return db.getDbClient().organizationAlmBindingDao().selectByOrganization(db.getSession(), organization).get();
   }
 
+  public ProjectAlmBindingDto insertProjectAlmBinding(ALM alm, ComponentDto componentDto, String repositoryUuid) {
+    db.getDbClient().projectAlmBindingsDao().insertOrUpdate(db.getSession(), alm, repositoryUuid, componentDto.uuid(),
+      "some_org/some_repo", "http://alm/some_org_some_repo");
+    db.commit();
+    return db.getDbClient().projectAlmBindingsDao().selectByProjectUuid(db.getSession(), componentDto.uuid()).get();
+  }
+
   @SafeVarargs
   public final AlmAppInstallDto insertAlmAppInstall(Consumer<AlmAppInstallDto>... dtoPopulators) {
     AlmAppInstallDto dto = new AlmAppInstallDto()
index c34d1792b5b95a3e0dddcff6c973b5357a2940c5..cb67a39fb17cab02c619ed89f94a6be174bdbb6a 100644 (file)
@@ -41,6 +41,7 @@ public class ScannerProperties {
   public static final String PULL_REQUEST_BASE = "sonar.pullrequest.base";
 
   public static final String LINKS_SOURCES_DEV = "sonar.links.scm_dev";
+  public static final String DISABLE_PROJECT_AND_ORG_AUTODETECTION = "sonar.keys_autodetection.disabled";
 
   private ScannerProperties() {
     // only static stuff
@@ -90,6 +91,12 @@ public class ScannerProperties {
           "Defines the target branch of the pull request being analyzed. "
             + "If no target is defined, the main branch is used as the target.")
         .hidden()
+        .build(),
+      PropertyDefinition.builder(DISABLE_PROJECT_AND_ORG_AUTODETECTION)
+        .name("Disables project and organization auto-detection")
+        .description("Disables auto-detection of project and organization keys from scanner execution environment.")
+        .type(BOOLEAN)
+        .hidden()
         .build());
   }
 }
index 9649863b8b9e474bea19e96dce0391a26bb28f7a..54c4a7aac16289f312f1e493d347efe6d2251336 100644 (file)
@@ -30,7 +30,7 @@ public class CorePropertyDefinitionsTest {
   @Test
   public void all() {
     List<PropertyDefinition> defs = CorePropertyDefinitions.all();
-    assertThat(defs).hasSize(53);
+    assertThat(defs).hasSize(54);
   }
 
   @Test
index e805460f5cf4265033349b30858c0e1193031400..8eea31c6967cacf3bb673af37663ccb8482d208e 100644 (file)
@@ -142,26 +142,26 @@ public final class PropertyDefinitions {
     if (qualifier == null) {
       // Special categories on global page
       Map<SubCategory, Collection<PropertyDefinition>> emailSubCategories = new HashMap<>();
-      emailSubCategories.put(new SubCategory("email", true), new ArrayList<PropertyDefinition>());
+      emailSubCategories.put(new SubCategory("email", true), new ArrayList<>());
       byCategory.put(new Category(CoreProperties.CATEGORY_GENERAL, false), emailSubCategories);
 
       HashMap<SubCategory, Collection<PropertyDefinition>> licenseSubCategories = new HashMap<>();
-      licenseSubCategories.put(new SubCategory("server_id", true), new ArrayList<PropertyDefinition>());
+      licenseSubCategories.put(new SubCategory("server_id", true), new ArrayList<>());
       byCategory.put(new Category(CoreProperties.CATEGORY_LICENSES, false), licenseSubCategories);
 
       HashMap<SubCategory, Collection<PropertyDefinition>> encryptionSubCategories = new HashMap<>();
-      encryptionSubCategories.put(new SubCategory("encryption", true), new ArrayList<PropertyDefinition>());
+      encryptionSubCategories.put(new SubCategory("encryption", true), new ArrayList<>());
       byCategory.put(new Category(CoreProperties.CATEGORY_SECURITY, false), encryptionSubCategories);
     }
     for (PropertyDefinition definition : getAll()) {
       if (qualifier == null ? definition.global() : definition.qualifiers().contains(qualifier)) {
         Category category = categories.get(definition.key());
         if (!byCategory.containsKey(category)) {
-          byCategory.put(category, new HashMap<SubCategory, Collection<PropertyDefinition>>());
+          byCategory.put(category, new HashMap<>());
         }
         SubCategory subCategory = subcategories.get(definition.key());
         if (!byCategory.get(category).containsKey(subCategory)) {
-          byCategory.get(category).put(subCategory, new ArrayList<PropertyDefinition>());
+          byCategory.get(category).put(subCategory, new ArrayList<>());
         }
         byCategory.get(category).get(subCategory).add(definition);
       }
index b97e63b9ee17119221ee34a90450eda9e61c351b..abfc2727df243cb0aef194486c5895b8f7af52d6 100644 (file)
@@ -25,7 +25,7 @@ import org.sonar.api.batch.AnalysisMode;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 
 @Immutable
 public class DefaultAnalysisMode implements AnalysisMode {
@@ -37,7 +37,7 @@ public class DefaultAnalysisMode implements AnalysisMode {
 
   private boolean scanAllFiles;
 
-  public DefaultAnalysisMode(ScannerProperties props, GlobalAnalysisMode analysisMode) {
+  public DefaultAnalysisMode(ProcessedScannerProperties props, GlobalAnalysisMode analysisMode) {
     this.analysisMode = analysisMode;
     this.analysisProps = props.properties();
     load();
index 421dfdeb73fff77928a9150312960671b0c5141e..26aced1fb60216620f68d1967cb40b059fe4172c 100644 (file)
@@ -36,7 +36,7 @@ public class GlobalAnalysisMode {
   protected boolean issues;
   protected boolean mediumTestMode;
 
-  public GlobalAnalysisMode(ScannerProperties props) {
+  public GlobalAnalysisMode(RawScannerProperties props) {
     String mode = props.property(CoreProperties.ANALYSIS_MODE);
     validate(mode);
     issues = CoreProperties.ANALYSIS_MODE_ISSUES.equals(mode) || CoreProperties.ANALYSIS_MODE_PREVIEW.equals(mode);
index be54e94b2583fe241b52afc4020ffad43e58c6ed..ceb0fc91db66e698b1fdc1a0f76185b62d912a9e 100644 (file)
@@ -28,7 +28,8 @@ public class GlobalConfigurationProvider extends ProviderAdapter {
 
   private GlobalConfiguration globalConfig;
 
-  public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps, PropertyDefinitions propertyDefinitions) {
+  public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, RawScannerProperties scannerProps,
+    PropertyDefinitions propertyDefinitions) {
     if (globalConfig == null) {
       Map<String, String> mergedSettings = new LinkedHashMap<>();
       mergedSettings.putAll(globalServerSettings.properties());
index a8202e1fc4857afac4ee66916199426ce88dc222..4211ab99cfe409511aa7e0e5b5c1ce0f1656028d 100644 (file)
@@ -49,8 +49,8 @@ import org.sonar.scanner.platform.DefaultServer;
 import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader;
 import org.sonar.scanner.repository.MetricsRepositoryLoader;
 import org.sonar.scanner.repository.MetricsRepositoryProvider;
-import org.sonar.scanner.repository.settings.DefaultSettingsLoader;
-import org.sonar.scanner.repository.settings.SettingsLoader;
+import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader;
+import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
 import org.sonar.scanner.scan.ProjectScanContainer;
 import org.sonar.scanner.storage.StoragesManager;
 
@@ -71,9 +71,9 @@ public class GlobalContainer extends ComponentContainer {
 
   @Override
   protected void doBeforeStart() {
-    ScannerProperties scannerProps = new ScannerProperties(scannerProperties);
-    GlobalAnalysisMode globalMode = new GlobalAnalysisMode(scannerProps);
-    add(scannerProps);
+    RawScannerProperties rawScannerProperties = new RawScannerProperties(scannerProperties);
+    GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties);
+    add(rawScannerProperties);
     add(globalMode);
     addBootstrapComponents();
   }
@@ -106,7 +106,7 @@ public class GlobalContainer extends ComponentContainer {
       UuidFactoryImpl.INSTANCE);
     addIfMissing(ScannerPluginInstaller.class, PluginInstaller.class);
     add(CoreExtensionRepositoryImpl.class, CoreExtensionsLoader.class, ScannerCoreExtensionsInstaller.class);
-    addIfMissing(DefaultSettingsLoader.class, SettingsLoader.class);
+    addIfMissing(DefaultGlobalSettingsLoader.class, GlobalSettingsLoader.class);
     addIfMissing(DefaultMetricsRepositoryLoader.class, MetricsRepositoryLoader.class);
   }
 
index 9f2ff35d9d0d9913fe01cd4bde6c32d23ac0ec59..47ab119164fadddb788c8d9e300c8b23c5c25da3 100644 (file)
@@ -25,7 +25,7 @@ import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.repository.settings.SettingsLoader;
+import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
 
 public class GlobalServerSettingsProvider extends ProviderAdapter {
 
@@ -33,7 +33,7 @@ public class GlobalServerSettingsProvider extends ProviderAdapter {
 
   private GlobalServerSettings singleton;
 
-  public GlobalServerSettings provide(SettingsLoader loader) {
+  public GlobalServerSettings provide(GlobalSettingsLoader loader) {
     if (singleton == null) {
       Map<String, String> serverSideSettings = loader.loadGlobalSettings();
       singleton = new GlobalServerSettings(serverSideSettings);
index 20b5e2014a194dbd28a41d89518893897a2e56b7..ad49d73742589e259409d47e2ab67ddc8c6cbcf8 100644 (file)
@@ -56,7 +56,7 @@ public class GlobalTempFolderProvider extends ProviderAdapter implements Compone
     this.system = system;
   }
 
-  public TempFolder provide(ScannerProperties scannerProps) {
+  public TempFolder provide(RawScannerProperties scannerProps) {
     if (tempFolder == null) {
 
       String workingPathName = StringUtils.defaultIfBlank(scannerProps.property(CoreProperties.GLOBAL_WORKING_DIRECTORY), CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE);
@@ -95,7 +95,7 @@ public class GlobalTempFolderProvider extends ProviderAdapter implements Compone
     }
   }
 
-  private Path findSonarHome(ScannerProperties props) {
+  private Path findSonarHome(RawScannerProperties props) {
     String home = props.property("sonar.userHome");
     if (home != null) {
       return Paths.get(home).toAbsolutePath();
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ProcessedScannerProperties.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ProcessedScannerProperties.java
new file mode 100644 (file)
index 0000000..1c9b77b
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.bootstrap;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.bootstrap.ProjectKey;
+import org.sonar.scanner.scan.ExternalProjectKeyAndOrganization;
+
+import static org.apache.commons.lang.StringUtils.trimToNull;
+
+/**
+ * Properties that are coming from scanner.
+ */
+@Immutable
+public class ProcessedScannerProperties implements ProjectKey {
+
+  private final Map<String, String> properties;
+
+  public ProcessedScannerProperties(RawScannerProperties rawScannerProperties,
+    ExternalProjectKeyAndOrganization externalProjectKeyAndOrganization) {
+    this.properties = new HashMap<>();
+    this.properties.putAll(rawScannerProperties.properties());
+
+    externalProjectKeyAndOrganization.getProjectKey()
+      .ifPresent(projectKey -> properties.put(CoreProperties.PROJECT_KEY_PROPERTY, projectKey));
+    externalProjectKeyAndOrganization.getOrganization()
+      .ifPresent(organization -> properties.put(org.sonar.core.config.ScannerProperties.ORGANIZATION, organization));
+  }
+
+  public Map<String, String> properties() {
+    return ImmutableMap.copyOf(properties);
+  }
+
+  public String property(String key) {
+    return properties.get(key);
+  }
+
+  @Override
+  public String get() {
+    return getKeyWithBranch();
+  }
+
+  private String getKey() {
+    return properties.get(CoreProperties.PROJECT_KEY_PROPERTY);
+  }
+
+  public String getKeyWithBranch() {
+    String branch = getBranch();
+    String projectKey = getKey();
+    if (branch == null) {
+      return projectKey;
+    }
+    return String.format("%s:%s", projectKey, branch);
+  }
+
+  @CheckForNull
+  private String getBranch() {
+    return trimToNull(properties.get(CoreProperties.PROJECT_BRANCH_PROPERTY));
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/RawScannerProperties.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/RawScannerProperties.java
new file mode 100644 (file)
index 0000000..343e08c
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.bootstrap;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Encryption;
+
+/**
+ * Properties that are coming from scanner.
+ */
+@Immutable
+public class RawScannerProperties {
+
+  private final Map<String, String> properties;
+  private final Encryption encryption;
+
+  public RawScannerProperties(Map<String, String> properties) {
+    encryption = new Encryption(properties.get(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
+    Map<String, String> decryptedProps = new HashMap<>(properties.size());
+    for (Map.Entry<String, String> entry : properties.entrySet()) {
+      String value = entry.getValue();
+      if (value != null && encryption.isEncrypted(value)) {
+        try {
+          value = encryption.decrypt(value);
+        } catch (Exception e) {
+          throw new IllegalStateException("Fail to decrypt the property " + entry.getKey() + ". Please check your secret key.", e);
+        }
+      }
+      decryptedProps.put(entry.getKey(), value);
+    }
+    this.properties = decryptedProps;
+  }
+
+  public Encryption getEncryption() {
+    return encryption;
+  }
+
+  public Map<String, String> properties() {
+    return ImmutableMap.copyOf(properties);
+  }
+
+  public String property(String key) {
+    return properties.get(key);
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerProperties.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerProperties.java
deleted file mode 100644 (file)
index a351765..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.scanner.bootstrap;
-
-import com.google.common.collect.ImmutableMap;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.bootstrap.ProjectKey;
-import org.sonar.api.config.Encryption;
-
-import static org.apache.commons.lang.StringUtils.trimToNull;
-
-/**
- * Properties that are coming from scanner.
- */
-@Immutable
-public class ScannerProperties implements ProjectKey {
-
-  private final Map<String, String> properties;
-  private final Encryption encryption;
-
-  public ScannerProperties(Map<String, String> properties) {
-    encryption = new Encryption(properties.get(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
-    Map<String, String> decryptedProps = new HashMap<>(properties.size());
-    for (Map.Entry<String, String> entry : properties.entrySet()) {
-      String value = entry.getValue();
-      if (value != null && encryption.isEncrypted(value)) {
-        try {
-          value = encryption.decrypt(value);
-        } catch (Exception e) {
-          throw new IllegalStateException("Fail to decrypt the property " + entry.getKey() + ". Please check your secret key.", e);
-        }
-      }
-      decryptedProps.put(entry.getKey(), value);
-    }
-    this.properties = decryptedProps;
-  }
-
-  public Encryption getEncryption() {
-    return encryption;
-  }
-
-  public Map<String, String> properties() {
-    return ImmutableMap.copyOf(properties);
-  }
-
-  public String property(String key) {
-    return properties.get(key);
-  }
-
-  @Override
-  public String get() {
-    return getKeyWithBranch();
-  }
-
-  private String getKey() {
-    return properties.get(CoreProperties.PROJECT_KEY_PROPERTY);
-  }
-
-  public String getKeyWithBranch() {
-    String branch = getBranch();
-    String projectKey = getKey();
-    if (branch == null) {
-      return projectKey;
-    }
-    return String.format("%s:%s", projectKey, branch);
-  }
-
-  @CheckForNull
-  private String getBranch() {
-    return trimToNull(properties.get(CoreProperties.PROJECT_BRANCH_PROPERTY));
-  }
-}
index 810a2c37a41698f772abcaf36a4766dbd0abbf39..7f619482ab16ec57942e44303df641ec640f4384 100644 (file)
@@ -38,8 +38,8 @@ public class ScannerWsClientProvider extends ProviderAdapter {
 
   private ScannerWsClient wsClient;
 
-  public synchronized ScannerWsClient provide(final ScannerProperties scannerProps, final EnvironmentInformation env,
-    GlobalAnalysisMode globalMode, System2 system) {
+  public synchronized ScannerWsClient provide(final RawScannerProperties scannerProps,
+    final EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
     if (wsClient == null) {
       String url = defaultIfBlank(scannerProps.property("sonar.host.url"), CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE);
       HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder();
index 30eabd15947cbb5f7f965aef20ac96781de19a68..b6fae284f4818d3aec4dafb398ba894f405257fc 100644 (file)
@@ -24,7 +24,7 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 
 public class ProjectRepositoriesProvider extends ProviderAdapter {
@@ -32,7 +32,7 @@ public class ProjectRepositoriesProvider extends ProviderAdapter {
   private static final String LOG_MSG = "Load project repositories";
   private ProjectRepositories project = null;
 
-  public ProjectRepositories provide(ProjectRepositoriesLoader loader, ScannerProperties scannerProperties, GlobalAnalysisMode mode, BranchConfiguration branchConfig) {
+  public ProjectRepositories provide(ProjectRepositoriesLoader loader, ProcessedScannerProperties scannerProperties, GlobalAnalysisMode mode, BranchConfiguration branchConfig) {
     if (project == null) {
       boolean isIssuesMode = mode.isIssues();
       Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
index 60b52f440eea0ce976068e226a2d436776d4431d..7ed441cfa08cd2ce69bfde2765932e0662c4e9d0 100644 (file)
@@ -25,7 +25,7 @@ import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.rule.QualityProfiles;
 import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
 
@@ -34,7 +34,7 @@ public class QualityProfilesProvider extends ProviderAdapter {
   private static final String LOG_MSG = "Load quality profiles";
   private QualityProfiles profiles = null;
 
-  public QualityProfiles provide(QualityProfileLoader loader, ProjectRepositories projectRepositories, ScannerProperties props) {
+  public QualityProfiles provide(QualityProfileLoader loader, ProjectRepositories projectRepositories, ProcessedScannerProperties props) {
     if (this.profiles == null) {
       List<QualityProfile> profileList;
       Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
@@ -51,7 +51,7 @@ public class QualityProfilesProvider extends ProviderAdapter {
   }
 
   @CheckForNull
-  private static String getSonarProfile(ScannerProperties props) {
+  private static String getSonarProfile(ProcessedScannerProperties props) {
     String profile = props.property(QualityProfiles.SONAR_PROFILE_PROP);
     if (profile != null) {
       LOG.warn("Ability to set quality profile from command line using '" + QualityProfiles.SONAR_PROFILE_PROP
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/AbstractSettingsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/AbstractSettingsLoader.java
new file mode 100644 (file)
index 0000000..797acbf
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.util.ScannerUtils;
+import org.sonarqube.ws.Settings;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.HttpException;
+
+public abstract class AbstractSettingsLoader {
+
+  private static final Logger LOG = Loggers.get(AbstractSettingsLoader.class);
+  private final ScannerWsClient wsClient;
+
+  public AbstractSettingsLoader(final ScannerWsClient wsClient) {
+    this.wsClient = wsClient;
+  }
+
+  Map<String, String> load(@Nullable String componentKey) {
+    String url = "api/settings/values.protobuf";
+    Profiler profiler = Profiler.create(LOG);
+    if (componentKey != null) {
+      url += "?component=" + ScannerUtils.encodeForUrl(componentKey);
+      profiler.startInfo(String.format("Load project settings for component key: '%s'", componentKey));
+    } else {
+      profiler.startInfo("Load global settings");
+    }
+    try (InputStream is = wsClient.call(new GetRequest(url)).contentStream()) {
+      Settings.ValuesWsResponse values = Settings.ValuesWsResponse.parseFrom(is);
+      profiler.stopInfo();
+      return toMap(values.getSettingsList());
+    } catch (HttpException e) {
+      if (e.code() == HttpURLConnection.HTTP_NOT_FOUND) {
+        return Collections.emptyMap();
+      }
+      throw e;
+    } catch (IOException e) {
+      throw new IllegalStateException("Unable to load settings", e);
+    }
+  }
+
+  @VisibleForTesting
+  static Map<String, String> toMap(List<Settings.Setting> settingsList) {
+    Map<String, String> result = new LinkedHashMap<>();
+    for (Settings.Setting s : settingsList) {
+      if (!s.getInherited()) {
+        switch (s.getValueOneOfCase()) {
+          case VALUE:
+            result.put(s.getKey(), s.getValue());
+            break;
+          case VALUES:
+            result.put(s.getKey(), s.getValues().getValuesList().stream().map(StringEscapeUtils::escapeCsv).collect(Collectors.joining(",")));
+            break;
+          case FIELDVALUES:
+            convertPropertySetToProps(result, s);
+            break;
+          default:
+            throw new IllegalStateException("Unknown property value for " + s.getKey());
+        }
+      }
+    }
+    return result;
+  }
+
+  private static void convertPropertySetToProps(Map<String, String> result, Settings.Setting s) {
+    List<String> ids = new ArrayList<>();
+    int id = 1;
+    for (Settings.FieldValues.Value v : s.getFieldValues().getFieldValuesList()) {
+      for (Map.Entry<String, String> entry : v.getValueMap().entrySet()) {
+        result.put(s.getKey() + "." + id + "." + entry.getKey(), entry.getValue());
+      }
+      ids.add(String.valueOf(id));
+      id++;
+    }
+    result.put(s.getKey(), String.join(",", ids));
+  }
+
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoader.java
new file mode 100644 (file)
index 0000000..cd61656
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import java.util.Map;
+import org.sonar.scanner.bootstrap.ScannerWsClient;
+
+public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader {
+
+  public DefaultGlobalSettingsLoader(final ScannerWsClient wsClient) {
+    super(wsClient);
+  }
+
+  @Override
+  public Map<String, String> loadGlobalSettings() {
+    return load(null);
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultProjectSettingsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultProjectSettingsLoader.java
new file mode 100644 (file)
index 0000000..4274772
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import java.util.Map;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
+import org.sonar.scanner.bootstrap.ScannerWsClient;
+
+public class DefaultProjectSettingsLoader extends AbstractSettingsLoader implements ProjectSettingsLoader {
+  private final ProcessedScannerProperties scannerProperties;
+
+  public DefaultProjectSettingsLoader(final ScannerWsClient wsClient, final ProcessedScannerProperties scannerProperties) {
+    super(wsClient);
+    this.scannerProperties = scannerProperties;
+  }
+
+  @Override
+  public Map<String, String> loadProjectSettings() {
+    return load(scannerProperties.getKeyWithBranch());
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultSettingsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultSettingsLoader.java
deleted file mode 100644 (file)
index e3f820b..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.scanner.repository.settings;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.scanner.bootstrap.ScannerProperties;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
-import org.sonar.scanner.util.ScannerUtils;
-import org.sonarqube.ws.Settings.FieldValues.Value;
-import org.sonarqube.ws.Settings.Setting;
-import org.sonarqube.ws.Settings.ValuesWsResponse;
-import org.sonarqube.ws.client.GetRequest;
-import org.sonarqube.ws.client.HttpException;
-
-public class DefaultSettingsLoader implements SettingsLoader {
-
-  private ScannerWsClient wsClient;
-  private final ScannerProperties scannerProperties;
-  private static final Logger LOG = Loggers.get(DefaultSettingsLoader.class);
-
-  public DefaultSettingsLoader(ScannerWsClient wsClient, ScannerProperties scannerProperties) {
-    this.wsClient = wsClient;
-    this.scannerProperties = scannerProperties;
-  }
-
-  @Override
-  public Map<String, String> loadGlobalSettings() {
-    return load(null);
-  }
-
-  @Override
-  public Map<String, String> loadProjectSettings() {
-    return load(scannerProperties.getKeyWithBranch());
-  }
-
-  private Map<String, String> load(@Nullable String componentKey) {
-    String url = "api/settings/values.protobuf";
-    Profiler profiler = Profiler.create(LOG);
-    if (componentKey != null) {
-      url += "?component=" + ScannerUtils.encodeForUrl(componentKey);
-      profiler.startInfo("Load project settings");
-    } else {
-      profiler.startInfo("Load global settings");
-    }
-    try (InputStream is = wsClient.call(new GetRequest(url)).contentStream()) {
-      ValuesWsResponse values = ValuesWsResponse.parseFrom(is);
-      profiler.stopInfo();
-      return toMap(values.getSettingsList());
-    } catch (HttpException e) {
-      if (e.code() == HttpURLConnection.HTTP_NOT_FOUND) {
-        return Collections.emptyMap();
-      }
-      throw e;
-    } catch (IOException e) {
-      throw new IllegalStateException("Unable to load settings", e);
-    }
-  }
-
-  @VisibleForTesting
-  static Map<String, String> toMap(List<Setting> settingsList) {
-    Map<String, String> result = new LinkedHashMap<>();
-    for (Setting s : settingsList) {
-      if (!s.getInherited()) {
-        switch (s.getValueOneOfCase()) {
-          case VALUE:
-            result.put(s.getKey(), s.getValue());
-            break;
-          case VALUES:
-            result.put(s.getKey(), s.getValues().getValuesList().stream().map(StringEscapeUtils::escapeCsv).collect(Collectors.joining(",")));
-            break;
-          case FIELDVALUES:
-            convertPropertySetToProps(result, s);
-            break;
-          default:
-            throw new IllegalStateException("Unknow property value for " + s.getKey());
-        }
-      }
-    }
-    return result;
-  }
-
-  private static void convertPropertySetToProps(Map<String, String> result, Setting s) {
-    List<String> ids = new ArrayList<>();
-    int id = 1;
-    for (Value v : s.getFieldValues().getFieldValuesList()) {
-      for (Map.Entry<String, String> entry : v.getValue().entrySet()) {
-        result.put(s.getKey() + "." + id + "." + entry.getKey(), entry.getValue());
-      }
-      ids.add(String.valueOf(id));
-      id++;
-    }
-    result.put(s.getKey(), ids.stream().collect(Collectors.joining(",")));
-  }
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/GlobalSettingsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/GlobalSettingsLoader.java
new file mode 100644 (file)
index 0000000..4ff0a80
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import java.util.Map;
+
+public interface GlobalSettingsLoader {
+  Map<String, String> loadGlobalSettings();
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/ProjectSettingsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/ProjectSettingsLoader.java
new file mode 100644 (file)
index 0000000..9904a2d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import java.util.Map;
+
+public interface ProjectSettingsLoader {
+  Map<String, String> loadProjectSettings();
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/SettingsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/SettingsLoader.java
deleted file mode 100644 (file)
index b7942a6..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.scanner.repository.settings;
-
-import java.util.Map;
-
-public interface SettingsLoader {
-  Map<String, String> loadGlobalSettings();
-
-  Map<String, String> loadProjectSettings();
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/EmptyExternalProjectKeyAndOrganization.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/EmptyExternalProjectKeyAndOrganization.java
new file mode 100644 (file)
index 0000000..f6db041
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.scan;
+
+import java.util.Optional;
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Optional.empty;
+
+@Immutable
+public class EmptyExternalProjectKeyAndOrganization implements ExternalProjectKeyAndOrganization {
+  @Override
+  public Optional<String> getProjectKey() {
+    return empty();
+  }
+
+  @Override
+  public Optional<String> getOrganization() {
+    return empty();
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganization.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganization.java
new file mode 100644 (file)
index 0000000..e744d94
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.scan;
+
+import java.util.Optional;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+public interface ExternalProjectKeyAndOrganization {
+  Optional<String> getProjectKey();
+
+  Optional<String> getOrganization();
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationLoader.java
new file mode 100644 (file)
index 0000000..8aa92b3
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.scan;
+
+import java.util.Optional;
+import org.sonar.api.scanner.ScannerSide;
+
+@ScannerSide
+public interface ExternalProjectKeyAndOrganizationLoader {
+  Optional<ExternalProjectKeyAndOrganization> load();
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationProvider.java
new file mode 100644 (file)
index 0000000..c7d0456
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.scan;
+
+import org.picocontainer.annotations.Nullable;
+import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.bootstrap.RawScannerProperties;
+
+import static org.apache.commons.lang.StringUtils.equalsIgnoreCase;
+import static org.sonar.core.config.ScannerProperties.DISABLE_PROJECT_AND_ORG_AUTODETECTION;
+
+public class ExternalProjectKeyAndOrganizationProvider extends ProviderAdapter {
+  private static final Logger LOG = Loggers.get(ExternalProjectKeyAndOrganizationProvider.class);
+  private ExternalProjectKeyAndOrganization properties = null;
+
+  public ExternalProjectKeyAndOrganization provide(RawScannerProperties rawScannerProperties,
+    @Nullable @javax.annotation.Nullable ExternalProjectKeyAndOrganizationLoader loader) {
+    if (properties == null) {
+      boolean disableProjectKeyAndOrgAutodetection = equalsIgnoreCase(
+        rawScannerProperties.property(DISABLE_PROJECT_AND_ORG_AUTODETECTION), "true");
+      if (disableProjectKeyAndOrgAutodetection) {
+        LOG.info("Skipping project and organization key auto-detection.");
+      }
+
+      if (loader != null && !disableProjectKeyAndOrgAutodetection) {
+        properties = loader.load().orElse(new EmptyExternalProjectKeyAndOrganization());
+      } else {
+        properties = new EmptyExternalProjectKeyAndOrganization();
+      }
+    }
+
+    return properties;
+  }
+}
index 7dceaf350a050b3547c05bda5a9b88ee02985f02..5f709ee61c7525c3fc8e28f67b228d854ef691a0 100644 (file)
@@ -45,7 +45,7 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.core.config.IssueExclusionProperties;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
 import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
 import org.sonar.scanner.util.ScannerUtils;
@@ -110,12 +110,12 @@ public class ProjectReactorBuilder {
   private static final List<String> NON_HERITED_PROPERTIES_FOR_CHILD = Stream.concat(Stream.of(PROPERTY_PROJECT_BASEDIR, CoreProperties.WORKING_DIRECTORY, PROPERTY_MODULES,
     CoreProperties.PROJECT_DESCRIPTION_PROPERTY), UNSUPPORTED_PROPS_FOR_MODULES.stream()).collect(toList());
 
-  private final ScannerProperties scannerProps;
+  private final ProcessedScannerProperties scannerProps;
   private final AnalysisWarnings analysisWarnings;
   private File rootProjectWorkDir;
   private boolean warnExclusionsAlreadyLogged;
 
-  public ProjectReactorBuilder(ScannerProperties props, AnalysisWarnings analysisWarnings) {
+  public ProjectReactorBuilder(ProcessedScannerProperties props, AnalysisWarnings analysisWarnings) {
     this.scannerProps = props;
     this.analysisWarnings = analysisWarnings;
   }
index 09900d136c1d0287b2535a760da415869b0a04a2..540b88c4cac6f2b9b37ee27b2e60d3f186a9aef1 100644 (file)
@@ -45,6 +45,7 @@ import org.sonar.scanner.bootstrap.ExtensionMatcher;
 import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
 import org.sonar.scanner.bootstrap.MetricProvider;
 import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.cpd.CpdExecutor;
 import org.sonar.scanner.cpd.CpdSettings;
 import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
@@ -91,6 +92,8 @@ import org.sonar.scanner.repository.QualityProfileLoader;
 import org.sonar.scanner.repository.QualityProfilesProvider;
 import org.sonar.scanner.repository.ServerIssuesLoader;
 import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
+import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader;
+import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
 import org.sonar.scanner.rule.ActiveRulesLoader;
 import org.sonar.scanner.rule.ActiveRulesProvider;
 import org.sonar.scanner.rule.DefaultActiveRulesLoader;
@@ -142,8 +145,8 @@ public class ProjectScanContainer extends ComponentContainer {
 
   @Override
   protected void doBeforeStart() {
-    addScannerComponents();
     addScannerExtensions();
+    addScannerComponents();
     ProjectLock lock = getComponentByType(ProjectLock.class);
     lock.tryLock();
     getComponentByType(WorkDirectoriesInitializer.class).execute();
@@ -158,8 +161,10 @@ public class ProjectScanContainer extends ComponentContainer {
 
   private void addScannerComponents() {
     add(
-      ProjectReactorBuilder.class,
+      new ExternalProjectKeyAndOrganizationProvider(),
+      ProcessedScannerProperties.class,
       ScanProperties.class,
+      ProjectReactorBuilder.class,
       WorkDirectoriesInitializer.class,
       new MutableProjectReactorProvider(),
       ProjectBuildersExecutor.class,
@@ -281,6 +286,7 @@ public class ProjectScanContainer extends ComponentContainer {
 
       AnalysisObservers.class);
 
+    addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class);
     addIfMissing(DefaultRulesLoader.class, RulesLoader.class);
     addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class);
     addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class);
index a22d79cf7b9244015955869c0c30146db0f0a142..0c4f84f2a09bba0795e3c31bf26596925ea3e98f 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.api.CoreProperties;
 import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.repository.settings.SettingsLoader;
+import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
 
 public class ProjectServerSettingsProvider extends ProviderAdapter {
 
@@ -39,7 +39,7 @@ public class ProjectServerSettingsProvider extends ProviderAdapter {
 
   private ProjectServerSettings singleton = null;
 
-  public ProjectServerSettings provide(SettingsLoader loader, AnalysisWarnings analysisWarnings) {
+  public ProjectServerSettings provide(ProjectSettingsLoader loader, AnalysisWarnings analysisWarnings) {
     if (singleton == null) {
       Map<String, String> serverSideSettings = loader.loadProjectSettings();
       if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) {
index 19be5a48378037ea74ae8a7ec63eb8e54d6e4337..4e678fcd44d1681e282f7d4e0f1e387b81024686 100644 (file)
@@ -25,7 +25,9 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.RawScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
+import org.sonar.scanner.scan.EmptyExternalProjectKeyAndOrganization;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -44,7 +46,8 @@ public class DefaultAnalysisModeTest {
 
   @Test
   public void scan_all_even_on_short_lived_branch() {
-    ScannerProperties analysisProps = new ScannerProperties(Collections.singletonMap("sonar.scanAllFiles", "true"));
+    ProcessedScannerProperties analysisProps = new ProcessedScannerProperties(
+      new RawScannerProperties(Collections.singletonMap("sonar.scanAllFiles", "true")), new EmptyExternalProjectKeyAndOrganization());
     DefaultAnalysisMode mode = createmode(analysisProps);
 
     assertThat(mode.scanAllFiles()).isTrue();
@@ -55,7 +58,8 @@ public class DefaultAnalysisModeTest {
     when(globalMode.isIssues()).thenReturn(true);
     when(globalMode.isPublish()).thenReturn(true);
     when(globalMode.isPreview()).thenReturn(true);
-    DefaultAnalysisMode mode = createmode(new ScannerProperties(Collections.emptyMap()));
+    DefaultAnalysisMode mode = createmode(new ProcessedScannerProperties(
+      new RawScannerProperties(Collections.emptyMap()), new EmptyExternalProjectKeyAndOrganization()));
 
     assertThat(mode.isIssues()).isTrue();
     assertThat(mode.isPublish()).isTrue();
@@ -65,14 +69,16 @@ public class DefaultAnalysisModeTest {
   @Test
   public void scan_all_if_publish() {
     when(globalMode.isIssues()).thenReturn(false);
-    DefaultAnalysisMode mode = createmode(new ScannerProperties(Collections.emptyMap()));
+    DefaultAnalysisMode mode = createmode(new ProcessedScannerProperties(
+      new RawScannerProperties(Collections.emptyMap()), new EmptyExternalProjectKeyAndOrganization()));
 
     assertThat(mode.scanAllFiles()).isTrue();
   }
 
   @Test
   public void scan_all_if_property_set() {
-    ScannerProperties analysisProps = new ScannerProperties(Collections.singletonMap("sonar.scanAllFiles", "true"));
+    ProcessedScannerProperties analysisProps = new ProcessedScannerProperties(
+      new RawScannerProperties(Collections.singletonMap("sonar.scanAllFiles", "true")), new EmptyExternalProjectKeyAndOrganization());
     DefaultAnalysisMode mode = createmode(analysisProps);
 
     assertThat(mode.scanAllFiles()).isTrue();
@@ -81,12 +87,13 @@ public class DefaultAnalysisModeTest {
   @Test
   public void dont_scan_all_if_issues_mode() {
     when(globalMode.isIssues()).thenReturn(true);
-    DefaultAnalysisMode mode = createmode(new ScannerProperties(Collections.emptyMap()));
+    DefaultAnalysisMode mode = createmode(new ProcessedScannerProperties(
+      new RawScannerProperties(Collections.emptyMap()), new EmptyExternalProjectKeyAndOrganization()));
 
     assertThat(mode.scanAllFiles()).isFalse();
   }
 
-  private DefaultAnalysisMode createmode(ScannerProperties analysisProps) {
+  private DefaultAnalysisMode createmode(ProcessedScannerProperties analysisProps) {
     return new DefaultAnalysisMode(analysisProps, globalMode);
   }
 
index 306712ef9982e70363e03b9715fa5c32cc360575..bfcf46179d965ddf016e4d5dff33a2644953e0d5 100644 (file)
@@ -82,7 +82,7 @@ public class GlobalAnalysisModeTest {
     if (key != null) {
       map.put(key, value);
     }
-    ScannerProperties props = new ScannerProperties(map);
+    RawScannerProperties props = new RawScannerProperties(map);
     return new GlobalAnalysisMode(props);
   }
 }
index f81093cc676f9495e6e495a200ed381b6f85156a..1d5d057b300c2a70a8133d07bfa4007f4c2df344 100644 (file)
@@ -41,13 +41,12 @@ public class GlobalConfigurationProviderTest {
   public LogTester logTester = new LogTester();
 
   GlobalServerSettings globalServerSettings;
-  ScannerProperties scannerProps;
-
+  RawScannerProperties scannerProps;
 
   @Before
   public void prepare() {
     globalServerSettings = mock(GlobalServerSettings.class);
-    scannerProps = new ScannerProperties(Collections.<String, String>emptyMap());
+    scannerProps = new RawScannerProperties(Collections.emptyMap());
   }
 
   @Test
index b5f78a389eea9eecc99fa39a9d1fcea3861c7e97..416326c6e1d24a00f4a506d5a0f9b7cb6958e772 100644 (file)
@@ -30,6 +30,7 @@ import org.junit.rules.TemporaryFolder;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.ScannerSide;
 import org.sonar.api.utils.TempFolder;
+import org.sonar.batch.bootstrapper.EnvironmentInformation;
 import org.sonar.core.util.UuidFactory;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -49,7 +50,7 @@ public class GlobalContainerTest {
 
   @Test
   public void should_add_components() {
-    GlobalContainer container = createContainer(Collections.emptyList());
+    GlobalContainer container = createContainer(Collections.singletonList(new EnvironmentInformation("maven", "3.1.0")));
 
     assertThat(container.getComponentByType(UuidFactory.class)).isNotNull();
     assertThat(container.getComponentByType(TempFolder.class)).isNotNull();
index 3583ac85f34f43ae632870abce0fc1f6d44c2dbb..5de2170fd3c5a7392006239eb7729a0492b7ec32 100644 (file)
@@ -51,7 +51,8 @@ public class GlobalTempFolderProviderTest {
     File workingDir = temp.newFolder();
     workingDir.delete();
 
-    TempFolder tempFolder = tempFolderProvider.provide(new ScannerProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
+    TempFolder tempFolder = tempFolderProvider.provide(
+      new RawScannerProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
     tempFolder.newDir();
     tempFolder.newFile();
     assertThat(getCreatedTempDir(workingDir)).exists();
@@ -71,7 +72,8 @@ public class GlobalTempFolderProviderTest {
       setFileCreationDate(tmp, creationTime);
     }
 
-    tempFolderProvider.provide(new ScannerProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
+    tempFolderProvider.provide(
+      new RawScannerProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
     // this also checks that all other temps were deleted
     assertThat(getCreatedTempDir(workingDir)).exists();
 
@@ -84,7 +86,8 @@ public class GlobalTempFolderProviderTest {
     File sonarHome = temp.newFolder();
     File workingDir = new File(sonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE).getAbsoluteFile();
 
-    TempFolder tempFolder = tempFolderProvider.provide(new ScannerProperties(ImmutableMap.of("sonar.userHome", sonarHome.getAbsolutePath())));
+    TempFolder tempFolder = tempFolderProvider.provide(
+      new RawScannerProperties(ImmutableMap.of("sonar.userHome", sonarHome.getAbsolutePath())));
     tempFolder.newDir();
     tempFolder.newFile();
     assertThat(getCreatedTempDir(workingDir)).exists();
@@ -106,7 +109,8 @@ public class GlobalTempFolderProviderTest {
     File defaultSonarHome = new File(userHome.getAbsolutePath(), ".sonar");
     File workingDir = new File(defaultSonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE).getAbsoluteFile();
     try {
-      TempFolder tempFolder = tempFolderProvider.provide(new ScannerProperties(Collections.<String, String>emptyMap()));
+      TempFolder tempFolder = tempFolderProvider.provide(
+        new RawScannerProperties(Collections.emptyMap()));
       tempFolder.newDir();
       tempFolder.newFile();
       assertThat(getCreatedTempDir(workingDir)).exists();
@@ -120,8 +124,8 @@ public class GlobalTempFolderProviderTest {
   public void dotWorkingDir() throws IOException {
     File sonarHome = temp.getRoot();
     String globalWorkDir = ".";
-    ScannerProperties globalProperties = new ScannerProperties(ImmutableMap.of("sonar.userHome", sonarHome.getAbsolutePath(),
-      CoreProperties.GLOBAL_WORKING_DIRECTORY, globalWorkDir));
+    RawScannerProperties globalProperties = new RawScannerProperties(
+      ImmutableMap.of("sonar.userHome", sonarHome.getAbsolutePath(), CoreProperties.GLOBAL_WORKING_DIRECTORY, globalWorkDir));
 
     TempFolder tempFolder = tempFolderProvider.provide(globalProperties);
     File newFile = tempFolder.newFile();
@@ -136,7 +140,7 @@ public class GlobalTempFolderProviderTest {
     File symlink = temp.newFolder();
     symlink.delete();
     Files.createSymbolicLink(symlink.toPath(), realSonarHome.toPath());
-    ScannerProperties globalProperties = new ScannerProperties(ImmutableMap.of("sonar.userHome", symlink.getAbsolutePath()));
+    RawScannerProperties globalProperties = new RawScannerProperties(ImmutableMap.of("sonar.userHome", symlink.getAbsolutePath()));
 
     TempFolder tempFolder = tempFolderProvider.provide(globalProperties);
     File newFile = tempFolder.newFile();
index f63d60f14bb08c56789f07af382dea664e8aaa01..9a7ebb0e127221a8ed07851634b15717eb2f3e0b 100644 (file)
@@ -73,7 +73,7 @@ public class PluginFilesTest {
   @Before
   public void setUp() throws Exception {
     HttpConnector connector = HttpConnector.newBuilder().url(server.url("/").toString()).build();
-    GlobalAnalysisMode analysisMode = new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap()));
+    GlobalAnalysisMode analysisMode = new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()));
     ScannerWsClient wsClient = new ScannerWsClient(WsClientFactories.getDefault().newClient(connector), false, analysisMode);
 
     userHome = temp.newFolder();
@@ -311,13 +311,13 @@ public class PluginFilesTest {
   private File packAndUnpackJar(File source) throws IOException {
     File packed = temp.newFile();
     try (JarInputStream in = new JarInputStream(new BufferedInputStream(Files.newInputStream(source.toPath())));
-         OutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(packed.toPath())))) {
+      OutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(packed.toPath())))) {
       Pack200.newPacker().pack(in, out);
     }
 
     File to = temp.newFile();
     try (InputStream input = new GZIPInputStream(new BufferedInputStream(Files.newInputStream(packed.toPath())));
-         JarOutputStream output = new JarOutputStream(new BufferedOutputStream(Files.newOutputStream(to.toPath())))) {
+      JarOutputStream output = new JarOutputStream(new BufferedOutputStream(Files.newOutputStream(to.toPath())))) {
       Pack200.newUnpacker().unpack(input, output);
     } catch (IOException e) {
       throw new IllegalStateException(e);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ProcessedScannerPropertiesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ProcessedScannerPropertiesTest.java
new file mode 100644 (file)
index 0000000..95f3e02
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.bootstrap;
+
+import com.google.common.collect.Maps;
+import java.util.Map;
+import org.junit.Test;
+import org.sonar.scanner.scan.EmptyExternalProjectKeyAndOrganization;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+
+public class ProcessedScannerPropertiesTest {
+  @Test
+  public void test_copy_of_properties() {
+    Map<String, String> map = Maps.newHashMap();
+    map.put("foo", "bar");
+
+    ProcessedScannerProperties underTest = new ProcessedScannerProperties(
+      new RawScannerProperties(map),
+      new EmptyExternalProjectKeyAndOrganization());
+    assertThat(underTest.properties()).containsOnly(entry("foo", "bar"));
+    assertThat(underTest.properties()).isNotSameAs(map);
+
+    map.put("put", "after_copy");
+    assertThat(underTest.properties()).hasSize(1);
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerPropertiesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerPropertiesTest.java
deleted file mode 100644 (file)
index 670f0b0..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.scanner.bootstrap;
-
-import com.google.common.collect.Maps;
-import java.util.Map;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-
-public class ScannerPropertiesTest {
-  @Test
-  public void test_copy_of_properties() {
-    Map<String, String> map = Maps.newHashMap();
-    map.put("foo", "bar");
-
-    ScannerProperties underTest = new ScannerProperties(map);
-    assertThat(underTest.properties()).containsOnly(entry("foo", "bar"));
-    assertThat(underTest.properties()).isNotSameAs(map);
-
-    map.put("put", "after_copy");
-    assertThat(underTest.properties()).hasSize(1);
-  }
-}
index 9e4511cc48b7c11e7ade826fd64b3b372fbe5895..5122d6f23e1dbc83cbf62538754877d3796e2c88 100644 (file)
@@ -37,9 +37,9 @@ public class ScannerWsClientProviderTest {
 
   @Test
   public void provide_client_with_default_settings() {
-    ScannerProperties settings = new ScannerProperties(new HashMap<>());
+    RawScannerProperties settings = new RawScannerProperties(new HashMap<>());
 
-    ScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), mock(System2.class));
+    ScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), mock(System2.class));
 
     assertThat(client).isNotNull();
     assertThat(client.baseUrl()).isEqualTo("http://localhost:9000/");
@@ -57,9 +57,9 @@ public class ScannerWsClientProviderTest {
     props.put("sonar.login", "theLogin");
     props.put("sonar.password", "thePassword");
     props.put("sonar.ws.timeout", "42");
-    ScannerProperties settings = new ScannerProperties(props);
+    RawScannerProperties settings = new RawScannerProperties(props);
 
-    ScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), mock(System2.class));
+    ScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), mock(System2.class));
 
     assertThat(client).isNotNull();
     HttpConnector httpConnector = (HttpConnector) client.wsConnector();
@@ -71,9 +71,9 @@ public class ScannerWsClientProviderTest {
   public void build_singleton() {
     System2 system = mock(System2.class);
 
-    ScannerProperties settings = new ScannerProperties(new HashMap<>());
-    ScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
-    ScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
+    RawScannerProperties settings = new RawScannerProperties(new HashMap<>());
+    ScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), system);
+    ScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), system);
     assertThat(first).isSameAs(second);
   }
 }
index 9a9dfa0a9cd8c82c469d692cca93e8cfc37885ec..abe99ed2c15550f6ae4c65ef453cbda4f48ce286 100644 (file)
@@ -57,7 +57,8 @@ public class ScannerWsClientTest {
     when(wsClient.wsConnector().call(request)).thenReturn(response);
 
     logTester.setLevel(LoggerLevel.DEBUG);
-    ScannerWsClient underTest = new ScannerWsClient(wsClient, false, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())));
+    ScannerWsClient underTest = new ScannerWsClient(wsClient, false, new GlobalAnalysisMode(
+      new RawScannerProperties(Collections.emptyMap())));
 
     WsResponse result = underTest.call(request);
 
@@ -98,7 +99,7 @@ public class ScannerWsClientTest {
     WsResponse response = newResponse().setCode(401);
     when(wsClient.wsConnector().call(request)).thenReturn(response);
 
-    new ScannerWsClient(wsClient, false, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap()))).call(request);
+    new ScannerWsClient(wsClient, false, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
   }
 
   @Test
@@ -110,7 +111,7 @@ public class ScannerWsClientTest {
     WsResponse response = newResponse().setCode(401);
     when(wsClient.wsConnector().call(request)).thenReturn(response);
 
-    new ScannerWsClient(wsClient, /* credentials are configured */true, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap()))).call(request);
+    new ScannerWsClient(wsClient, /* credentials are configured */true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
   }
 
   @Test
@@ -123,7 +124,7 @@ public class ScannerWsClientTest {
       .setCode(403);
     when(wsClient.wsConnector().call(request)).thenReturn(response);
 
-    new ScannerWsClient(wsClient, true, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap()))).call(request);
+    new ScannerWsClient(wsClient, true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
   }
 
   @Test
@@ -137,7 +138,7 @@ public class ScannerWsClientTest {
       .setContent("{\"errors\":[{\"msg\":\"Boo! bad request! bad!\"}]}");
     when(wsClient.wsConnector().call(request)).thenReturn(response);
 
-    new ScannerWsClient(wsClient, true, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap()))).call(request);
+    new ScannerWsClient(wsClient, true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
   }
 
   private MockWsResponse newResponse() {
index 071f57834379214da5b097f2c860ae6829ff06e4..c2b1580ff1587faa20bbd152b74634bb7897a035 100644 (file)
@@ -29,7 +29,7 @@ import org.junit.ClassRule;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.CoreProperties;
 import org.sonar.scanner.bootstrap.GlobalTempFolderProvider;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.RawScannerProperties;
 import org.sonar.scanner.storage.Storages;
 import org.sonar.scanner.storage.StoragesManager;
 
@@ -44,7 +44,7 @@ public abstract class AbstractCachesTest {
     Map<String, String> props = ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, temp.getRoot().getAbsolutePath(),
       CoreProperties.GLOBAL_WORKING_DIRECTORY, temp.getRoot().getAbsolutePath());
 
-    return new StoragesManager(new GlobalTempFolderProvider().provide(new ScannerProperties(props)));
+    return new StoragesManager(new GlobalTempFolderProvider().provide(new RawScannerProperties(props)));
   }
 
   @BeforeClass
index 46f6e6ef7c052643750c98c3d1985d4dacdb730a..cbae1f9c0ba23a2231b575d6134179f1cc993386 100644 (file)
@@ -62,7 +62,8 @@ import org.sonar.scanner.repository.ProjectRepositoriesLoader;
 import org.sonar.scanner.repository.QualityProfileLoader;
 import org.sonar.scanner.repository.ServerIssuesLoader;
 import org.sonar.scanner.repository.SingleProjectRepository;
-import org.sonar.scanner.repository.settings.SettingsLoader;
+import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
+import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
 import org.sonar.scanner.rule.ActiveRulesLoader;
 import org.sonar.scanner.rule.LoadedActiveRule;
 import org.sonar.scanner.rule.RulesLoader;
@@ -89,7 +90,8 @@ public class ScannerMediumTester extends ExternalResource {
   private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader();
   private final FakePluginInstaller pluginInstaller = new FakePluginInstaller();
   private final FakeServerIssuesLoader serverIssues = new FakeServerIssuesLoader();
-  private final FakeSettingsLoader settingsLoader = new FakeSettingsLoader();
+  private final FakeGlobalSettingsLoader globalSettingsLoader = new FakeGlobalSettingsLoader();
+  private final FakeProjectSettingsLoader projectSettingsLoader = new FakeProjectSettingsLoader();
   private final FakeServerLineHashesLoader serverLineHashes = new FakeServerLineHashesLoader();
   private final FakeRulesLoader rulesLoader = new FakeRulesLoader();
   private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
@@ -230,12 +232,12 @@ public class ScannerMediumTester extends ExternalResource {
   }
 
   public ScannerMediumTester addGlobalServerSettings(String key, String value) {
-    settingsLoader.getGlobalSettings().put(key, value);
+    globalSettingsLoader.getGlobalSettings().put(key, value);
     return this;
   }
 
   public ScannerMediumTester addProjectServerSettings(String key, String value) {
-    settingsLoader.getProjectSettings().put(key, value);
+    projectSettingsLoader.getProjectSettings().put(key, value);
     return this;
   }
 
@@ -311,7 +313,8 @@ public class ScannerMediumTester extends ExternalResource {
           tester.projectRefProvider,
           tester.activeRules,
           tester.serverIssues,
-          tester.settingsLoader,
+          tester.globalSettingsLoader,
+          tester.projectSettingsLoader,
           result)
         .setLogOutput(tester.logOutput)
         .build().execute();
@@ -502,23 +505,27 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
-  private static class FakeSettingsLoader implements SettingsLoader {
+  private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {
 
     private Map<String, String> globalSettings = new HashMap<>();
-    private Map<String, String> projectSettings = new HashMap<>();
 
     public Map<String, String> getGlobalSettings() {
       return globalSettings;
     }
 
-    public Map<String, String> getProjectSettings() {
-      return projectSettings;
-    }
-
     @Override
     public Map<String, String> loadGlobalSettings() {
       return Collections.unmodifiableMap(globalSettings);
     }
+  }
+
+  private static class FakeProjectSettingsLoader implements ProjectSettingsLoader {
+
+    private Map<String, String> projectSettings = new HashMap<>();
+
+    public Map<String, String> getProjectSettings() {
+      return projectSettings;
+    }
 
     @Override
     public Map<String, String> loadProjectSettings() {
index ce9e0d393aeb280b2d82ef5b8c9ea477e2d34168..a38911bf11225242b5b8633fc5ee620902a11dfe 100644 (file)
@@ -31,18 +31,18 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.utils.MessageException;
 import org.sonar.batch.bootstrapper.Batch;
 import org.sonar.batch.bootstrapper.EnvironmentInformation;
-import org.sonar.scanner.repository.settings.SettingsLoader;
+import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
 
 public class ExceptionHandlingMediumTest {
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
   private Batch batch;
-  private static ErrorSettingsLoader loader;
+  private static ErrorGlobalSettingsLoader loader;
 
   @BeforeClass
   public static void beforeClass() {
-    loader = new ErrorSettingsLoader();
+    loader = new ErrorGlobalSettingsLoader();
   }
 
   public void setUp(boolean verbose) {
@@ -98,7 +98,7 @@ public class ExceptionHandlingMediumTest {
     batch.execute();
   }
 
-  private static class ErrorSettingsLoader implements SettingsLoader {
+  private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader {
     boolean withCause = false;
 
     @Override
@@ -110,10 +110,5 @@ public class ExceptionHandlingMediumTest {
         throw MessageException.of("Error loading settings");
       }
     }
-
-    @Override
-    public Map<String, String> loadProjectSettings() {
-      return null;
-    }
   }
 }
index 9af998d5ebded1aff1dd717e1d0ba1c9e53f63eb..fced08351f1f7483aa2577605bbf89c19f862f8a 100644 (file)
@@ -27,7 +27,7 @@ import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -45,7 +45,7 @@ public class ProjectRepositoriesProviderTest {
   @Mock
   private ProjectRepositoriesLoader loader;
   @Mock
-  private ScannerProperties props;
+  private ProcessedScannerProperties props;
   @Mock
   private GlobalAnalysisMode mode;
   @Mock
index 4ef1c77b08345217fbc9a3c6e0a8e39168f28e3b..77dddffefd377188494351da04625383b5305008 100644 (file)
@@ -31,7 +31,7 @@ import org.mockito.MockitoAnnotations;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.rule.QualityProfiles;
 import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
 
@@ -52,7 +52,7 @@ public class QualityProfileProviderTest {
   @Mock
   private QualityProfileLoader loader;
   @Mock
-  private ScannerProperties props;
+  private ProcessedScannerProperties props;
   @Mock
   private ProjectRepositories projectRepo;
 
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/AbstractSettingsLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/AbstractSettingsLoaderTest.java
new file mode 100644 (file)
index 0000000..19b999a
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import org.junit.Test;
+import org.sonarqube.ws.Settings.FieldValues;
+import org.sonarqube.ws.Settings.FieldValues.Value;
+import org.sonarqube.ws.Settings.FieldValues.Value.Builder;
+import org.sonarqube.ws.Settings.Setting;
+import org.sonarqube.ws.Settings.Values;
+
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+
+public class AbstractSettingsLoaderTest {
+
+  @Test
+  public void should_load_global_multivalue_settings() {
+    assertThat(AbstractSettingsLoader.toMap(singletonList(Setting.newBuilder()
+      .setKey("sonar.preview.supportedPlugins")
+      .setValues(Values.newBuilder().addValues("java").addValues("php")).build())))
+        .containsExactly(entry("sonar.preview.supportedPlugins", "java,php"));
+  }
+
+  @Test
+  public void should_escape_global_multivalue_settings() {
+    assertThat(AbstractSettingsLoader.toMap(singletonList(Setting.newBuilder()
+      .setKey("sonar.preview.supportedPlugins")
+      .setValues(Values.newBuilder().addValues("ja,va").addValues("p\"hp")).build())))
+        .containsExactly(entry("sonar.preview.supportedPlugins", "\"ja,va\",\"p\"\"hp\""));
+  }
+
+  @Test
+  public void should_load_global_propertyset_settings() {
+    Builder valuesBuilder = Value.newBuilder();
+    valuesBuilder.putValue("filepattern", "**/*.xml");
+    valuesBuilder.putValue("rulepattern", "*:S12345");
+    Value value1 = valuesBuilder.build();
+    valuesBuilder.clear();
+    valuesBuilder.putValue("filepattern", "**/*.java");
+    valuesBuilder.putValue("rulepattern", "*:S456");
+    Value value2 = valuesBuilder.build();
+
+    assertThat(AbstractSettingsLoader.toMap(singletonList(Setting.newBuilder()
+      .setKey("sonar.issue.exclusions.multicriteria")
+      .setFieldValues(FieldValues.newBuilder().addFieldValues(value1).addFieldValues(value2)).build())))
+        .containsOnly(entry("sonar.issue.exclusions.multicriteria", "1,2"),
+          entry("sonar.issue.exclusions.multicriteria.1.filepattern", "**/*.xml"),
+          entry("sonar.issue.exclusions.multicriteria.1.rulepattern", "*:S12345"),
+          entry("sonar.issue.exclusions.multicriteria.2.filepattern", "**/*.java"),
+          entry("sonar.issue.exclusions.multicriteria.2.rulepattern", "*:S456"));
+  }
+
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoaderTest.java
new file mode 100644 (file)
index 0000000..aff5f0f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import java.io.IOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Map;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonarqube.ws.Settings;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsResponse;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultGlobalSettingsLoaderTest {
+
+  private ScannerWsClient wsClient = mock(ScannerWsClient.class);
+  private DefaultGlobalSettingsLoader underTest = new DefaultGlobalSettingsLoader(wsClient);
+
+  @Test
+  public void loadGlobalSettings() throws IOException {
+    WsResponse response = mock(WsResponse.class);
+    PipedOutputStream out = new PipedOutputStream();
+    PipedInputStream in = new PipedInputStream(out);
+    Settings.ValuesWsResponse.newBuilder()
+      .addSettings(Settings.Setting.newBuilder()
+        .setKey("abc").setValue("def")
+        .build())
+      .addSettings(Settings.Setting.newBuilder()
+        .setKey("123").setValue("456")
+        .build())
+      .build()
+      .writeTo(out);
+    out.close();
+    when(response.contentStream()).thenReturn(in);
+    when(wsClient.call(any())).thenReturn(response);
+
+    Map<String, String> result = underTest.loadGlobalSettings();
+
+    ArgumentCaptor<GetRequest> argumentCaptor = ArgumentCaptor.forClass(GetRequest.class);
+    verify(wsClient, times(1)).call(argumentCaptor.capture());
+    assertThat(argumentCaptor.getValue().getPath()).isEqualTo("api/settings/values.protobuf");
+    assertThat(result).isNotNull();
+    assertThat(result).hasSize(2);
+    assertThat(result.get("abc")).isEqualTo("def");
+    assertThat(result.get("123")).isEqualTo("456");
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultProjectSettingsLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultProjectSettingsLoaderTest.java
new file mode 100644 (file)
index 0000000..a9163f5
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.repository.settings;
+
+import java.io.IOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Map;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
+import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonarqube.ws.Settings;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsResponse;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultProjectSettingsLoaderTest {
+
+  private ScannerWsClient wsClient = mock(org.sonar.scanner.bootstrap.ScannerWsClient.class);
+  private ProcessedScannerProperties properties = mock(ProcessedScannerProperties.class);
+  private DefaultProjectSettingsLoader underTest = new DefaultProjectSettingsLoader(wsClient, properties);
+
+  @Test
+  public void loadProjectSettings() throws IOException {
+    WsResponse response = mock(WsResponse.class);
+    PipedOutputStream out = new PipedOutputStream();
+    PipedInputStream in = new PipedInputStream(out);
+    Settings.ValuesWsResponse.newBuilder()
+      .addSettings(Settings.Setting.newBuilder()
+        .setKey("abc").setValue("def")
+        .build())
+      .addSettings(Settings.Setting.newBuilder()
+        .setKey("123").setValue("456")
+        .build())
+      .build()
+      .writeTo(out);
+    out.close();
+    when(response.contentStream()).thenReturn(in);
+    when(wsClient.call(any())).thenReturn(response);
+    when(properties.getKeyWithBranch()).thenReturn("project_key");
+
+    Map<String, String> result = underTest.loadProjectSettings();
+
+    ArgumentCaptor<GetRequest> argumentCaptor = ArgumentCaptor.forClass(GetRequest.class);
+    verify(wsClient, times(1)).call(argumentCaptor.capture());
+    assertThat(argumentCaptor.getValue().getPath()).isEqualTo("api/settings/values.protobuf?component=project_key");
+    assertThat(result).isNotNull();
+    assertThat(result).hasSize(2);
+    assertThat(result.get("abc")).isEqualTo("def");
+    assertThat(result.get("123")).isEqualTo("456");
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultSettingsLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/settings/DefaultSettingsLoaderTest.java
deleted file mode 100644 (file)
index 9797757..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.scanner.repository.settings;
-
-import org.junit.Test;
-import org.sonarqube.ws.Settings.FieldValues;
-import org.sonarqube.ws.Settings.FieldValues.Value;
-import org.sonarqube.ws.Settings.FieldValues.Value.Builder;
-import org.sonarqube.ws.Settings.Setting;
-import org.sonarqube.ws.Settings.Values;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-
-public class DefaultSettingsLoaderTest {
-
-  @Test
-  public void should_load_global_multivalue_settings() {
-    assertThat(DefaultSettingsLoader.toMap(asList(Setting.newBuilder()
-      .setKey("sonar.preview.supportedPlugins")
-      .setValues(Values.newBuilder().addValues("java").addValues("php")).build())))
-        .containsExactly(entry("sonar.preview.supportedPlugins", "java,php"));
-  }
-
-  @Test
-  public void should_escape_global_multivalue_settings() {
-    assertThat(DefaultSettingsLoader.toMap(asList(Setting.newBuilder()
-      .setKey("sonar.preview.supportedPlugins")
-      .setValues(Values.newBuilder().addValues("ja,va").addValues("p\"hp")).build())))
-        .containsExactly(entry("sonar.preview.supportedPlugins", "\"ja,va\",\"p\"\"hp\""));
-  }
-
-  @Test
-  public void should_load_global_propertyset_settings() {
-    Builder valuesBuilder = Value.newBuilder();
-    valuesBuilder.getMutableValue().put("filepattern", "**/*.xml");
-    valuesBuilder.getMutableValue().put("rulepattern", "*:S12345");
-    Value value1 = valuesBuilder.build();
-    valuesBuilder.clear();
-    valuesBuilder.getMutableValue().put("filepattern", "**/*.java");
-    valuesBuilder.getMutableValue().put("rulepattern", "*:S456");
-    Value value2 = valuesBuilder.build();
-
-    assertThat(DefaultSettingsLoader.toMap(asList(Setting.newBuilder()
-      .setKey("sonar.issue.exclusions.multicriteria")
-      .setFieldValues(FieldValues.newBuilder().addFieldValues(value1).addFieldValues(value2)).build())))
-        .containsOnly(entry("sonar.issue.exclusions.multicriteria", "1,2"),
-          entry("sonar.issue.exclusions.multicriteria.1.filepattern", "**/*.xml"),
-          entry("sonar.issue.exclusions.multicriteria.1.rulepattern", "*:S12345"),
-          entry("sonar.issue.exclusions.multicriteria.2.filepattern", "**/*.java"),
-          entry("sonar.issue.exclusions.multicriteria.2.rulepattern", "*:S456"));
-  }
-
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ExternalProjectKeyAndOrganizationProviderTest.java
new file mode 100644 (file)
index 0000000..028fa7a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.scanner.scan;
+
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.scanner.bootstrap.RawScannerProperties;
+
+import static java.util.Optional.of;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ExternalProjectKeyAndOrganizationProviderTest {
+
+  private ExternalProjectKeyAndOrganizationLoader loader = mock(ExternalProjectKeyAndOrganizationLoader.class);
+  private RawScannerProperties rawProperties = mock(RawScannerProperties.class);
+
+  private ExternalProjectKeyAndOrganizationProvider underTest = new ExternalProjectKeyAndOrganizationProvider();
+
+  @Before
+  public void setUp() {
+    when(loader.load()).thenReturn(of(new ExternalProjectKeyAndOrganization() {
+      @Override
+      public Optional<String> getProjectKey() {
+        return of("some_key");
+      }
+
+      @Override
+      public Optional<String> getOrganization() {
+        return of("organization_key");
+      }
+    }));
+  }
+
+  @Test
+  public void does_nothing_when_key_autodetection_is_disabled() {
+    when(rawProperties.property("sonar.keys_autodetection.disabled")).thenReturn("true");
+
+    ExternalProjectKeyAndOrganization result = underTest.provide(rawProperties, loader);
+
+    assertThat(result).isInstanceOf(EmptyExternalProjectKeyAndOrganization.class);
+  }
+
+  @Test
+  public void by_default_attempts_to_autodetect_keys_if_external_key_loader_detected() {
+    when(rawProperties.property("sonar.keys_autodetection.disabled")).thenReturn(null);
+
+    ExternalProjectKeyAndOrganization result = underTest.provide(rawProperties, loader);
+
+    assertThat(result).isNotInstanceOf(EmptyExternalProjectKeyAndOrganization.class);
+    assertThat(result.getProjectKey()).isEqualTo(of("some_key"));
+    assertThat(result.getOrganization()).isEqualTo(of("organization_key"));
+  }
+
+  @Test
+  public void by_default_does_nothing_when_no_external_key_loader_detected() {
+    when(rawProperties.property("sonar.keys_autodetection.disabled")).thenReturn(null);
+
+    ExternalProjectKeyAndOrganization result = underTest.provide(rawProperties, null);
+
+    assertThat(result).isInstanceOf(EmptyExternalProjectKeyAndOrganization.class);
+  }
+
+  @Test
+  public void attempts_to_autodetect_keys_if_autodection_is_explicitly_enabled() {
+    when(rawProperties.property("sonar.keys_autodetection.disabled")).thenReturn("false");
+
+    ExternalProjectKeyAndOrganization result = underTest.provide(rawProperties, loader);
+
+    assertThat(result).isNotInstanceOf(EmptyExternalProjectKeyAndOrganization.class);
+    assertThat(result.getProjectKey()).isEqualTo(of("some_key"));
+    assertThat(result.getOrganization()).isEqualTo(of("organization_key"));
+  }
+}
index ead72172d9cf17c7ef3ca553dba5eaa9cd7875b6..c9bd41df8e7b259c790396eb54f39b3a38b906a3 100644 (file)
@@ -38,7 +38,8 @@ import org.sonar.api.batch.bootstrap.ProjectReactor;
 import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.log.LogTester;
-import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.sonar.scanner.bootstrap.RawScannerProperties;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -401,19 +402,24 @@ public class ProjectReactorBuilderTest {
 
   @Test
   public void shouldInitRootWorkDir() {
-    ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(Maps.<String, String>newHashMap()), mock(AnalysisWarnings.class));
+    ProjectReactorBuilder builder = new ProjectReactorBuilder(new ProcessedScannerProperties(
+      new RawScannerProperties(Maps.newHashMap()), new EmptyExternalProjectKeyAndOrganization()),
+      mock(AnalysisWarnings.class));
     File baseDir = new File("target/tmp/baseDir");
 
-    File workDir = builder.initRootProjectWorkDir(baseDir, Maps.<String, String>newHashMap());
+    File workDir = builder.initRootProjectWorkDir(baseDir, Maps.newHashMap());
 
     assertThat(workDir).isEqualTo(new File(baseDir, ".sonar"));
   }
 
   @Test
   public void shouldInitWorkDirWithCustomRelativeFolder() {
-    Map<String, String> props = Maps.<String, String>newHashMap();
+    Map<String, String> props = Maps.newHashMap();
     props.put("sonar.working.directory", ".foo");
-    ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(props), mock(AnalysisWarnings.class));
+    ProjectReactorBuilder builder = new ProjectReactorBuilder(new ProcessedScannerProperties(
+      new RawScannerProperties(props),
+      new EmptyExternalProjectKeyAndOrganization()),
+      mock(AnalysisWarnings.class));
     File baseDir = new File("target/tmp/baseDir");
 
     File workDir = builder.initRootProjectWorkDir(baseDir, props);
@@ -423,9 +429,11 @@ public class ProjectReactorBuilderTest {
 
   @Test
   public void shouldInitRootWorkDirWithCustomAbsoluteFolder() {
-    Map<String, String> props = Maps.<String, String>newHashMap();
+    Map<String, String> props = Maps.newHashMap();
     props.put("sonar.working.directory", new File("src").getAbsolutePath());
-    ProjectReactorBuilder builder = new ProjectReactorBuilder(new ScannerProperties(props), mock(AnalysisWarnings.class));
+    ProjectReactorBuilder builder = new ProjectReactorBuilder(new ProcessedScannerProperties(
+      new RawScannerProperties(props), new EmptyExternalProjectKeyAndOrganization()),
+      mock(AnalysisWarnings.class));
     File baseDir = new File("target/tmp/baseDir");
 
     File workDir = builder.initRootProjectWorkDir(baseDir, props);
@@ -483,7 +491,9 @@ public class ProjectReactorBuilderTest {
 
   private ProjectDefinition loadProjectDefinition(String projectFolder) {
     Map<String, String> props = loadProps(projectFolder);
-    ScannerProperties bootstrapProps = new ScannerProperties(props);
+    ProcessedScannerProperties bootstrapProps = new ProcessedScannerProperties(
+      new RawScannerProperties(props),
+      new EmptyExternalProjectKeyAndOrganization());
     ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps, mock(AnalysisWarnings.class)).execute();
     return projectReactor.getRoot();
   }
@@ -503,7 +513,7 @@ public class ProjectReactorBuilderTest {
   }
 
   private Map<String, String> loadProps(String projectFolder) {
-    Map<String, String> props = Maps.<String, String>newHashMap();
+    Map<String, String> props = Maps.newHashMap();
     Properties runnerProps = toProperties(getResource(this.getClass(), projectFolder + "/sonar-project.properties"));
     for (final String name : runnerProps.stringPropertyNames()) {
       props.put(name, runnerProps.getProperty(name));
index 2062e35ec350695a513d2877ea0f85d19664fbde..4e8f705cb2c025b2a7d70d57b4212cd70daba075 100644 (file)
@@ -46,6 +46,8 @@ public class ProjectsWsParameters {
   public static final String PARAM_ON_PROVISIONED_ONLY = "onProvisionedOnly";
   public static final String PARAM_PROJECT_IDS = "projectIds";
   public static final String PARAM_PROJECTS = "projects";
+  public static final String PARAM_ALM_ID = "almId";
+  public static final String PARAM_ALM_REPOSITORY_ID = "almRepoId";
 
   public static final String FILTER_LANGUAGES = "languages";
   public static final String FILTER_TAGS = "tags";