]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22873 Remove project queries using joins on live_measures
authorEric Giffon <eric.giffon@sonarsource.com>
Tue, 24 Sep 2024 11:48:03 +0000 (13:48 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 9 Oct 2024 20:02:46 +0000 (20:02 +0000)
12 files changed:
server/sonar-db-dao/src/it/java/org/sonar/db/measure/MeasureDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureMapper.java
server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/measure/MeasureMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml
server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImpl.java
server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImplTest.java
server/sonar-webserver/src/it/java/org/sonar/server/platform/telemetry/ProjectCppAutoconfigTelemetryProviderIT.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/telemetry/ProjectCppAutoconfigTelemetryProvider.java

index a80d2e7c4be0a1365ba3bf3ce496682d5abc6eb9..ed11ebf9183679189a49dd30fdd5816894c443c1 100644 (file)
@@ -52,6 +52,7 @@ import static org.sonar.db.component.ComponentTesting.newDirectory;
 import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
 import static org.sonar.db.measure.MeasureTesting.newMeasure;
+import static org.sonar.db.qualityprofile.QualityProfileTesting.newQualityProfileDto;
 
 class MeasureDaoIT {
 
@@ -567,6 +568,41 @@ class MeasureDaoIT {
       );
   }
 
+  @Test
+  void selectAllForProjectMainBranchesAssociatedToDefaultQualityProfile() {
+    ProjectData projectData1 = db.components().insertPrivateProject();
+    BranchDto branch1 = projectData1.getMainBranchDto();
+    BranchDto branch2 = db.components().insertProjectBranch(projectData1.getProjectDto());
+
+    ProjectData projectData2 = db.components().insertPrivateProject();
+    BranchDto branch3 = projectData2.getMainBranchDto();
+
+    // Insert measures for each branch and for a random component on branch1
+    MetricDto metric = db.measures().insertMetric();
+    MeasureDto measure1 = newMeasure(branch1, metric, 3);
+    MeasureDto measure2 = newMeasure(branch2, metric, 4);
+    MeasureDto measure3 = newMeasure(branch3, metric, 5);
+    MeasureDto measure4 = newMeasure(db.components().insertFile(branch1), metric, 7);
+
+    underTest.insertOrUpdate(db.getSession(), measure1);
+    underTest.insertOrUpdate(db.getSession(), measure2);
+    underTest.insertOrUpdate(db.getSession(), measure3);
+    underTest.insertOrUpdate(db.getSession(), measure4);
+
+    db.qualityProfiles().associateWithProject(projectData2.getProjectDto(), newQualityProfileDto());
+
+    List<ProjectMainBranchMeasureDto> measures =
+      underTest.selectAllForProjectMainBranchesAssociatedToDefaultQualityProfile(db.getSession());
+    assertThat(measures).hasSize(1);
+    assertThat(measures)
+      .flatExtracting(m -> m.getMetricValues().entrySet().stream()
+        .map(entry -> tuple(m.getProjectUuid(), entry.getKey(), entry.getValue()))
+        .toList())
+      .containsExactly(
+        tuple(projectData1.projectUuid(), metric.getKey(), 3.0)
+      );
+  }
+
   @Test
   void selectAllForMainBranches() {
     ProjectData projectData1 = db.components().insertPrivateProject();
index 3f4003019cfa05f537c5b437d79cd5126a16fe59..3befb7954787ba5f0f117da2aaa759a688f883db 100644 (file)
  */
 package org.sonar.db.project;
 
-import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Random;
 import java.util.Set;
-import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import javax.annotation.Nullable;
@@ -48,11 +44,7 @@ import org.sonar.db.audit.NoOpAuditPersister;
 import org.sonar.db.component.BranchDto;
 import org.sonar.db.component.BranchType;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ProjectData;
 import org.sonar.db.entity.EntityDto;
-import org.sonar.db.measure.LiveMeasureDto;
-import org.sonar.db.metric.MetricDto;
-import org.sonar.db.qualityprofile.QProfileDto;
 
 import static java.util.Collections.emptySet;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -62,13 +54,9 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
-import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
-import static org.sonar.api.measures.Metric.ValueType.STRING;
 
 class ProjectDaoIT {
 
-  private final Random random = new SecureRandom();
-
   private final System2 system2 = new AlwaysIncreasingSystem2(1000L);
 
   @RegisterExtension
@@ -351,18 +339,6 @@ class ProjectDaoIT {
     verify(auditPersister, times(1)).updateComponent(any(), any());
   }
 
-  @Test
-  void select_project_uuids_associated_to_default_quality_profile_for_specific_language() {
-    String language = "xoo";
-    Set<ProjectData> projects = insertProjects(random.nextInt(10));
-    insertDefaultQualityProfile(language);
-    insertProjectsLiveMeasures(language, projects);
-
-    Set<String> projectUuids = projectDao.selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(db.getSession(), language);
-
-    assertThat(projectUuids).containsExactlyInAnyOrderElementsOf(extractComponentUuids(projects));
-  }
-
   @Test
   void update_ncloc_should_update_project() {
     String projectUuid = db.components().insertPublicProject().projectUuid();
@@ -445,72 +421,6 @@ class ProjectDaoIT {
     assertThat(projectDao.countProjects(db.getSession())).isEqualTo(10);
   }
 
-  @Test
-  void selectProjectsByLanguage_whenTwoLanguagesArePassed_selectProjectsWithTheseLanguages() {
-    Consumer<MetricDto> configureMetric = metric -> metric
-      .setValueType(STRING.name())
-      .setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY);
-
-    MetricDto metric = db.measures().insertMetric(configureMetric);
-
-    ProjectData project1 = db.components().insertPrivateProject();
-    ProjectData project2 = db.components().insertPrivateProject();
-    ProjectData project3 = db.components().insertPrivateProject();
-    ProjectData project4 = db.components().insertPrivateProject();
-
-    insertLiveMeasure("c", metric).accept(project1);
-    insertLiveMeasure("cpp", metric).accept(project2);
-    insertLiveMeasure("java", metric).accept(project3);
-    insertLiveMeasure("cobol", metric).accept(project4);
-
-    List<ProjectDto> projectDtos = projectDao.selectProjectsByLanguage(db.getSession(), Set.of("cpp", "c"));
-
-    assertThat(projectDtos).extracting(ProjectDto::getUuid)
-      .containsExactlyInAnyOrder(project1.getProjectDto().getUuid(), project2.getProjectDto().getUuid());
-  }
-
-  private void insertDefaultQualityProfile(String language) {
-    QProfileDto profile = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage(language));
-    db.qualityProfiles().setAsDefault(profile);
-  }
-
-  private static Set<String> extractComponentUuids(Collection<ProjectData> components) {
-    return components
-      .stream()
-      .map(ProjectData::projectUuid)
-      .collect(Collectors.toSet());
-  }
-
-  private Set<ProjectData> insertProjects(int number) {
-    return IntStream
-      .rangeClosed(0, number)
-      .mapToObj(x -> db.components().insertPrivateProject())
-      .collect(Collectors.toSet());
-  }
-
-  private Consumer<LiveMeasureDto> configureLiveMeasure(String language, MetricDto metric, ComponentDto componentDto) {
-    return liveMeasure -> liveMeasure
-      .setMetricUuid(metric.getUuid())
-      .setComponentUuid(componentDto.uuid())
-      .setProjectUuid(componentDto.uuid())
-      .setData(language + "=" + random.nextInt(10));
-  }
-
-  private Consumer<ProjectData> insertLiveMeasure(String language, MetricDto metric) {
-    return (projectData) -> db.measures().insertLiveMeasure(projectData.getMainBranchComponent(), metric,
-      configureLiveMeasure(language, metric, projectData.getMainBranchComponent()));
-  }
-
-  private void insertProjectsLiveMeasures(String language, Set<ProjectData> projects) {
-    Consumer<MetricDto> configureMetric = metric -> metric
-      .setValueType(STRING.name())
-      .setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY);
-
-    MetricDto metric = db.measures().insertMetric(configureMetric);
-
-    projects.forEach(insertLiveMeasure(language, metric));
-  }
-
   private void assertProject(ProjectDto dto, String name, String kee, String uuid, String desc, @Nullable String tags, boolean isPrivate) {
     assertProject(dto, name, kee, uuid, desc, tags, isPrivate, false);
   }
index 7feb6a6795addac90ae4a418679d692e59da90c1..ab619fcb46f280d7f23d660826a4e455d486c5ed 100644 (file)
@@ -132,6 +132,10 @@ public class MeasureDao implements Dao {
     return mapper(dbSession).selectAllForProjectMainBranches();
   }
 
+  public List<ProjectMainBranchMeasureDto> selectAllForProjectMainBranchesAssociatedToDefaultQualityProfile(DbSession dbSession) {
+    return mapper(dbSession).selectAllForProjectMainBranchesAssociatedToDefaultQualityProfile();
+  }
+
   public List<MeasureDto> selectAllForMainBranches(DbSession dbSession) {
     return mapper(dbSession).selectAllForMainBranches();
   }
index a324666512bb28db6d74ebd541be4ded8048427c..b6baf817e2a9223ce39da905fc60aec0462de646 100644 (file)
@@ -51,5 +51,7 @@ public interface MeasureMapper {
 
   List<ProjectMainBranchMeasureDto> selectAllForProjectMainBranches();
 
+  List<ProjectMainBranchMeasureDto> selectAllForProjectMainBranchesAssociatedToDefaultQualityProfile();
+
   List<MeasureDto> selectAllForMainBranches();
 }
index 20f41f792274e62e4421cc3a53cc67981adc6fbd..49f305100e71a2e564a6bf2f894ba9b524766530 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.db.project;
 
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
@@ -140,10 +139,6 @@ public class ProjectDao implements Dao {
     return session.getMapper(ProjectMapper.class);
   }
 
-  public Set<String> selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(DbSession session, String language) {
-    return mapper(session).selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(languageFilters.apply(language));
-  }
-
   public void updateNcloc(DbSession dbSession, String projectUuid, long ncloc) {
     mapper(dbSession).updateNcloc(projectUuid, ncloc);
   }
@@ -163,12 +158,4 @@ public class ProjectDao implements Dao {
   public int countProjects(DbSession session) {
     return mapper(session).countProjects();
   }
-
-  public List<ProjectDto> selectProjectsByLanguage(DbSession dbSession, Set<String> setOfLanguages) {
-    Set<String> likeFilters = new HashSet<>();
-    for (String language : setOfLanguages) {
-      likeFilters.addAll(languageFilters.apply(language));
-    }
-    return mapper(dbSession).selectProjectsByLanguage(likeFilters);
-  }
 }
index 3ee4d95435d6e1aeb2a07713db348af3f4909cfc..4717d3e55b18d1c174d604817b6f4f6059f86119 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.db.project;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.apache.ibatis.annotations.Param;
@@ -68,8 +67,6 @@ public interface ProjectMapper {
   @CheckForNull
   ProjectDto selectByBranchUuid(String branchUuid);
 
-  Set<String> selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(@Param("languageFilters") Set<String> languageFilters);
-
   void updateNcloc(@Param("projectUuid") String projectUuid, @Param("ncloc") long ncloc);
 
   @CheckForNull
@@ -78,6 +75,4 @@ public interface ProjectMapper {
   int countIndexedProjects();
 
   int countProjects();
-
-  List<ProjectDto> selectProjectsByLanguage(@Param("languageFilters") Set<String> languageFilters);
 }
index 3bd68171aba2341a35190cbc897c6b00c9ff9039..118ef27e034fe1a5222a2b9d62a267ec199ba077 100644 (file)
     and pb.is_main = ${_true}
   </select>
 
+  <select id="selectAllForProjectMainBranchesAssociatedToDefaultQualityProfile" resultType="org.sonar.db.measure.ProjectMainBranchMeasureDto">
+    select p.uuid as projectUuid, m.json_value as jsonValue
+    from measures m
+    inner join project_branches pb on pb.uuid = m.component_uuid
+    inner join projects p on p.uuid = pb.project_uuid
+    where
+    pb.is_main = ${_true}
+    and p.uuid not in (select project_uuid from project_qprofiles)
+  </select>
+
   <select id="selectAllForMainBranches" resultType="org.sonar.db.measure.MeasureDto">
     select <include refid="columns"/> from measures m
     inner join project_branches pb on pb.uuid = m.component_uuid and pb.is_main = ${_true}
index 575a4356117e3e2c4587478eebb075faa2e849f7..c54aa32323fe04403d125fa0d7fb1197d6ae6ae6 100644 (file)
       p.kee=#{key,jdbcType=VARCHAR}
   </select>
 
-  <select id="selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage" parameterType="map" resultType="string">
-    select
-      p.uuid
-    from
-      live_measures lm
-    inner join
-      project_branches pb on pb.uuid = lm.component_uuid
-    inner join
-      projects p on p.uuid = pb.project_uuid
-    inner join
-      metrics m on m.uuid = lm.metric_uuid
-    where
-      m.name = 'ncloc_language_distribution'
-      and pb.is_main = ${_true}
-      and p.uuid not in (select project_uuid from project_qprofiles)
-      and
-      <foreach collection="languageFilters" index="index" item="languageFilter" open="(" separator=" or " close=")">
-        lm.text_value like #{languageFilter, jdbcType=VARCHAR} escape '/'
-      </foreach>
-  </select>
-
-  <select id="selectProjectsByLanguage" parameterType="map" resultType="Project">
-    select distinct
-      <include refid="projectColumns"/>
-    from
-      live_measures lm
-    inner join
-      project_branches pb on pb.uuid = lm.project_uuid and pb.is_main = ${_true}
-    inner join
-      projects p on p.uuid = pb.project_uuid
-    inner join
-      metrics m on m.uuid = lm.metric_uuid
-    where
-      m.name = 'ncloc_language_distribution'
-      and
-      <foreach collection="languageFilters" index="index" item="languageFilter" open="(" separator=" or " close=")">
-        lm.text_value like #{languageFilter, jdbcType=VARCHAR} escape '/'
-      </foreach>
-  </select>
-
   <insert id="insert" parameterType="Project">
     INSERT INTO projects (
       kee,
index baf693c63bea74b3ff2bcdecc934e36a8a96c819..ddffddaab9954d841f3ee776cd6e2f6adbcd4725 100644 (file)
@@ -35,6 +35,7 @@ import java.util.stream.Stream;
 import javax.annotation.Nullable;
 import org.apache.commons.lang3.StringUtils;
 import org.jetbrains.annotations.NotNull;
+import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.util.ParamChange;
@@ -42,6 +43,7 @@ import org.sonar.core.util.rule.RuleChange;
 import org.sonar.core.util.rule.RuleSetChangedEvent;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
+import org.sonar.db.measure.ProjectMainBranchMeasureDto;
 import org.sonar.db.project.ProjectDto;
 import org.sonar.db.pushevent.PushEventDto;
 import org.sonar.db.qualityprofile.ActiveRuleDto;
@@ -271,10 +273,24 @@ public class QualityProfileChangeEventServiceImpl implements QualityProfileChang
   }
 
   private List<ProjectDto> getDefaultQualityProfileAssociatedProjects(DbSession dbSession, String language) {
-    Set<String> associatedProjectUuids = dbClient.projectDao().selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(dbSession, language);
+    Set<String> associatedProjectUuids = new HashSet<>();
+
+    List<ProjectMainBranchMeasureDto> measureDtos =
+      dbClient.measureDao().selectAllForProjectMainBranchesAssociatedToDefaultQualityProfile(dbSession);
+    for (ProjectMainBranchMeasureDto measureDto : measureDtos) {
+      String distribution = (String) measureDto.getMetricValues().get(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY);
+      if (distribution != null && distributionContainsLanguage(distribution, language)) {
+        associatedProjectUuids.add(measureDto.getProjectUuid());
+      }
+    }
+
     return dbClient.projectDao().selectByUuids(dbSession, associatedProjectUuids);
   }
 
+  private static boolean distributionContainsLanguage(String distribution, String language) {
+    return distribution.startsWith(language + "=") || distribution.contains(";" + language + "=");
+  }
+
   private List<ProjectDto> getManuallyAssociatedQualityProfileProjects(DbSession dbSession, List<QProfileDto> profiles) {
     return profiles
       .stream()
index cea9b9855cbafb455976b5ba3def9010cf8b15c4..8d629900c8f4288727ac372106e142f3cc5f4da2 100644 (file)
 package org.sonar.server.pushapi.qualityprofile;
 
 import java.nio.charset.StandardCharsets;
-import java.security.SecureRandom;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Deque;
 import java.util.List;
-import java.util.Random;
 import java.util.Set;
 import java.util.function.Consumer;
 import org.junit.Rule;
@@ -34,8 +32,6 @@ import org.sonar.api.rule.RuleKey;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ProjectData;
-import org.sonar.db.measure.LiveMeasureDto;
-import org.sonar.db.metric.MetricDto;
 import org.sonar.db.project.ProjectDto;
 import org.sonar.db.pushevent.PushEventDto;
 import org.sonar.db.qualityprofile.ActiveRuleDto;
@@ -51,15 +47,12 @@ import static java.util.List.of;
 import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
-import static org.sonar.api.measures.Metric.ValueType.STRING;
 import static org.sonar.db.rule.RuleTesting.newCustomRule;
 import static org.sonar.db.rule.RuleTesting.newTemplateRule;
 import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED;
 
 public class QualityProfileChangeEventServiceImplTest {
 
-  private final Random random = new SecureRandom();
-
   @Rule
   public DbTester db = DbTester.create();
 
@@ -114,7 +107,7 @@ public class QualityProfileChangeEventServiceImplTest {
     QProfileDto defaultQualityProfile = insertDefaultQualityProfile(language);
     RuleDto rule = insertCustomRule(templateRule, language, "<div>line1\nline2</div>");
     ActiveRuleChange activeRuleChange = changeActiveRule(defaultQualityProfile, rule, "paramChangeKey", "paramChangeValue");
-    insertQualityProfileLiveMeasure(mainBranch, projectData.getProjectDto(), language, NCLOC_LANGUAGE_DISTRIBUTION_KEY);
+    db.measures().insertMeasure(mainBranch, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, language + "=100"));
 
     db.getSession().commit();
 
@@ -221,25 +214,4 @@ public class QualityProfileChangeEventServiceImplTest {
                 "\"params\":[{\"key\":\"" + activeRuleParam1.getKey() + "\",\"value\":\"" + activeRuleParam1.getValue() + "\"}]}]," +
                 "\"deactivatedRules\":[\"repo2:ruleKey2\"]");
   }
-
-  private void insertQualityProfileLiveMeasure(ComponentDto branch, ProjectDto projectDto, String language, String metricKey) {
-    MetricDto metric = insertMetric(metricKey);
-
-    Consumer<LiveMeasureDto> configureLiveMeasure = liveMeasure -> liveMeasure
-      .setMetricUuid(metric.getUuid())
-      .setComponentUuid(branch.uuid())
-      .setProjectUuid(projectDto.getUuid())
-      .setData(language + "=" + random.nextInt(10));
-
-    db.measures().insertLiveMeasure(branch, metric, configureLiveMeasure);
-  }
-
-  private MetricDto insertMetric(String metricKey) {
-    Consumer<MetricDto> configureMetric = metric -> metric
-      .setUuid("uuid")
-      .setValueType(STRING.name())
-      .setKey(metricKey);
-
-    return db.measures().insertMetric(configureMetric);
-  }
 }
index b1e40ad643b2e643060618207a39089328af9aaf..2a2e39c2ac54759addea2ca7771eaa02d383c629 100644 (file)
 package org.sonar.server.platform.telemetry;
 
 import java.util.Map;
-import java.util.function.Consumer;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ProjectData;
-import org.sonar.db.measure.LiveMeasureDto;
-import org.sonar.db.metric.MetricDto;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
-import static org.sonar.api.measures.Metric.ValueType.STRING;
 
 class ProjectCppAutoconfigTelemetryProviderIT {
 
@@ -51,39 +46,26 @@ class ProjectCppAutoconfigTelemetryProviderIT {
 
   @Test
   void getValues_whenNoCppAndCProjects_returnEmptyMap() {
-    Consumer<MetricDto> configureMetric = metric -> metric
-      .setValueType(STRING.name())
-      .setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY);
-
-    MetricDto metric = db.measures().insertMetric(configureMetric);
-
     ProjectData project1 = db.components().insertPrivateProject();
     ProjectData project2 = db.components().insertPrivateProject();
 
-    insertLiveMeasure("java", metric).accept(project1);
-    insertLiveMeasure("cobol", metric).accept(project2);
-
+    db.measures().insertMeasure(project1, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "java=100"));
+    db.measures().insertMeasure(project2, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "cobol=100"));
 
     assertThat(underTest.getValues()).isEmpty();
   }
 
   @Test
   void getValues_when1CppAnd1CProject_returnMapWithSize2AndAutoconfigByDefault() {
-    Consumer<MetricDto> configureMetric = metric -> metric
-      .setValueType(STRING.name())
-      .setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY);
-
-    MetricDto metric = db.measures().insertMetric(configureMetric);
-
     ProjectData project1 = db.components().insertPrivateProject();
     ProjectData project2 = db.components().insertPrivateProject();
     ProjectData project3 = db.components().insertPrivateProject();
     ProjectData project4 = db.components().insertPrivateProject();
 
-    insertLiveMeasure("c", metric).accept(project1);
-    insertLiveMeasure("cpp", metric).accept(project2);
-    insertLiveMeasure("java", metric).accept(project3);
-    insertLiveMeasure("cobol", metric).accept(project4);
+    db.measures().insertMeasure(project1, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "c=100;java=2"));
+    db.measures().insertMeasure(project2, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "java=2;cpp=100"));
+    db.measures().insertMeasure(project3, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "java=100"));
+    db.measures().insertMeasure(project4, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "cobol=100"));
 
     Map<String, String> actualResult = underTest.getValues();
 
