]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-14525 include CI usage information in telemetry
authorMichal Duda <michal.duda@sonarsource.com>
Mon, 1 Mar 2021 16:48:43 +0000 (17:48 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 4 Mar 2021 20:12:49 +0000 (20:12 +0000)
35 files changed:
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisPropertiesStep.java
server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java
server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java
server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java
server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDataLoaderImpl.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ClusterSystemInfoWriterTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/StandaloneSystemInfoWriterTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java
sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationImpl.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/AppVeyor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/AwsCodeBuild.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/AzureDevops.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Bamboo.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/BitbucketPipelines.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Bitrise.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Buildkite.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/CircleCi.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/CirrusCi.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/DroneCi.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/GithubActions.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/GitlabCi.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Jenkins.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/SemaphoreCi.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/TravisCi.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/CiConfigurationImplTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/CiConfigurationProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/AwsCodeBuildTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/BambooTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/BitriseTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ContextPropertiesPublisherTest.java

index ec1055ff4b593c7d3f0c83a0f08f8ea15d80f2c7..633f2ff9e0191175e147f2adc7e9a2b2acf9794e 100644 (file)
  */
 package org.sonar.ce.task.projectanalysis.step;
 
+import com.google.common.collect.ImmutableSet;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
 import org.sonar.ce.task.step.ComputationStep;
@@ -32,6 +34,7 @@ import org.sonar.db.component.AnalysisPropertyDto;
 import org.sonar.scanner.protocol.output.ScannerReport;
 
 import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS;
+import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDCI;
 import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDSCM;
 
 /**
@@ -40,6 +43,7 @@ import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS_DETEC
 public class PersistAnalysisPropertiesStep implements ComputationStep {
 
   private static final String SONAR_PULL_REQUEST = "sonar.pullrequest.";
+  private static final Set<String> ANALYSIS_PROPERTIES_TO_PERSIST = ImmutableSet.of(SONAR_ANALYSIS_DETECTEDSCM, SONAR_ANALYSIS_DETECTEDCI);
 
   private final DbClient dbClient;
   private final AnalysisMetadataHolder analysisMetadataHolder;
@@ -61,7 +65,8 @@ public class PersistAnalysisPropertiesStep implements ComputationStep {
       it.forEachRemaining(
         contextProperty -> {
           String propertyKey = contextProperty.getKey();
-          if (propertyKey.startsWith(SONAR_ANALYSIS) || propertyKey.startsWith(SONAR_PULL_REQUEST) || SONAR_ANALYSIS_DETECTEDSCM.equals(propertyKey)) {
+          if (propertyKey.startsWith(SONAR_ANALYSIS) || propertyKey.startsWith(SONAR_PULL_REQUEST) ||
+            ANALYSIS_PROPERTIES_TO_PERSIST.contains(propertyKey)) {
             analysisPropertyDtos.add(new AnalysisPropertyDto()
               .setUuid(uuidFactory.create())
               .setKey(propertyKey)
index a6d51d11204a556ab50757dd8ff51e1923f744b0..6859da51a36dd5658ec04f6933803128e0b89003 100644 (file)
@@ -44,6 +44,7 @@ public class TelemetryData {
   private final Map<String, Long> nclocByLanguage;
   private final List<String> externalAuthenticationProviders;
   private final Map<String, Long> projectCountByScm;
+  private final Map<String, Long> projectCountByCi;
   private final EditionProvider.Edition edition;
   private final String licenseType;
   private final Long installationDate;
@@ -77,6 +78,7 @@ public class TelemetryData {
     customSecurityConfigs = builder.customSecurityConfigs == null ? emptyList() : builder.customSecurityConfigs;
     externalAuthenticationProviders = builder.externalAuthenticationProviders;
     projectCountByScm = builder.projectCountByScm;
+    projectCountByCi = builder.projectCountByCi;
   }
 
   public String getServerId() {
@@ -167,6 +169,10 @@ public class TelemetryData {
     return projectCountByScm;
   }
 
+  public Map<String, Long> getProjectCountByCi() {
+    return projectCountByCi;
+  }
+
   static Builder builder() {
     return new Builder();
   }
@@ -192,7 +198,7 @@ public class TelemetryData {
     private List<String> customSecurityConfigs;
     private List<String> externalAuthenticationProviders;
     private Map<String, Long> projectCountByScm;
-
+    private Map<String, Long> projectCountByCi;
 
     private Builder() {
       // enforce static factory method
@@ -213,6 +219,11 @@ public class TelemetryData {
       return this;
     }
 
+    Builder setProjectCountByCi(Map<String, Long> projectCountByCi) {
+      this.projectCountByCi = projectCountByCi;
+      return this;
+    }
+
     Builder setServerId(String serverId) {
       this.serverId = serverId;
       return this;
@@ -309,6 +320,7 @@ public class TelemetryData {
       requireNonNull(usingBranches);
       requireNonNull(externalAuthenticationProviders);
       requireNonNull(projectCountByScm);
+      requireNonNull(projectCountByCi);
 
       return new TelemetryData(this);
     }
index f427f0c5e28840c465f1ca2082bc8e001a68d4cf..94d6f78c751a2f23896eb2578843bbcecf5beb07 100644 (file)
@@ -95,17 +95,11 @@ public class TelemetryDataJsonWriter {
     statistics.getExternalAuthenticationProviders().forEach(json::value);
     json.endArray();
 
-    json.name("projectCountByScm");
-    json.beginArray();
-    statistics.getProjectCountByScm().forEach((scm, count) -> {
-      json.beginObject();
-      json.prop("scm", scm);
-      json.prop(COUNT, count);
-      json.endObject();
-    });
-    json.endArray();
+    addScmInfo(json, statistics);
+    addCiInfo(json, statistics);
 
     json.prop("sonarlintWeeklyUsers", statistics.sonarlintWeeklyUsers());
+
     if (statistics.getInstallationDate() != null) {
       json.prop("installationDate", statistics.getInstallationDate());
     }
@@ -115,4 +109,28 @@ public class TelemetryDataJsonWriter {
     json.prop("docker", statistics.isInDocker());
     json.endObject();
   }
+
+  private static void addScmInfo(JsonWriter json, TelemetryData statistics) {
+    json.name("projectCountByScm");
+    json.beginArray();
+    statistics.getProjectCountByScm().forEach((scm, count) -> {
+      json.beginObject();
+      json.prop("scm", scm);
+      json.prop(COUNT, count);
+      json.endObject();
+    });
+    json.endArray();
+  }
+
+  private static void addCiInfo(JsonWriter json, TelemetryData statistics) {
+    json.name("projectCountByCI");
+    json.beginArray();
+    statistics.getProjectCountByCi().forEach((ci, count) -> {
+      json.beginObject();
+      json.prop("ci", ci);
+      json.prop(COUNT, count);
+      json.endObject();
+    });
+    json.endArray();
+  }
 }
index 2b0c918d9c5b3010e965276c29b1f3edb0336bbf..f1d55c74abfed2d281ad6c7739c29390140a213f 100644 (file)
@@ -60,6 +60,7 @@ public class TelemetryDataJsonWriterTest {
     .setExternalAuthenticationProviders(asList("github", "gitlab"))
     .setProjectCountByScm(Collections.emptyMap())
     .setSonarlintWeeklyUsers(10)
+    .setProjectCountByCi(Collections.emptyMap())
     .setDatabase(new TelemetryData.Database("H2", "11"))
     .setUsingBranches(true);
 
@@ -244,6 +245,23 @@ public class TelemetryDataJsonWriterTest {
       + "]}");
   }
 
+  @Test
+  public void write_project_count_by_ci() {
+    TelemetryData data = SOME_TELEMETRY_DATA
+      .setProjectCountByCi(ImmutableMap.of("Bitbucket Pipelines", 5L, "Github Actions", 4L, "Jenkins", 3L, "undetected", 2L))
+      .build();
+
+    String json = writeTelemetryData(data);
+
+    assertJson(json).isSimilarTo("{" +
+      "  \"projectCountByCI\": ["
+      + "{ \"ci\":\"Bitbucket Pipelines\", \"count\":5},"
+      + "{ \"ci\":\"Github Actions\", \"count\":4},"
+      + "{ \"ci\":\"Jenkins\", \"count\":3},"
+      + "{ \"ci\":\"undetected\", \"count\":2},"
+      + "]}");
+  }
+
   @Test
   public void write_project_stats_by_language() {
     int projectCount = random.nextInt(8909);
index 16354f7b35907577723beb43ac27f951c7bc11f8..8d26cb3300c99dd4847dda4b16109c1d5017210d 100644 (file)
@@ -139,12 +139,9 @@ public class TelemetryDataLoaderImpl implements TelemetryDataLoader {
 
       data.setAlmIntegrationCountByAlm(countAlmUsage(dbSession));
       data.setExternalAuthenticationProviders(dbClient.userDao().selectExternalIdentityProviders(dbSession));
-      Map<String, Long> projectCountPerScmDetected = dbClient.analysisPropertiesDao()
-        .selectProjectCountPerAnalysisPropertyValueInLastAnalysis(dbSession, CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDSCM)
-        .stream()
-        .collect(Collectors.toMap(ProjectCountPerAnalysisPropertyValue::getPropertyValue, ProjectCountPerAnalysisPropertyValue::getCount));
-      data.setProjectCountByScm(projectCountPerScmDetected);
       data.setSonarlintWeeklyUsers(dbClient.userDao().countSonarlintWeeklyUsers(dbSession));
+      addScmInformationToTelemetry(dbSession, data);
+      addCiInformationToTelemetry(dbSession, data);
     }
 
     setSecurityCustomConfigIfPresent(data);
@@ -174,6 +171,22 @@ public class TelemetryDataLoaderImpl implements TelemetryDataLoader {
       });
   }
 
+  private void addScmInformationToTelemetry(DbSession dbSession, TelemetryData.Builder data) {
+    Map<String, Long> projectCountPerScmDetected = dbClient.analysisPropertiesDao()
+      .selectProjectCountPerAnalysisPropertyValueInLastAnalysis(dbSession, CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDSCM)
+      .stream()
+      .collect(Collectors.toMap(ProjectCountPerAnalysisPropertyValue::getPropertyValue, ProjectCountPerAnalysisPropertyValue::getCount));
+    data.setProjectCountByScm(projectCountPerScmDetected);
+  }
+
+  private void addCiInformationToTelemetry(DbSession dbSession, TelemetryData.Builder data) {
+    Map<String, Long> projectCountPerCiDetected = dbClient.analysisPropertiesDao()
+      .selectProjectCountPerAnalysisPropertyValueInLastAnalysis(dbSession, CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDCI)
+      .stream()
+      .collect(Collectors.toMap(ProjectCountPerAnalysisPropertyValue::getPropertyValue, ProjectCountPerAnalysisPropertyValue::getCount));
+    data.setProjectCountByCi(projectCountPerCiDetected);
+  }
+
   private Map<String, Long> countAlmUsage(DbSession dbSession) {
     return dbClient.almSettingDao().selectAll(dbSession).stream()
       .collect(Collectors.groupingBy(almSettingDto -> {
index e22bbe0cd20ce99be30bf6b41894618ee8f8442c..f90cb0dba9d19984e33db95fbf6fc78365050c63 100644 (file)
@@ -74,8 +74,8 @@ public class ClusterSystemInfoWriterTest {
       + "\"Search Nodes\":[{\"Name\":\"searchNodes\",\"\":{\"name\":\"searchNodes\"}}],"
       + "\"Statistics\":{\"id\":\"\",\"version\":\"\",\"database\":{\"name\":\"\",\"version\":\"\"},\"plugins\":[],"
       + "\"userCount\":0,\"projectCount\":0,\"usingBranches\":false,\"ncloc\":0,\"projectCountByLanguage\":[],"
-      + "\"nclocByLanguage\":[],\"almIntegrationCount\":[],\"externalAuthProviders\":[],\"projectCountByScm\":[],\"sonarlintWeeklyUsers\":0,\"installationDate\":0,"
-      + "\"installationVersion\":\"\",\"docker\":false}}");
+      + "\"nclocByLanguage\":[],\"almIntegrationCount\":[],\"externalAuthProviders\":[],\"projectCountByScm\":[],\"projectCountByCI\":[],\"sonarlintWeeklyUsers\":0,"
+      + "\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
   }
 
   private static NodeInfo createNodeInfo(String name) {
index d9e68091ae125a22ebaa36ef8f0ed6b5c709eb45..bd893c90327d8a1530816c3b42b89b1002caba0a 100644 (file)
@@ -81,7 +81,7 @@ public class StandaloneSystemInfoWriterTest {
     assertThat(writer).hasToString("{\"Health\":\"GREEN\",\"Health Causes\":[],\"Section One\":{\"foo\":\"bar\"},\"Section Two\":{\"one\":1,\"two\":2}," +
       "\"Statistics\":{\"id\":\"\",\"version\":\"\",\"database\":{\"name\":\"\",\"version\":\"\"},\"plugins\":[],\"userCount\":0,\"projectCount\":0,\"usingBranches\":false," +
       "\"ncloc\":0,\"projectCountByLanguage\":[],\"nclocByLanguage\":[],\"almIntegrationCount\":[],\"externalAuthProviders\":[],\"projectCountByScm\":[],"
-      + "\"sonarlintWeeklyUsers\":0,\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
+      + "\"projectCountByCI\":[],\"sonarlintWeeklyUsers\":0,\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
   }
 
   private void logInAsSystemAdministrator() {
index ccf32d6732760b92c5ab38108d387ff1c9d5354f..4d643f91ac8fa57d69cee00da2aa958efaafcc04 100644 (file)
@@ -68,6 +68,7 @@ public class TelemetryDaemonTest {
     .setAlmIntegrationCountByAlm(Collections.emptyMap())
     .setExternalAuthenticationProviders(singletonList("github"))
     .setProjectCountByScm(Collections.emptyMap())
+    .setProjectCountByCi(Collections.emptyMap())
     .setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
       .setProjectCount(12)
       .setProjectCountByLanguage(Collections.emptyMap())
index 58162ad28b6a81ef5b362c7034e72c004075f1f3..7e75d6957081b411719144c2058b4a3df865ead0 100644 (file)
@@ -35,6 +35,7 @@ public class CorePropertyDefinitions {
 
   public static final String SONAR_ANALYSIS = "sonar.analysis.";
   public static final String SONAR_ANALYSIS_DETECTEDSCM = "sonar.analysis.detectedscm";
+  public static final String SONAR_ANALYSIS_DETECTEDCI = "sonar.analysis.detectedci";
 
   private static final String CATEGORY_ORGANIZATIONS = "organizations";
 
index 8b8ee783a7d71664527c4e446c1171e20b975528..5b57c38015fa50783f6bb4663fc435c52e1e0388 100644 (file)
@@ -28,6 +28,11 @@ import java.util.Optional;
  */
 public interface CiConfiguration {
 
+  /**
+   * Name of the CI environment
+   */
+  String getCiName();
+
   /**
    * The revision that triggered the analysis. It should
    * be the revision as seen by end-user, but not the necessarily
index f7baa5741f52f55e0f51c9bb7dc7acd7f7bd9c27..9ac6bd865731270d77038019333e15ec623c438c 100644 (file)
@@ -25,16 +25,23 @@ import javax.annotation.Nullable;
 import static org.apache.commons.lang.StringUtils.defaultIfBlank;
 
 public class CiConfigurationImpl implements CiConfiguration {
+  private final String ciName;
 
   @Nullable
   private final String scmRevision;
 
-  public CiConfigurationImpl(@Nullable String scmRevision) {
+  public CiConfigurationImpl(@Nullable String scmRevision, String ciName) {
     this.scmRevision = defaultIfBlank(scmRevision, null);
+    this.ciName = ciName;
   }
 
   @Override
   public Optional<String> getScmRevision() {
     return Optional.ofNullable(scmRevision);
   }
+
+  @Override
+  public String getCiName() {
+    return ciName;
+  }
 }
index be8f5c1f84dcb0513abd69699f1783de9aa5c1cd..ea84fbcb9184b87619aba8279b454329aa421b87 100644 (file)
@@ -57,10 +57,15 @@ public class CiConfigurationProvider extends ProviderAdapter {
     return new EmptyCiConfiguration();
   }
 
-  private static class EmptyCiConfiguration implements CiConfiguration {
+  static class EmptyCiConfiguration implements CiConfiguration {
     @Override
     public Optional<String> getScmRevision() {
       return Optional.empty();
     }
+
+    @Override
+    public String getCiName() {
+      return "undetected";
+    }
   }
 }
index 2444e4475faca46c5ec49d6f196e146c18f25877..863221c7b6e9e7e3ac2a3a8f7956190d41340663 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.scanner.ci.CiVendor;
 
 /**
  * Support of https://www.appveyor.com
- *
+ * <p>
  * Environment variables: https://www.appveyor.com/docs/environment-variables/
  */
 public class AppVeyor implements CiVendor {
@@ -50,6 +50,6 @@ public class AppVeyor implements CiVendor {
   @Override
   public CiConfiguration loadConfiguration() {
     String revision = system.envVariable("APPVEYOR_REPO_COMMIT");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/AwsCodeBuild.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/AwsCodeBuild.java
new file mode 100644 (file)
index 0000000..5f57825
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.ci.vendors;
+
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.ci.CiConfiguration;
+import org.sonar.scanner.ci.CiConfigurationImpl;
+import org.sonar.scanner.ci.CiVendor;
+
+public class AwsCodeBuild implements CiVendor {
+  private final System2 system;
+
+  public AwsCodeBuild(System2 system) {
+    this.system = system;
+  }
+
+  @Override
+  public String getName() {
+    return "AwsCodeBuild";
+  }
+
+
+  @Override
+  public boolean isDetected() {
+    return environmentVariableIsPresent("CODEBUILD_BUILD_ID") &&
+      environmentVariableIsPresent("CODEBUILD_START_TIME");
+  }
+
+  @Override
+  public CiConfiguration loadConfiguration() {
+    return new CiConfigurationImpl(null, getName());
+  }
+
+  private boolean environmentVariableIsPresent(String key) {
+    return system.envVariable(key) != null;
+  }
+}
index 3610691fbdb49171351da3006c63f2885b976097..0e2d2b0969730e800078c5a9e5487e8c043b6e24 100644 (file)
@@ -28,7 +28,7 @@ import static org.apache.commons.lang.StringUtils.isBlank;
 
 /**
  * Support of https://azure.microsoft.com/en-us/services/devops/
- *
+ * <p>
  * Environment variables: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables
  */
 public class AzureDevops implements CiVendor {
@@ -55,6 +55,6 @@ public class AzureDevops implements CiVendor {
     if (isBlank(revision)) {
       revision = system.envVariable("BUILD_SOURCEVERSION");
     }
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Bamboo.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Bamboo.java
new file mode 100644 (file)
index 0000000..98e856d
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.ci.vendors;
+
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.ci.CiConfiguration;
+import org.sonar.scanner.ci.CiConfigurationImpl;
+import org.sonar.scanner.ci.CiVendor;
+
+public class Bamboo implements CiVendor {
+  private final System2 system;
+
+  public Bamboo(System2 system) {
+    this.system = system;
+  }
+
+  @Override
+  public String getName() {
+    return "Bamboo";
+  }
+
+
+  @Override
+  public boolean isDetected() {
+    return system.envVariable("bamboo_buildNumber") != null;
+  }
+
+  @Override
+  public CiConfiguration loadConfiguration() {
+    String revision = system.envVariable("bamboo_planRepository_revision");
+    return new CiConfigurationImpl(revision, getName());
+  }
+}
index c4f96476ce7e43cb6dd19dcb148634be0d80c537..798166a8102473757b58d823d0504b84db04b3ad 100644 (file)
@@ -49,6 +49,6 @@ public class BitbucketPipelines implements CiVendor {
   @Override
   public CiConfiguration loadConfiguration() {
     String revision = system.envVariable("BITBUCKET_COMMIT");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Bitrise.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/vendors/Bitrise.java
new file mode 100644 (file)
index 0000000..9fec71f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.ci.vendors;
+
+import java.util.Optional;
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.ci.CiConfiguration;
+import org.sonar.scanner.ci.CiConfigurationImpl;
+import org.sonar.scanner.ci.CiVendor;
+
+public class Bitrise implements CiVendor {
+
+  private final System2 system2;
+
+  public Bitrise(System2 system2) {
+    this.system2 = system2;
+  }
+
+  @Override
+  public String getName() {
+    return "Bitrise";
+  }
+
+  @Override
+  public boolean isDetected() {
+    return environmentVariableIsTrue("CI") && environmentVariableIsTrue("BITRISE_IO");
+  }
+
+  @Override
+  public CiConfiguration loadConfiguration() {
+    String revision = system2.envVariable("BITRISE_GIT_COMMIT");
+    return new CiConfigurationImpl(revision, getName());
+  }
+
+  private boolean environmentVariableIsTrue(String key) {
+    return Optional.ofNullable(system2.envVariable(key))
+      .map(Boolean::parseBoolean)
+      .orElse(false);
+  }
+}
index c230293ec1935d3a1be6555bfccb0ae478a9260c..4f6105e1e19da8251dafb6b778a2140ee463aa6d 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.scanner.ci.CiVendor;
 
 /**
  * Support of https://buildkite.com
- *
+ * <p>
  * Environment variables: https://buildkite.com/docs/pipelines/environment-variables
  */
 public class Buildkite implements CiVendor {
@@ -50,6 +50,6 @@ public class Buildkite implements CiVendor {
   @Override
   public CiConfiguration loadConfiguration() {
     String revision = system.envVariable("BUILDKITE_COMMIT");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index c67807851adb6b8602c5f44078f7d3a70cda4b95..0070768b6f64494c4238b6bcc12795f39bbe1547 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.scanner.ci.CiVendor;
 
 /**
  * Support of https://circleci.com
- *
+ * <p>
  * Environment variables: https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables
  */
 public class CircleCi implements CiVendor {
@@ -50,6 +50,6 @@ public class CircleCi implements CiVendor {
   @Override
   public CiConfiguration loadConfiguration() {
     String revision = system.envVariable("CIRCLE_SHA1");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index 1b252d0581c8640a17fefc27e880a42919740c0c..e794a2eb10243ebb249c02170d22aa3dbcd4a2d1 100644 (file)
@@ -29,7 +29,7 @@ import static org.apache.commons.lang.StringUtils.isEmpty;
 
 /**
  * Support https://cirrus-ci.org/
- *
+ * <p>
  * Environment variables are documented at https://cirrus-ci.org/guide/writing-tasks/#environment-variables
  */
 public class CirrusCi implements CiVendor {
@@ -57,6 +57,6 @@ public class CirrusCi implements CiVendor {
     if (isEmpty(revision)) {
       Loggers.get(getClass()).warn("Missing environment variable " + PROPERTY_COMMIT);
     }
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index a4ccc6e31dfa77a506c95f6c3de77e3dbe5c2900..53b84bff6abbec13c000a279809ecd484f599659 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.scanner.ci.CiVendor;
 
 /**
  * Support https://drone.io
- *
+ * <p>
  * Environment variables are documented at https://docs.drone.io/reference/environ/
  */
 public class DroneCi implements CiVendor {
@@ -49,6 +49,6 @@ public class DroneCi implements CiVendor {
   @Override
   public CiConfiguration loadConfiguration() {
     String revision = system.envVariable("DRONE_COMMIT_SHA");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index de9d81460b52a976271a14442051c3ea9f891035..e0c5940abaa64f8c6f830dde43841b2282ae4d04 100644 (file)
@@ -30,7 +30,7 @@ import static org.apache.commons.lang.StringUtils.isEmpty;
 
 /**
  * Support of https://github.com/features/actions
- *
+ * <p>
  * Environment variables: https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#environment-variables
  */
 public class GithubActions implements CiVendor {
@@ -59,6 +59,6 @@ public class GithubActions implements CiVendor {
     if (isEmpty(revision)) {
       Loggers.get(getClass()).warn("Missing environment variable " + PROPERTY_COMMIT);
     }
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index 68b860cd71750f66912d49a5ef8ce71dd06c4f0e..995af3afba898587ac37b5a24575774533731724 100644 (file)
@@ -47,6 +47,6 @@ public class GitlabCi implements CiVendor {
   @Override
   public CiConfiguration loadConfiguration() {
     String revision = system.envVariable("CI_COMMIT_SHA");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index db3d61727dd0aa5592d91688bcf68e7c632a0daf..2581809f79e249606da7626779153679198b4ef2 100644 (file)
@@ -62,7 +62,7 @@ public class Jenkins implements CiVendor {
     // https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project
     String revision = system.envVariable("ghprbActualCommit");
     if (StringUtils.isNotBlank(revision)) {
-      return new CiConfigurationImpl(revision);
+      return new CiConfigurationImpl(revision, getName());
     }
 
     revision = system.envVariable("GIT_COMMIT");
@@ -71,14 +71,14 @@ public class Jenkins implements CiVendor {
       if (StringUtils.isNotBlank(system.envVariable("CHANGE_ID"))) {
         String jenkinsGitPrSha1 = getJenkinsGitPrSha1();
         if (StringUtils.isNotBlank(jenkinsGitPrSha1)) {
-          return new CiConfigurationImpl(jenkinsGitPrSha1);
+          return new CiConfigurationImpl(jenkinsGitPrSha1, getName());
         }
       }
-      return new CiConfigurationImpl(revision);
+      return new CiConfigurationImpl(revision, getName());
     }
 
     revision = system.envVariable("SVN_COMMIT");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 
   private String getJenkinsGitPrSha1() {
index 94b178ec62683f6199a1f4618c3d8fc65f191082..d94289970366bda7556134fc168e2538e1476c99 100644 (file)
@@ -49,6 +49,6 @@ public class SemaphoreCi implements CiVendor {
   @Override
   public CiConfiguration loadConfiguration() {
     String revision = system.envVariable("SEMAPHORE_GIT_SHA");
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index 63027665b61b2ae365093ed9ea2b7b4a4715fed0..8b24d0d33b56ec2680d701104221b542535fb5f9 100644 (file)
@@ -28,7 +28,7 @@ import static org.apache.commons.lang.StringUtils.isBlank;
 
 /**
  * Support of https://travis-ci.com
- *
+ * <p>
  * Environment variables: https://docs.travis-ci.com/user/environment-variables/
  */
 public class TravisCi implements CiVendor {
@@ -58,6 +58,6 @@ public class TravisCi implements CiVendor {
       revision = system.envVariable("TRAVIS_PULL_REQUEST_SHA");
 
     }
-    return new CiConfigurationImpl(revision);
+    return new CiConfigurationImpl(revision, getName());
   }
 }
index 0c8e49da4d7b2a4b40aed12ebbdb9b1d98fdf1a4..525d3c6d8f8e895d0bca5c21a6b21f41a5fc06db 100644 (file)
 package org.sonar.scanner.report;
 
 import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
-import java.util.function.Function;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import javax.annotation.Nonnull;
 import org.sonar.api.batch.scm.ScmProvider;
 import org.sonar.core.config.CorePropertyDefinitions;
+import org.sonar.scanner.ci.CiConfiguration;
 import org.sonar.scanner.config.DefaultConfiguration;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
 import org.sonar.scanner.repository.ContextPropertiesCache;
 import org.sonar.scanner.scm.ScmConfiguration;
 
+import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDCI;
 import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDSCM;
 
 public class ContextPropertiesPublisher implements ReportPublisherStep {
   private final ContextPropertiesCache cache;
   private final DefaultConfiguration config;
   private final ScmConfiguration scmConfiguration;
+  private final CiConfiguration ciConfiguration;
 
-  public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration) {
+  public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration,
+                                    CiConfiguration ciConfiguration) {
     this.cache = cache;
     this.config = config;
     this.scmConfiguration = scmConfiguration;
+    this.ciConfiguration = ciConfiguration;
   }
 
   @Override
   public void publish(ScannerReportWriter writer) {
-    MapEntryToContextPropertyFunction transformer = new MapEntryToContextPropertyFunction();
-
-    // properties defined programmatically by plugins
-    Stream<ScannerReport.ContextProperty> fromCache = Stream.concat(cache.getAll().entrySet().stream(), Stream.of(constructScmInfo())).map(transformer);
-
+    List<Map.Entry<String, String>> properties = new ArrayList<>(cache.getAll().entrySet());
+    properties.add(constructScmInfo());
+    properties.add(constructCiInfo());
     // properties that are automatically included to report so that
     // they can be included to webhook payloads
-    Stream<ScannerReport.ContextProperty> fromSettings = config.getProperties().entrySet().stream()
+    properties.addAll(config.getProperties().entrySet()
+      .stream()
       .filter(e -> e.getKey().startsWith(CorePropertyDefinitions.SONAR_ANALYSIS))
-      .map(transformer);
+      .collect(Collectors.toList()));
 
-    writer.writeContextProperties(Stream.concat(fromCache, fromSettings).collect(Collectors.toList()));
+    writer.writeContextProperties(properties
+      .stream()
+      .map(e -> ScannerReport.ContextProperty.newBuilder()
+        .setKey(e.getKey())
+        .setValue(e.getValue())
+        .build())
+      .collect(Collectors.toList()));
   }
 
   private Map.Entry<String, String> constructScmInfo() {
@@ -71,12 +80,7 @@ public class ContextPropertiesPublisher implements ReportPublisherStep {
     }
   }
 
-  private static final class MapEntryToContextPropertyFunction implements Function<Map.Entry<String, String>, ScannerReport.ContextProperty> {
-    private final ScannerReport.ContextProperty.Builder builder = ScannerReport.ContextProperty.newBuilder();
-
-    @Override
-    public ScannerReport.ContextProperty apply(@Nonnull Map.Entry<String, String> input) {
-      return builder.clear().setKey(input.getKey()).setValue(input.getValue()).build();
-    }
+  private Map.Entry<String, String> constructCiInfo() {
+    return new AbstractMap.SimpleEntry<>(SONAR_ANALYSIS_DETECTEDCI, ciConfiguration.getCiName());
   }
 }
index 8ee1267d4d00ec913972231ac95f66a612dc9ad3..300d15568d94c1fc86021ca68697259557756899 100644 (file)
@@ -46,8 +46,11 @@ import org.sonar.scanner.bootstrap.MetricProvider;
 import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
 import org.sonar.scanner.ci.CiConfigurationProvider;
 import org.sonar.scanner.ci.vendors.AppVeyor;
+import org.sonar.scanner.ci.vendors.AwsCodeBuild;
 import org.sonar.scanner.ci.vendors.AzureDevops;
+import org.sonar.scanner.ci.vendors.Bamboo;
 import org.sonar.scanner.ci.vendors.BitbucketPipelines;
+import org.sonar.scanner.ci.vendors.Bitrise;
 import org.sonar.scanner.ci.vendors.Buildkite;
 import org.sonar.scanner.ci.vendors.CircleCi;
 import org.sonar.scanner.ci.vendors.CirrusCi;
@@ -286,8 +289,11 @@ public class ProjectScanContainer extends ComponentContainer {
       // CI
       new CiConfigurationProvider(),
       AppVeyor.class,
+      AwsCodeBuild.class,
       AzureDevops.class,
+      Bamboo.class,
       BitbucketPipelines.class,
+      Bitrise.class,
       Buildkite.class,
       CircleCi.class,
       CirrusCi.class,
index 2dec59543366777835fb277abb4831669e01d73d..4eb8a6e13a938a62de9ef3f7ec9ded770e231fb6 100644 (file)
@@ -27,9 +27,19 @@ public class CiConfigurationImplTest {
 
   @Test
   public void getScmRevision() {
-    assertThat(new CiConfigurationImpl(null).getScmRevision()).isEmpty();
-    assertThat(new CiConfigurationImpl("").getScmRevision()).isEmpty();
-    assertThat(new CiConfigurationImpl("   ").getScmRevision()).isEmpty();
-    assertThat(new CiConfigurationImpl("a7bdf2d").getScmRevision()).hasValue("a7bdf2d");
+    assertThat(new CiConfigurationImpl(null, "test").getScmRevision()).isEmpty();
+    assertThat(new CiConfigurationImpl("", "test").getScmRevision()).isEmpty();
+    assertThat(new CiConfigurationImpl("   ", "test").getScmRevision()).isEmpty();
+    assertThat(new CiConfigurationImpl("a7bdf2d", "test").getScmRevision()).hasValue("a7bdf2d");
+  }
+
+  @Test
+  public void getNam_for_undetected_ci() {
+    assertThat(new CiConfigurationProvider.EmptyCiConfiguration().getCiName()).isEqualTo("undetected");
+  }
+
+  @Test
+  public void getName_for_detected_ci() {
+    assertThat(new CiConfigurationImpl(null, "test").getCiName()).isEqualTo("test");
   }
 }
index b99ff8374992978961b0a915dc10a97532706ec8..e980d53de974187cf4dbb9a8975623ca6a0a7096 100644 (file)
@@ -28,8 +28,8 @@ import static org.assertj.core.api.Assertions.catchThrowable;
 
 public class CiConfigurationProviderTest {
 
-  private MapSettings cli = new MapSettings();
-  private CiConfigurationProvider underTest = new CiConfigurationProvider();
+  private final MapSettings cli = new MapSettings();
+  private final CiConfigurationProvider underTest = new CiConfigurationProvider();
 
   @Test
   public void empty_configuration_if_no_ci_vendors() {
@@ -40,21 +40,21 @@ public class CiConfigurationProviderTest {
 
   @Test
   public void empty_configuration_if_no_ci_detected() {
-    CiConfiguration ciConfiguration = underTest.provide(cli.asConfig(), new CiVendor[] {new DisabledCiVendor("vendor1"), new DisabledCiVendor("vendor2")});
+    CiConfiguration ciConfiguration = underTest.provide(cli.asConfig(), new CiVendor[]{new DisabledCiVendor("vendor1"), new DisabledCiVendor("vendor2")});
 
     assertThat(ciConfiguration.getScmRevision()).isEmpty();
   }
 
   @Test
   public void configuration_defined_by_ci_vendor() {
-    CiConfiguration ciConfiguration = underTest.provide(cli.asConfig(), new CiVendor[] {new DisabledCiVendor("vendor1"), new EnabledCiVendor("vendor2")});
+    CiConfiguration ciConfiguration = underTest.provide(cli.asConfig(), new CiVendor[]{new DisabledCiVendor("vendor1"), new EnabledCiVendor("vendor2")});
 
     assertThat(ciConfiguration.getScmRevision()).hasValue(EnabledCiVendor.SHA);
   }
 
   @Test
   public void fail_if_multiple_ci_vendor_are_detected() {
-    Throwable thrown = catchThrowable(() -> underTest.provide(cli.asConfig(), new CiVendor[] {new EnabledCiVendor("vendor1"), new EnabledCiVendor("vendor2")}));
+    Throwable thrown = catchThrowable(() -> underTest.provide(cli.asConfig(), new CiVendor[]{new EnabledCiVendor("vendor1"), new EnabledCiVendor("vendor2")}));
 
     assertThat(thrown)
       .isInstanceOf(MessageException.class)
@@ -64,7 +64,7 @@ public class CiConfigurationProviderTest {
   @Test
   public void empty_configuration_if_auto_configuration_is_disabled() {
     cli.setProperty("sonar.ci.autoconfig.disabled", true);
-    CiConfiguration ciConfiguration = underTest.provide(cli.asConfig(), new CiVendor[] {new EnabledCiVendor("vendor1")});
+    CiConfiguration ciConfiguration = underTest.provide(cli.asConfig(), new CiVendor[]{new EnabledCiVendor("vendor1")});
 
     assertThat(ciConfiguration.getScmRevision()).isEmpty();
   }
@@ -112,7 +112,7 @@ public class CiConfigurationProviderTest {
 
     @Override
     public CiConfiguration loadConfiguration() {
-      return new CiConfigurationImpl(SHA);
+      return new CiConfigurationImpl(SHA, name);
     }
   }
 }
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/AwsCodeBuildTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/AwsCodeBuildTest.java
new file mode 100644 (file)
index 0000000..f9094a3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.ci.vendors;
+
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.ci.CiVendor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AwsCodeBuildTest {
+
+  private final System2 system = mock(System2.class);
+  private final CiVendor underTest = new AwsCodeBuild(system);
+
+  @Test
+  public void getName() {
+    assertThat(underTest.getName()).isEqualTo("AwsCodeBuild");
+  }
+
+  @Test
+  public void isDetected() {
+    assertThat(underTest.isDetected()).isFalse();
+
+    setEnvVariable("CODEBUILD_BUILD_ID", "51");
+    assertThat(underTest.isDetected()).isFalse();
+
+    setEnvVariable("CODEBUILD_BUILD_ID", "52");
+    setEnvVariable("CODEBUILD_START_TIME", "some-time");
+    assertThat(underTest.isDetected()).isTrue();
+  }
+
+  @Test
+  public void loadConfiguration() {
+    setEnvVariable("CODEBUILD_BUILD_ID", "51");
+    setEnvVariable("CODEBUILD_START_TIME", "some-time");
+
+    assertThat(underTest.loadConfiguration().getScmRevision()).isEmpty();
+  }
+
+  private void setEnvVariable(String key, @Nullable String value) {
+    when(system.envVariable(key)).thenReturn(value);
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/BambooTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/BambooTest.java
new file mode 100644 (file)
index 0000000..330b538
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.ci.vendors;
+
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.ci.CiVendor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BambooTest {
+
+  private final System2 system = mock(System2.class);
+  private final CiVendor underTest = new Bamboo(system);
+
+  @Test
+  public void getName() {
+    assertThat(underTest.getName()).isEqualTo("Bamboo");
+  }
+
+  @Test
+  public void isDetected() {
+    assertThat(underTest.isDetected()).isFalse();
+
+    setEnvVariable("bamboo_buildNumber", "41");
+    assertThat(underTest.isDetected()).isTrue();
+  }
+
+  @Test
+  public void loadConfiguration() {
+    setEnvVariable("bamboo_buildNumber", "41");
+    setEnvVariable("bamboo_planRepository_revision", "42109719-93c9-4d47-9d7c-b3b0b87b6985");
+
+    assertThat(underTest.loadConfiguration().getScmRevision()).hasValue("42109719-93c9-4d47-9d7c-b3b0b87b6985");
+  }
+
+  private void setEnvVariable(String key, @Nullable String value) {
+    when(system.envVariable(key)).thenReturn(value);
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/BitriseTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/ci/vendors/BitriseTest.java
new file mode 100644 (file)
index 0000000..b804408
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.ci.vendors;
+
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.ci.CiVendor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BitriseTest {
+
+  private final System2 system = mock(System2.class);
+  private final CiVendor underTest = new Bitrise(system);
+
+  @Test
+  public void getName() {
+    assertThat(underTest.getName()).isEqualTo("Bitrise");
+  }
+
+  @Test
+  public void isDetected() {
+
+    assertThat(underTest.isDetected()).isFalse();
+
+    setEnvVariable("CI", "true");
+    assertThat(underTest.isDetected()).isFalse();
+
+    setEnvVariable("CI", "true");
+    setEnvVariable("BITRISE_IO", "false");
+    assertThat(underTest.isDetected()).isFalse();
+
+    setEnvVariable("CI", "true");
+    setEnvVariable("BITRISE_IO", "true");
+    assertThat(underTest.isDetected()).isTrue();
+  }
+
+  @Test
+  public void loadConfiguration() {
+    setEnvVariable("CI", "true");
+    setEnvVariable("BITRISE_IO", "true");
+    setEnvVariable("BITRISE_GIT_COMMIT", "abd12fc");
+
+    assertThat(underTest.loadConfiguration().getScmRevision()).hasValue("abd12fc");
+  }
+
+  private void setEnvVariable(String key, @Nullable String value) {
+    when(system.envVariable(key)).thenReturn(value);
+  }
+}
index db450a00657bdad9c868c6702898eeb22e5d4012..0dd340f5b3fdd287337696f54e7e2f5160630639 100644 (file)
@@ -25,9 +25,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
+import org.sonar.scanner.ci.CiConfiguration;
 import org.sonar.scanner.config.DefaultConfiguration;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
@@ -40,19 +39,18 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 public class ContextPropertiesPublisherTest {
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
   private final ScannerReportWriter writer = mock(ScannerReportWriter.class);
   private final ContextPropertiesCache cache = new ContextPropertiesCache();
   private final DefaultConfiguration config = mock(DefaultConfiguration.class);
   private final Map<String, String> props = new HashMap<>();
   private final ScmConfiguration scmConfiguration = mock(ScmConfiguration.class);
-  private final ContextPropertiesPublisher underTest = new ContextPropertiesPublisher(cache, config, scmConfiguration);
+  private final CiConfiguration ciConfiguration = mock(CiConfiguration.class);
+  private final ContextPropertiesPublisher underTest = new ContextPropertiesPublisher(cache, config, scmConfiguration, ciConfiguration);
 
   @Before
   public void prepareMock() {
     when(config.getProperties()).thenReturn(props);
+    when(ciConfiguration.getCiName()).thenReturn("undetected");
   }
 
   @Test
@@ -65,7 +63,8 @@ public class ContextPropertiesPublisherTest {
     List<ScannerReport.ContextProperty> expected = Arrays.asList(
       newContextProperty("foo1", "bar1"),
       newContextProperty("foo2", "bar2"),
-      newContextProperty("sonar.analysis.detectedscm", "undetected"));
+      newContextProperty("sonar.analysis.detectedscm", "undetected"),
+      newContextProperty("sonar.analysis.detectedci", "undetected"));
     expectWritten(expected);
   }
 
@@ -80,7 +79,8 @@ public class ContextPropertiesPublisherTest {
     List<ScannerReport.ContextProperty> expected = Arrays.asList(
       newContextProperty("sonar.analysis.revision", "ab45b3"),
       newContextProperty("sonar.analysis.build.number", "B123"),
-      newContextProperty("sonar.analysis.detectedscm", "undetected"));
+      newContextProperty("sonar.analysis.detectedscm", "undetected"),
+      newContextProperty("sonar.analysis.detectedci", "undetected"));
     expectWritten(expected);
   }