aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisPropertiesStep.java6
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java2
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java4
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java2
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/ProjectCountPerAnalysisPropertyValue.java45
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml12
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java32
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java14
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java16
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java23
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDataLoaderImpl.java14
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ClusterSystemInfoWriterTest.java18
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/platform/StandaloneSystemInfoWriterTest.java20
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java15
-rw-r--r--sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java1
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java21
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ContextPropertiesPublisherTest.java26
17 files changed, 214 insertions, 57 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisPropertiesStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisPropertiesStep.java
index aa74407325d..ec1055ff4b5 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisPropertiesStep.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisPropertiesStep.java
@@ -32,10 +32,10 @@ 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_DETECTEDSCM;
/**
* Persist analysis properties
- * Only properties starting with "sonar.analysis" or "sonar.pullrequest" will be persisted in database
*/
public class PersistAnalysisPropertiesStep implements ComputationStep {
@@ -47,7 +47,7 @@ public class PersistAnalysisPropertiesStep implements ComputationStep {
private final UuidFactory uuidFactory;
public PersistAnalysisPropertiesStep(DbClient dbClient, AnalysisMetadataHolder analysisMetadataHolder,
- BatchReportReader reportReader, UuidFactory uuidFactory) {
+ BatchReportReader reportReader, UuidFactory uuidFactory) {
this.dbClient = dbClient;
this.analysisMetadataHolder = analysisMetadataHolder;
this.reportReader = reportReader;
@@ -61,7 +61,7 @@ public class PersistAnalysisPropertiesStep implements ComputationStep {
it.forEachRemaining(
contextProperty -> {
String propertyKey = contextProperty.getKey();
- if (propertyKey.startsWith(SONAR_ANALYSIS) || propertyKey.startsWith(SONAR_PULL_REQUEST)) {
+ if (propertyKey.startsWith(SONAR_ANALYSIS) || propertyKey.startsWith(SONAR_PULL_REQUEST) || SONAR_ANALYSIS_DETECTEDSCM.equals(propertyKey)) {
analysisPropertyDtos.add(new AnalysisPropertyDto()
.setUuid(uuidFactory.create())
.setKey(propertyKey)
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
index f25e7820ece..58239037854 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
@@ -54,6 +54,7 @@ import org.sonar.db.component.ComponentMapper;
import org.sonar.db.component.ComponentWithModuleUuidDto;
import org.sonar.db.component.FilePathWithHashDto;
import org.sonar.db.component.KeyWithUuidDto;
+import org.sonar.db.component.ProjectCountPerAnalysisPropertyValue;
import org.sonar.db.component.ProjectLinkMapper;
import org.sonar.db.component.ResourceDto;
import org.sonar.db.component.ScrapAnalysisPropertyDto;
@@ -197,6 +198,7 @@ public class MyBatis implements Startable {
confBuilder.loadAlias("PrIssue", PrIssueDto.class);
confBuilder.loadAlias("ProjectQgateAssociation", ProjectQgateAssociationDto.class);
confBuilder.loadAlias("Project", ProjectDto.class);
+ confBuilder.loadAlias("ProjectCountPerAnalysisPropertyValue", ProjectCountPerAnalysisPropertyValue.class);
confBuilder.loadAlias("ProjectMapping", ProjectMappingDto.class);
confBuilder.loadAlias("PurgeableAnalysis", PurgeableAnalysisDto.class);
confBuilder.loadAlias("QualityGateCondition", QualityGateConditionDto.class);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java
index 83c5698b07f..c40ad31952f 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesDao.java
@@ -63,6 +63,10 @@ public class AnalysisPropertiesDao implements Dao {
}
}
+ public List<ProjectCountPerAnalysisPropertyValue> selectProjectCountPerAnalysisPropertyValueInLastAnalysis(DbSession session, String analysisPropertyKey) {
+ return getMapper(session).selectProjectCountPerAnalysisPropertyValueInLastAnalysis(analysisPropertyKey);
+ }
+
private static boolean mustBeStoredInClob(String value) {
return value.length() > VARCHAR_MAXSIZE;
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java
index fef92d58c06..19080f1413b 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/AnalysisPropertiesMapper.java
@@ -31,4 +31,6 @@ public interface AnalysisPropertiesMapper {
void insertAsClob(@Param("analysisPropertyDto") AnalysisPropertyDto analysisPropertyDto, @Param("createdAt") long createdAt);
void insertAsText(@Param("analysisPropertyDto") AnalysisPropertyDto analysisPropertyDto, @Param("createdAt") long createdAt);
+
+ List<ProjectCountPerAnalysisPropertyValue> selectProjectCountPerAnalysisPropertyValueInLastAnalysis(@Param("analysisPropertyKey") String analysisPropertyKey);
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ProjectCountPerAnalysisPropertyValue.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ProjectCountPerAnalysisPropertyValue.java
new file mode 100644
index 00000000000..bdc7055da8c
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ProjectCountPerAnalysisPropertyValue.java
@@ -0,0 +1,45 @@
+/*
+ * 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.db.component;
+
+public class ProjectCountPerAnalysisPropertyValue {
+ private String propertyValue;
+ private Long count;
+
+ public ProjectCountPerAnalysisPropertyValue() {
+ //nothing to do here
+ }
+
+ public String getPropertyValue() {
+ return propertyValue;
+ }
+
+ public void setPropertyValue(String propertyValue) {
+ this.propertyValue = propertyValue;
+ }
+
+ public Long getCount() {
+ return count;
+ }
+
+ public void setCount(Long count) {
+ this.count = count;
+ }
+}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml
index 865f072c2b1..124b27aad3d 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/AnalysisPropertiesMapper.xml
@@ -21,6 +21,18 @@
analysis_uuid = #{analysisUuid}
</select>
+ <select id="selectProjectCountPerAnalysisPropertyValueInLastAnalysis" parameterType="string" resultType="ProjectCountPerAnalysisPropertyValue">
+ select
+ ap.text_value as "propertyValue",
+ count(ap.text_value) as "count"
+ from components cp
+ inner join snapshots s on s.component_uuid = cp.uuid
+ inner join analysis_properties ap on ap.analysis_uuid = s.uuid
+ where
+ s.islast = ${_true} and ap.kee = #{analysisPropertyKey, jdbcType=VARCHAR}
+ group by ap.text_value
+ </select>
+
<insert id="insertAsEmpty" parameterType="map" useGeneratedKeys="false">
INSERT INTO analysis_properties (
uuid,
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java
index 616aa844389..9d49dcecb89 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/AnalysisPropertiesDaoTest.java
@@ -25,13 +25,15 @@ import java.util.Random;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
import org.sonar.api.impl.utils.TestSystem2;
+import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.project.ProjectDto;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.tuple;
public class AnalysisPropertiesDaoTest {
private static final long NOW = 1_000L;
@@ -159,6 +161,32 @@ public class AnalysisPropertiesDaoTest {
assertThat(result).containsExactlyInAnyOrder(propertyDtos.toArray(new AnalysisPropertyDto[0]));
}
+ @Test
+ public void selectProjectCountPerAnalysisPropertyValueInLastAnalysis_should_return_correct_values() {
+ final String analysisPropertyKey = "key";
+ for (int i = 0; i < 7; i++) {
+ final int index = i;
+ ProjectDto project = dbTester.components().insertPrivateProjectDto();
+ dbTester.components().insertSnapshot(project, s -> s.setLast(true).setUuid("uuid" + index));
+ }
+ underTest.insert(dbSession, new AnalysisPropertyDto().setKey(analysisPropertyKey).setValue("git").setAnalysisUuid("uuid0").setUuid("0"));
+ underTest.insert(dbSession, new AnalysisPropertyDto().setKey(analysisPropertyKey).setValue("svn").setAnalysisUuid("uuid1").setUuid("1"));
+ underTest.insert(dbSession, new AnalysisPropertyDto().setKey(analysisPropertyKey).setValue("undetected").setAnalysisUuid("uuid2").setUuid("2"));
+ underTest.insert(dbSession, new AnalysisPropertyDto().setKey(analysisPropertyKey).setValue("undetected").setAnalysisUuid("uuid3").setUuid("3"));
+ underTest.insert(dbSession, new AnalysisPropertyDto().setKey(analysisPropertyKey).setValue("git").setAnalysisUuid("uuid4").setUuid("4"));
+ underTest.insert(dbSession, new AnalysisPropertyDto().setKey(analysisPropertyKey).setValue("git").setAnalysisUuid("uuid5").setUuid("5"));
+
+ List<ProjectCountPerAnalysisPropertyValue> result = underTest.selectProjectCountPerAnalysisPropertyValueInLastAnalysis(dbSession, analysisPropertyKey);
+
+ assertThat(result)
+ .extracting(ProjectCountPerAnalysisPropertyValue::getPropertyValue, ProjectCountPerAnalysisPropertyValue::getCount)
+ .containsExactlyInAnyOrder(
+ tuple("git", 3L),
+ tuple("svn", 1L),
+ tuple("undetected", 2L)
+ );
+ }
+
private AnalysisPropertyDto insertAnalysisPropertyDto(int valueLength) {
AnalysisPropertyDto analysisPropertyDto = newAnalysisPropertyDto(valueLength, randomAlphanumeric(40));
underTest.insert(dbSession, analysisPropertyDto);
@@ -171,7 +199,7 @@ public class AnalysisPropertiesDaoTest {
.setKey(randomAlphanumeric(512))
.setUuid(randomAlphanumeric(40))
.setValue(randomAlphanumeric(valueLength))
- .setCreatedAt( 1_000L);
+ .setCreatedAt(1_000L);
}
private void compareFirstValueWith(AnalysisPropertyDto analysisPropertyDto) {
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java
index 4710e3f9d75..b625d1aead5 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java
@@ -43,6 +43,7 @@ public class TelemetryData {
private final Map<String, Long> almIntegrationCountByAlm;
private final Map<String, Long> nclocByLanguage;
private final List<String> externalAuthenticationProviders;
+ private final Map<String, Long> projectCountByScm;
private final EditionProvider.Edition edition;
private final String licenseType;
private final Long installationDate;
@@ -73,6 +74,7 @@ public class TelemetryData {
hasUnanalyzedCpp = builder.hasUnanalyzedCpp;
customSecurityConfigs = builder.customSecurityConfigs == null ? emptyList() : builder.customSecurityConfigs;
externalAuthenticationProviders = builder.externalAuthenticationProviders;
+ projectCountByScm = builder.projectCountByScm;
}
public String getServerId() {
@@ -155,6 +157,10 @@ public class TelemetryData {
return externalAuthenticationProviders;
}
+ public Map<String, Long> getProjectCountByScm() {
+ return projectCountByScm;
+ }
+
static Builder builder() {
return new Builder();
}
@@ -178,6 +184,8 @@ public class TelemetryData {
private Boolean hasUnanalyzedCpp;
private List<String> customSecurityConfigs;
private List<String> externalAuthenticationProviders;
+ private Map<String, Long> projectCountByScm;
+
private Builder() {
// enforce static factory method
@@ -188,6 +196,11 @@ public class TelemetryData {
return this;
}
+ Builder setProjectCountByScm(Map<String, Long> projectCountByScm) {
+ this.projectCountByScm = projectCountByScm;
+ return this;
+ }
+
Builder setServerId(String serverId) {
this.serverId = serverId;
return this;
@@ -283,6 +296,7 @@ public class TelemetryData {
requireNonNull(database);
requireNonNull(usingBranches);
requireNonNull(externalAuthenticationProviders);
+ requireNonNull(projectCountByScm);
return new TelemetryData(this);
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java
index 17366c51ebe..e675e1dc101 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java
@@ -26,6 +26,8 @@ import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
public class TelemetryDataJsonWriter {
+ public static final String COUNT = "count";
+
public void writeTelemetryData(JsonWriter json, TelemetryData statistics) {
json.beginObject();
json.prop("id", statistics.getServerId());
@@ -55,7 +57,7 @@ public class TelemetryDataJsonWriter {
statistics.getProjectCountByLanguage().forEach((language, count) -> {
json.beginObject();
json.prop("language", language);
- json.prop("count", count);
+ json.prop(COUNT, count);
json.endObject();
});
json.endArray();
@@ -73,7 +75,7 @@ public class TelemetryDataJsonWriter {
statistics.getAlmIntegrationCountByAlm().forEach((alm, count) -> {
json.beginObject();
json.prop("alm", alm);
- json.prop("count", count);
+ json.prop(COUNT, count);
json.endObject();
});
json.endArray();
@@ -93,6 +95,16 @@ 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();
+
if (statistics.getInstallationDate() != null) {
json.prop("installationDate", statistics.getInstallationDate());
}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java
index 141e4b57198..ca3e14f774c 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java
@@ -37,6 +37,7 @@ import org.sonar.core.platform.EditionProvider;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.server.measure.index.ProjectMeasuresStatistics;
+import static java.util.Arrays.asList;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
@@ -56,7 +57,8 @@ public class TelemetryDataJsonWriterTest {
.setNclocByLanguage(Collections.emptyMap())
.build())
.setNcloc(42L)
- .setExternalAuthenticationProviders(Arrays.asList("github", "gitlab"))
+ .setExternalAuthenticationProviders(asList("github", "gitlab"))
+ .setProjectCountByScm(Collections.emptyMap())
.setDatabase(new TelemetryData.Database("H2", "11"))
.setUsingBranches(true);
@@ -216,6 +218,23 @@ public class TelemetryDataJsonWriterTest {
}
@Test
+ public void write_project_count_by_scm() {
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setProjectCountByScm(ImmutableMap.of("git", 5L, "svn", 4L, "cvs", 3L, "undetected", 2L))
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"projectCountByScm\": ["
+ + "{ \"scm\":\"git\", \"count\":5},"
+ + "{ \"scm\":\"svn\", \"count\":4},"
+ + "{ \"scm\":\"cvs\", \"count\":3},"
+ + "{ \"scm\":\"undetected\", \"count\":2},"
+ + "]}");
+ }
+
+ @Test
public void write_project_stats_by_language() {
int projectCount = random.nextInt(8909);
Map<String, Long> countByLanguage = IntStream.range(0, 1 + random.nextInt(10))
@@ -368,7 +387,7 @@ public class TelemetryDataJsonWriterTest {
@DataProvider
public static Object[][] allEditions() {
return Arrays.stream(EditionProvider.Edition.values())
- .map(t -> new Object[] {t})
+ .map(t -> new Object[]{t})
.toArray(Object[][]::new);
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDataLoaderImpl.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDataLoaderImpl.java
index 266a6db942a..c944b32e857 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDataLoaderImpl.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDataLoaderImpl.java
@@ -32,6 +32,7 @@ import javax.annotation.Nullable;
import org.sonar.api.config.Configuration;
import org.sonar.api.platform.Server;
import org.sonar.api.server.ServerSide;
+import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
@@ -40,6 +41,7 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.alm.setting.ALM;
import org.sonar.db.alm.setting.AlmSettingDto;
+import org.sonar.db.component.ProjectCountPerAnalysisPropertyValue;
import org.sonar.db.measure.SumNclocDbQuery;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.measure.index.ProjectMeasuresIndex;
@@ -74,13 +76,13 @@ public class TelemetryDataLoaderImpl implements TelemetryDataLoader {
private final LicenseReader licenseReader;
public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
- PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration, DockerSupport dockerSupport) {
+ PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration, DockerSupport dockerSupport) {
this(server, dbClient, pluginRepository, userIndex, projectMeasuresIndex, editionProvider, internalProperties, configuration, dockerSupport, null);
}
public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
- PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration,
- DockerSupport dockerSupport, @Nullable LicenseReader licenseReader) {
+ PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration,
+ DockerSupport dockerSupport, @Nullable LicenseReader licenseReader) {
this.server = server;
this.dbClient = dbClient;
this.pluginRepository = pluginRepository;
@@ -137,7 +139,11 @@ 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);
}
setSecurityCustomConfigIfPresent(data);
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ClusterSystemInfoWriterTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ClusterSystemInfoWriterTest.java
index f3096ecfe32..560e4461f19 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ClusterSystemInfoWriterTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ClusterSystemInfoWriterTest.java
@@ -42,13 +42,13 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ClusterSystemInfoWriterTest {
- private GlobalInfoLoader globalInfoLoader = mock(GlobalInfoLoader.class);
- private AppNodesInfoLoader appNodesInfoLoader = mock(AppNodesInfoLoader.class);
- private SearchNodesInfoLoader searchNodesInfoLoader = mock(SearchNodesInfoLoader.class);
- private HealthChecker healthChecker = mock(HealthChecker.class);
- private TelemetryDataLoader telemetry = mock(TelemetryDataLoader.class, Mockito.RETURNS_MOCKS);
- private TelemetryDataJsonWriter dataJsonWriter = new TelemetryDataJsonWriter();
- private ClusterSystemInfoWriter underTest = new ClusterSystemInfoWriter(globalInfoLoader, appNodesInfoLoader,
+ private final GlobalInfoLoader globalInfoLoader = mock(GlobalInfoLoader.class);
+ private final AppNodesInfoLoader appNodesInfoLoader = mock(AppNodesInfoLoader.class);
+ private final SearchNodesInfoLoader searchNodesInfoLoader = mock(SearchNodesInfoLoader.class);
+ private final HealthChecker healthChecker = mock(HealthChecker.class);
+ private final TelemetryDataLoader telemetry = mock(TelemetryDataLoader.class, Mockito.RETURNS_MOCKS);
+ private final TelemetryDataJsonWriter dataJsonWriter = new TelemetryDataJsonWriter();
+ private final ClusterSystemInfoWriter underTest = new ClusterSystemInfoWriter(globalInfoLoader, appNodesInfoLoader,
searchNodesInfoLoader, healthChecker, telemetry, dataJsonWriter);
@Before
@@ -68,13 +68,13 @@ public class ClusterSystemInfoWriterTest {
underTest.write(jsonWriter);
jsonWriter.endObject();
- assertThat(writer.toString()).isEqualTo("{\"Health\":\"GREEN\","
+ assertThat(writer).hasToString("{\"Health\":\"GREEN\","
+ "\"Health Causes\":[],\"\":{\"name\":\"globalInfo\"},"
+ "\"Application Nodes\":[{\"Name\":\"appNodes\",\"\":{\"name\":\"appNodes\"}}],"
+ "\"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\":[],\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
+ "\"nclocByLanguage\":[],\"almIntegrationCount\":[],\"externalAuthProviders\":[],\"projectCountByScm\":[],\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
}
private static NodeInfo createNodeInfo(String name) {
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/StandaloneSystemInfoWriterTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/StandaloneSystemInfoWriterTest.java
index a7e99d4f402..c22757e9e81 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/StandaloneSystemInfoWriterTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/StandaloneSystemInfoWriterTest.java
@@ -48,14 +48,13 @@ public class StandaloneSystemInfoWriterTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private SystemInfoSection section1 = mock(SystemInfoSection.class);
- private SystemInfoSection section2 = mock(SystemInfoSection.class);
- private CeHttpClient ceHttpClient = mock(CeHttpClientImpl.class, Mockito.RETURNS_MOCKS);
- private TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker();
- private TelemetryDataLoader telemetry = mock(TelemetryDataLoader.class, Mockito.RETURNS_MOCKS);
- private TelemetryDataJsonWriter dataJsonWriter = new TelemetryDataJsonWriter();
-
- private StandaloneSystemInfoWriter underTest = new StandaloneSystemInfoWriter(telemetry, ceHttpClient, healthChecker, dataJsonWriter, section1, section2);
+ private final SystemInfoSection section1 = mock(SystemInfoSection.class);
+ private final SystemInfoSection section2 = mock(SystemInfoSection.class);
+ private final CeHttpClient ceHttpClient = mock(CeHttpClientImpl.class, Mockito.RETURNS_MOCKS);
+ private final TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker();
+ private final TelemetryDataLoader telemetry = mock(TelemetryDataLoader.class, Mockito.RETURNS_MOCKS);
+ private final TelemetryDataJsonWriter dataJsonWriter = new TelemetryDataJsonWriter();
+ private final StandaloneSystemInfoWriter underTest = new StandaloneSystemInfoWriter(telemetry, ceHttpClient, healthChecker, dataJsonWriter, section1, section2);
@Test
public void write_json() {
@@ -79,10 +78,9 @@ public class StandaloneSystemInfoWriterTest {
underTest.write(jsonWriter);
jsonWriter.endObject();
// response does not contain empty "Section Three"
- assertThat(writer.toString()).isEqualTo("{\"Health\":\"GREEN\",\"Health Causes\":[],\"Section One\":{\"foo\":\"bar\"},\"Section Two\":{\"one\":1,\"two\":2}," +
+ 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\":[],\"installationDate\":0," +
- "\"installationVersion\":\"\",\"docker\":false}}");
+ "\"ncloc\":0,\"projectCountByLanguage\":[],\"nclocByLanguage\":[],\"almIntegrationCount\":[],\"externalAuthProviders\":[],\"projectCountByScm\":[],\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
}
private void logInAsSystemAdministrator() {
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java
index 423c00cee02..ccf32d67327 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java
@@ -35,6 +35,7 @@ import org.sonar.server.property.MapInternalProperties;
import org.sonar.server.util.GlobalLockManager;
import org.sonar.server.util.GlobalLockManagerImpl;
+import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -65,6 +66,8 @@ public class TelemetryDaemonTest {
.setVersion("bar")
.setPlugins(Collections.emptyMap())
.setAlmIntegrationCountByAlm(Collections.emptyMap())
+ .setExternalAuthenticationProviders(singletonList("github"))
+ .setProjectCountByScm(Collections.emptyMap())
.setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
.setProjectCount(12)
.setProjectCountByLanguage(Collections.emptyMap())
@@ -76,15 +79,15 @@ public class TelemetryDaemonTest {
.setUsingBranches(true)
.build();
- private TelemetryClient client = mock(TelemetryClient.class);
- private InternalProperties internalProperties = spy(new MapInternalProperties());
+ private final TelemetryClient client = mock(TelemetryClient.class);
+ private final InternalProperties internalProperties = spy(new MapInternalProperties());
private final GlobalLockManager lockManager = mock(GlobalLockManagerImpl.class);
- private TestSystem2 system2 = new TestSystem2().setNow(System.currentTimeMillis());
- private MapSettings settings = new MapSettings();
+ private final TestSystem2 system2 = new TestSystem2().setNow(System.currentTimeMillis());
+ private final MapSettings settings = new MapSettings();
private final TelemetryDataLoader dataLoader = mock(TelemetryDataLoader.class);
private final TelemetryDataJsonWriter dataJsonWriter = mock(TelemetryDataJsonWriter.class);
- private TelemetryDaemon underTest = new TelemetryDaemon(dataLoader, dataJsonWriter, client, settings.asConfig(), internalProperties, lockManager, system2);
+ private final TelemetryDaemon underTest = new TelemetryDaemon(dataLoader, dataJsonWriter, client, settings.asConfig(), internalProperties, lockManager, system2);
@After
public void tearDown() {
@@ -134,7 +137,7 @@ public class TelemetryDaemonTest {
internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
- verify(client, timeout(2_000)).upload(anyString());
+ verify(client, timeout(2_000)).upload(anyString());
verify(dataJsonWriter).writeTelemetryData(any(JsonWriter.class), same(SOME_TELEMETRY_DATA));
}
diff --git a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java
index 55167daa8c1..58162ad28b6 100644
--- a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java
+++ b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java
@@ -34,6 +34,7 @@ import static org.sonar.api.PropertyType.STRING;
public class CorePropertyDefinitions {
public static final String SONAR_ANALYSIS = "sonar.analysis.";
+ public static final String SONAR_ANALYSIS_DETECTEDSCM = "sonar.analysis.detectedscm";
private static final String CATEGORY_ORGANIZATIONS = "organizations";
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java
index f45c1dd18cb..0c8e49da4d7 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java
@@ -19,25 +19,31 @@
*/
package org.sonar.scanner.report;
+import java.util.AbstractMap;
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.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;
-public class ContextPropertiesPublisher implements ReportPublisherStep {
+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;
- public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config) {
+ public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration) {
this.cache = cache;
this.config = config;
+ this.scmConfiguration = scmConfiguration;
}
@Override
@@ -45,7 +51,7 @@ public class ContextPropertiesPublisher implements ReportPublisherStep {
MapEntryToContextPropertyFunction transformer = new MapEntryToContextPropertyFunction();
// properties defined programmatically by plugins
- Stream<ScannerReport.ContextProperty> fromCache = cache.getAll().entrySet().stream().map(transformer);
+ Stream<ScannerReport.ContextProperty> fromCache = Stream.concat(cache.getAll().entrySet().stream(), Stream.of(constructScmInfo())).map(transformer);
// properties that are automatically included to report so that
// they can be included to webhook payloads
@@ -56,6 +62,15 @@ public class ContextPropertiesPublisher implements ReportPublisherStep {
writer.writeContextProperties(Stream.concat(fromCache, fromSettings).collect(Collectors.toList()));
}
+ private Map.Entry<String, String> constructScmInfo() {
+ ScmProvider scmProvider = scmConfiguration.provider();
+ if (scmProvider != null) {
+ return new AbstractMap.SimpleEntry<>(SONAR_ANALYSIS_DETECTEDSCM, scmProvider.key());
+ } else {
+ return new AbstractMap.SimpleEntry<>(SONAR_ANALYSIS_DETECTEDSCM, "undetected");
+ }
+ }
+
private static final class MapEntryToContextPropertyFunction implements Function<Map.Entry<String, String>, ScannerReport.ContextProperty> {
private final ScannerReport.ContextProperty.Builder builder = ScannerReport.ContextProperty.newBuilder();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ContextPropertiesPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ContextPropertiesPublisherTest.java
index 91d42673494..db450a00657 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ContextPropertiesPublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ContextPropertiesPublisherTest.java
@@ -32,8 +32,8 @@ 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 java.util.Collections.emptyList;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -43,11 +43,12 @@ public class ContextPropertiesPublisherTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private ScannerReportWriter writer = mock(ScannerReportWriter.class);
- private ContextPropertiesCache cache = new ContextPropertiesCache();
- private DefaultConfiguration config = mock(DefaultConfiguration.class);
- private Map<String, String> props = new HashMap<>();
- private ContextPropertiesPublisher underTest = new ContextPropertiesPublisher(cache, config);
+ 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);
@Before
public void prepareMock() {
@@ -63,18 +64,12 @@ public class ContextPropertiesPublisherTest {
List<ScannerReport.ContextProperty> expected = Arrays.asList(
newContextProperty("foo1", "bar1"),
- newContextProperty("foo2", "bar2"));
+ newContextProperty("foo2", "bar2"),
+ newContextProperty("sonar.analysis.detectedscm", "undetected"));
expectWritten(expected);
}
@Test
- public void publish_writes_no_properties_to_report() {
- underTest.publish(writer);
-
- expectWritten(emptyList());
- }
-
- @Test
public void publish_settings_prefixed_with_sonar_analysis_for_webhooks() {
props.put("foo", "should not be exported");
props.put("sonar.analysis.revision", "ab45b3");
@@ -84,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.build.number", "B123"),
+ newContextProperty("sonar.analysis.detectedscm", "undetected"));
expectWritten(expected);
}