@@ -95,21 +77,15 @@ class ProjectCppAutoconfigTelemetryProviderIT {
 
   @Test
   void getValues_whenCAndCppProjectsWithDifferentConfig_returnMapWithSize2AndNotAutoconfig() {
-    Consumer<MetricDto> configureMetric = metric -> metric
-      .setValueType(STRING.name())
-      .setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY);
-
-    MetricDto metric = db.measures().insertMetric(configureMetric);
-
     ProjectData project1 = db.components().insertPrivateProject();
     ProjectData project2 = db.components().insertPrivateProject();
     ProjectData project3 = db.components().insertPrivateProject();
     ProjectData project4 = db.components().insertPrivateProject();
 
-    insertLiveMeasure("c", metric).accept(project1);
-    insertLiveMeasure("cpp", metric).accept(project2);
-    insertLiveMeasure("java", metric).accept(project3);
-    insertLiveMeasure("cobol", metric).accept(project4);
+    db.measures().insertMeasure(project1, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "c=100"));
+    db.measures().insertMeasure(project2, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "cpp=100"));
+    db.measures().insertMeasure(project3, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "java=100"));
+    db.measures().insertMeasure(project4, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, "cobol=100"));
 
     db.properties().insertProperty("sonar.cfamily.build-wrapper-output", "anyvalue", project1.getProjectDto().getUuid());
     db.properties().insertProperty("sonar.cfamily.compile-commands", "anyvalue", project2.getProjectDto().getUuid());
