]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22479 added new telemetry metric "ncloc" for language dimension
authorMatteo Mara <matteo.mara@sonarsource.com>
Thu, 11 Jul 2024 10:11:11 +0000 (12:11 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 24 Jul 2024 20:02:48 +0000 (20:02 +0000)
server/sonar-telemetry/src/main/java/org/sonar/telemetry/TelemetryNclocProvider.java [new file with mode: 0644]
server/sonar-telemetry/src/test/java/org/sonar/telemetry/TelemetryNclocProviderTest.java [new file with mode: 0644]
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java

diff --git a/server/sonar-telemetry/src/main/java/org/sonar/telemetry/TelemetryNclocProvider.java b/server/sonar-telemetry/src/main/java/org/sonar/telemetry/TelemetryNclocProvider.java
new file mode 100644 (file)
index 0000000..f3f7231
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.telemetry;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.measure.ProjectLocDistributionDto;
+import org.sonar.db.metric.MetricDto;
+
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toMap;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
+
+public class TelemetryNclocProvider implements TelemetryDataProvider<Long> {
+
+  public static final String METRIC_KEY = "ncloc_per_language";
+
+  private final DbClient dbClient;
+
+  public TelemetryNclocProvider(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  public String getMetricKey() {
+    return METRIC_KEY;
+  }
+
+  @Override
+  public Dimension getDimension() {
+    return Dimension.LANGUAGE;
+  }
+
+  @Override
+  public Granularity getGranularity() {
+    return Granularity.DAILY;
+  }
+
+  @Override
+  public TelemetryDataType getType() {
+    return TelemetryDataType.INTEGER;
+  }
+
+  @Override
+  public Map<String, Long> getUuidValues() {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      return getNclocDistribution(dbSession);
+    }
+  }
+
+  private Map<String, Long> getNclocDistribution(DbSession dbSession) {
+    Map<String, String> metricUuidMap = getNclocMetricUuidMap(dbSession);
+    String nclocUuid = metricUuidMap.get(NCLOC_KEY);
+    String nclocDistributionUuid = metricUuidMap.get(NCLOC_LANGUAGE_DISTRIBUTION_KEY);
+    List<ProjectLocDistributionDto> branchesWithLargestNcloc = dbClient.liveMeasureDao().selectLargestBranchesLocDistribution(dbSession, nclocUuid, nclocDistributionUuid);
+    List<LanguageDistribution> languageDistributions = getLanguageDistributionList(branchesWithLargestNcloc);
+    return getNclocDistributionPerLanguage(languageDistributions);
+  }
+
+  private Map<String, String> getNclocMetricUuidMap(DbSession dbSession) {
+    return dbClient.metricDao().selectByKeys(dbSession, asList(NCLOC_KEY, NCLOC_LANGUAGE_DISTRIBUTION_KEY))
+      .stream()
+      .collect(toMap(MetricDto::getKey, MetricDto::getUuid));
+  }
+
+  private static List<LanguageDistribution> getLanguageDistributionList(List<ProjectLocDistributionDto> branchesWithLargestNcloc) {
+    return branchesWithLargestNcloc.stream()
+      .flatMap(measure -> Arrays.stream(measure.locDistribution().split(";"))
+        .map(languageAndLoc -> languageAndLoc.split("="))
+        .map(languageAndLoc -> new LanguageDistribution(
+          languageAndLoc[0],
+          Long.parseLong(languageAndLoc[1]))))
+      .toList();
+  }
+
+  private static Map<String, Long> getNclocDistributionPerLanguage(List<LanguageDistribution> languageDistributions) {
+    // a Map<String, Integer> that contains the sum of ncloc per language
+    Map<String, Long> nclocPerLanguage = new HashMap<>();
+    languageDistributions.forEach(languageDistribution -> nclocPerLanguage.merge(languageDistribution.language, languageDistribution.ncloc, Long::sum));
+    return nclocPerLanguage;
+  }
+
+  private record LanguageDistribution(String language, long ncloc) {
+  }
+}
diff --git a/server/sonar-telemetry/src/test/java/org/sonar/telemetry/TelemetryNclocProviderTest.java b/server/sonar-telemetry/src/test/java/org/sonar/telemetry/TelemetryNclocProviderTest.java
new file mode 100644 (file)
index 0000000..00aeb98
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.telemetry;
+
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.measure.ProjectLocDistributionDto;
+import org.sonar.db.metric.MetricDto;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
+import static org.sonar.telemetry.TelemetryNclocProvider.METRIC_KEY;
+
+class TelemetryNclocProviderTest {
+
+  DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS);
+  private final DbSession dbSession = mock(DbSession.class);
+
+  @Test
+  void getUuidValues_returnsTheRightLanguageDistribution() {
+    TelemetryNclocProvider telemetryNclocProvider = new TelemetryNclocProvider(dbClient);
+
+    when(dbClient.openSession(false)).thenReturn(dbSession);
+
+    when(dbClient.metricDao().selectByKeys(dbSession, asList(NCLOC_KEY, NCLOC_LANGUAGE_DISTRIBUTION_KEY))).thenReturn(Arrays.asList(
+      new MetricDto().setKey(NCLOC_KEY).setUuid("ncloc_uuid"),
+      new MetricDto().setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setUuid("ncloc_distribution_uuid")
+    ));
+
+    when(dbClient.liveMeasureDao().selectLargestBranchesLocDistribution(dbSession, "ncloc_uuid", "ncloc_distribution_uuid")).thenReturn(Arrays.asList(
+      new ProjectLocDistributionDto("project1", "branch1-p1", "java=5000;xml=1000;js=1000"),
+      new ProjectLocDistributionDto("project2", "branch1-p2", "java=10000;csharp=2000"),
+      new ProjectLocDistributionDto("project3", "branch1-p3", "java=7000;js=500")
+    ));
+
+    assertEquals(METRIC_KEY, telemetryNclocProvider.getMetricKey());
+    assertEquals(Granularity.DAILY, telemetryNclocProvider.getGranularity());
+    assertEquals(Dimension.LANGUAGE, telemetryNclocProvider.getDimension());
+
+    assertThat(telemetryNclocProvider.getUuidValues()).containsOnlyKeys("java", "xml", "csharp", "js");
+    assertThat(telemetryNclocProvider.getUuidValues()).containsEntry("java", 22000L);
+    assertThat(telemetryNclocProvider.getUuidValues()).containsEntry("xml", 1000L);
+    assertThat(telemetryNclocProvider.getUuidValues()).containsEntry("csharp", 2000L);
+    assertThat(telemetryNclocProvider.getUuidValues()).containsEntry("js", 1500L);
+  }
+}
\ No newline at end of file
index c37fa753d5edcf99025d075ed46b2847c41c203c..59d0d908787547741b3c45473dfcf6231879a027 100644 (file)
@@ -282,6 +282,7 @@ import org.sonar.server.webhook.WebhookQGChangeEventListener;
 import org.sonar.server.webhook.ws.WebhooksWsModule;
 import org.sonar.server.ws.WebServiceEngine;
 import org.sonar.server.ws.ws.WebServicesWsModule;
+import org.sonar.telemetry.TelemetryNclocProvider;
 import org.sonar.telemetry.legacy.CloudUsageDataProvider;
 import org.sonar.telemetry.legacy.QualityProfileDataProvider;
 import org.sonar.telemetry.legacy.TelemetryClient;
@@ -667,6 +668,7 @@ public class PlatformLevel4 extends PlatformLevel {
 
       //new telemetry metrics
       TelemetryVersionProvider.class,
+      TelemetryNclocProvider.class,
 
       // monitoring
       ServerMonitoringMetrics.class,