@@ -121,17 +97,4 @@ class ProjectCppAutoconfigTelemetryProviderIT {
         Map.of(project1.getProjectDto().getUuid(), "BW_DEPRECATED", project2.getProjectDto().getUuid(), "COMPDB")
       );
   }
-
-  private Consumer<LiveMeasureDto> configureLiveMeasure(String language, MetricDto metric, ComponentDto componentDto) {
-    return liveMeasure -> liveMeasure
-      .setMetricUuid(metric.getUuid())
-      .setComponentUuid(componentDto.uuid())
-      .setProjectUuid(componentDto.uuid())
-      .setData(language + "=" + 100);
-  }
-
-  private Consumer<ProjectData> insertLiveMeasure(String language, MetricDto metric) {
-    return projectData -> db.measures().insertLiveMeasure(projectData.getMainBranchComponent(), metric,
-      configureLiveMeasure(language, metric, projectData.getMainBranchComponent()));
-  }
 }
index 51382bbebe91e6600e8b5a4ef1b62c9e0021b127..fb83847c57aab4138f730e8ade352707b31559b9 100644 (file)
@@ -23,9 +23,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import org.sonar.api.measures.CoreMetrics;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.project.ProjectDto;
+import org.sonar.db.measure.ProjectMainBranchMeasureDto;
 import org.sonar.db.property.PropertyDto;
 import org.sonar.db.property.PropertyQuery;
 import org.sonar.telemetry.core.Dimension;
@@ -65,20 +66,26 @@ public class ProjectCppAutoconfigTelemetryProvider implements TelemetryDataProvi
   public Map<String, String> getValues() {
     Map<String, String> cppConfigTypePerProjectUuid = new HashMap<>();
     try (DbSession dbSession = dbClient.openSession(true)) {
-      // In the future ideally languages should be defined in the codebase as enums, using strings is error-prone
-      List<ProjectDto> cppProjects = dbClient.projectDao().selectProjectsByLanguage(dbSession, Set.of("cpp", "c"));
-      for (ProjectDto cppProject : cppProjects) {
-        CppConfigType cppConfigType = getCppConfigType(cppProject, dbSession);
-        cppConfigTypePerProjectUuid.put(cppProject.getUuid(), cppConfigType.name());
+      List<ProjectMainBranchMeasureDto> measureDtos = dbClient.measureDao().selectAllForProjectMainBranches(dbSession);
+      for (ProjectMainBranchMeasureDto measureDto : measureDtos) {
+        String distribution = (String) measureDto.getMetricValues().get(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY);
+        if (distribution != null && Set.of("cpp", "c").stream().anyMatch(language -> distributionContainsLanguage(distribution, language))) {
+          CppConfigType cppConfigType = getCppConfigType(measureDto.getProjectUuid(), dbSession);
+          cppConfigTypePerProjectUuid.put(measureDto.getProjectUuid(), cppConfigType.name());
+        }
       }
     }
     return cppConfigTypePerProjectUuid;
   }
 
-  private CppConfigType getCppConfigType(ProjectDto project, DbSession dbSession) {
+  private static boolean distributionContainsLanguage(String distribution, String language) {
+    return distribution.startsWith(language + "=") || distribution.contains(";" + language + "=");
+  }
+
+  private CppConfigType getCppConfigType(String entityUuid, DbSession dbSession) {
     List<PropertyDto> propertyDtos = dbClient.propertiesDao().selectByQuery(PropertyQuery
       .builder()
-      .setEntityUuid(project.getUuid())
+      .setEntityUuid(entityUuid)
       .build(), dbSession);
     for (PropertyDto propertyDto : propertyDtos) {
       if (propertyDto.getKey().equals("sonar.cfamily.build-wrapper-output")) {