]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22479 added new metric project_cpp_config_type
authorlukasz-jarocki-sonarsource <lukasz.jarocki@sonarsource.com>
Mon, 15 Jul 2024 09:50:02 +0000 (11:50 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 24 Jul 2024 20:02:48 +0000 (20:02 +0000)
12 files changed:
scripts/patches/json [deleted file]
server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.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/project/ProjectMapper.xml
server/sonar-telemetry/src/it/java/org/sonar/telemetry/legacy/project/ProjectCppAutoconfigTelemetryProviderIT.java [new file with mode: 0644]
server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProvider.java [new file with mode: 0644]
server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/package-info.java [new file with mode: 0644]
server/sonar-telemetry/src/test/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProviderTest.java [new file with mode: 0644]
server/sonar-webserver-core/build.gradle
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterPlugins.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java

diff --git a/scripts/patches/json b/scripts/patches/json
deleted file mode 100644 (file)
index e69de29..0000000
index 83b1fdfff64f165ffc538f2c16389769c3fddb7d..cf41906c23c809005a848821d0b9ec3e0189e98a 100644 (file)
@@ -406,6 +406,30 @@ 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);
index 49b01aebe1c6b8bc28c447ab3baa9e5d3098e647..7da97de7eefbccaee2cce2d26672151fcde01b4c 100644 (file)
 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;
+import java.util.function.Function;
 import javax.annotation.Nullable;
 import org.sonar.api.utils.System2;
 import org.sonar.db.Dao;
@@ -38,6 +40,8 @@ public class ProjectDao implements Dao {
   private final System2 system2;
   private final AuditPersister auditPersister;
 
+  private final Function<String, Set<String>> languageFilters = language -> Set.of(language + "=%", "%;" + language + "=%");
+
   public ProjectDao(System2 system2, AuditPersister auditPersister) {
     this.system2 = system2;
     this.auditPersister = auditPersister;
@@ -133,8 +137,7 @@ public class ProjectDao implements Dao {
   }
 
   public Set<String> selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(DbSession session, String language) {
-    Set<String> languageFilters = Set.of(language + "=%", "%;" + language + "=%");
-    return mapper(session).selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(languageFilters);
+    return mapper(session).selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(languageFilters.apply(language));
   }
 
   public void updateNcloc(DbSession dbSession, String projectUuid, long ncloc) {
@@ -156,4 +159,12 @@ 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 ee8a0d8e15ba2a832d38d315961ed18afdb843cd..c31542346f471f9df741b3321a1ecdee99333a61 100644 (file)
@@ -76,4 +76,6 @@ public interface ProjectMapper {
   int countIndexedProjects();
 
   int countProjects();
+
+  List<ProjectDto> selectProjectsByLanguage(@Param("languageFilters") Set<String> languageFilters);
 }
index aba8dbdf0b2ac743954588402e71694e0dcbb729..c1594315c72dbfce5f903b4802af9c1ddd0c268d 100644 (file)
       </foreach>
   </select>
 
+  <select id="selectProjectsByLanguage" parameterType="map" resultType="Project">
+    select distinct
+      <include refid="projectColumns"/>
+    from
+      live_measures lm
+    inner join
+      projects p on p.uuid = lm.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,
diff --git a/server/sonar-telemetry/src/it/java/org/sonar/telemetry/legacy/project/ProjectCppAutoconfigTelemetryProviderIT.java b/server/sonar-telemetry/src/it/java/org/sonar/telemetry/legacy/project/ProjectCppAutoconfigTelemetryProviderIT.java
new file mode 100644 (file)
index 0000000..aa53b73
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.legacy.project;
+
+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 org.sonar.db.project.ProjectDto;
+import org.sonar.telemetry.project.ProjectCppAutoconfigTelemetryProvider;
+
+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 {
+
+  private final System2 system2 = new AlwaysIncreasingSystem2(1000L);
+
+  @RegisterExtension
+  public final DbTester db = DbTester.create(system2);
+
+  ProjectCppAutoconfigTelemetryProvider underTest = new ProjectCppAutoconfigTelemetryProvider(db.getDbClient());
+
+  @Test
+  void getUuidValues_whenNoProjects_returnEmptyList() {
+    assertThat(underTest.getUuidValues()).isEmpty();
+  }
+
+  @Test
+  void getUuidValues_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);
+
+
+    assertThat(underTest.getUuidValues()).isEmpty();
+  }
+
+  @Test
+  void getUuidValues_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);
+
+    Map<String, String> actualResult = underTest.getUuidValues();
+
+    assertThat(actualResult).hasSize(2);
+    assertThat(actualResult).containsExactlyInAnyOrderEntriesOf(Map.of(project1.getProjectDto().getUuid(), "AUTOCONFIG",
+      project2.getProjectDto().getUuid(), "AUTOCONFIG"));
+  }
+
+  @Test
+  void getUuidValues_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.properties().insertProperty("sonar.cfamily.build-wrapper-output", "anyvalue", project1.getProjectDto().getUuid());
+    db.properties().insertProperty("sonar.cfamily.compile-commands", "anyvalue", project2.getProjectDto().getUuid());
+
+    Map<String, String> actualResult = underTest.getUuidValues();
+
+    assertThat(actualResult).hasSize(2);
+    assertThat(actualResult).containsExactlyInAnyOrderEntriesOf(Map.of(project1.getProjectDto().getUuid(), "BW_DEPRECATED",
+      project2.getProjectDto().getUuid(), "COMPDB"));
+  }
+
+  private Consumer<LiveMeasureDto> configureLiveMeasure(String language, MetricDto metric, ProjectDto project, ComponentDto componentDto) {
+    return liveMeasure -> liveMeasure
+      .setMetricUuid(metric.getUuid())
+      .setComponentUuid(componentDto.uuid())
+      .setProjectUuid(project.getUuid())
+      .setData(language + "=" + 100);
+  }
+
+  private Consumer<ProjectData> insertLiveMeasure(String language, MetricDto metric) {
+    return projectData -> db.measures().insertLiveMeasure(projectData.getMainBranchComponent(), metric,
+      configureLiveMeasure(language, metric, projectData.getProjectDto(), projectData.getMainBranchComponent()));
+  }
+}
diff --git a/server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProvider.java b/server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProvider.java
new file mode 100644 (file)
index 0000000..caa0b90
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.project;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.property.PropertyQuery;
+import org.sonar.telemetry.Dimension;
+import org.sonar.telemetry.Granularity;
+import org.sonar.telemetry.TelemetryDataType;
+import org.sonar.telemetry.TelemetryDataProvider;
+
+public class ProjectCppAutoconfigTelemetryProvider implements TelemetryDataProvider<String> {
+
+  private final DbClient dbClient;
+
+  public ProjectCppAutoconfigTelemetryProvider(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  public String getMetricKey() {
+    return "project_cpp_config_type";
+  }
+
+  @Override
+  public Dimension getDimension() {
+    return Dimension.PROJECT;
+  }
+
+  @Override
+  public Granularity getGranularity() {
+    return Granularity.WEEKLY;
+  }
+
+  @Override
+  public TelemetryDataType getType() {
+    return TelemetryDataType.STRING;
+  }
+
+  @Override
+  public Map<String, String> getUuidValues() {
+    Map<String, String> cppConfigTypePerProjectUuid = new HashMap<>();
+    try (DbSession dbSession = dbClient.openSession(true)) {
+      //TODO in the feature 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());
+      }
+    }
+    return cppConfigTypePerProjectUuid;
+  }
+
+  private CppConfigType getCppConfigType(ProjectDto project, DbSession dbSession) {
+    List<PropertyDto> propertyDtos = dbClient.propertiesDao().selectByQuery(PropertyQuery
+      .builder()
+      .setEntityUuid(project.getUuid())
+      .build(), dbSession);
+    for (PropertyDto propertyDto : propertyDtos) {
+      if (propertyDto.getKey().equals("sonar.cfamily.build-wrapper-output")) {
+        return CppConfigType.BW_DEPRECATED;
+      }
+      if (propertyDto.getKey().equals("sonar.cfamily.compile-commands")) {
+        return CppConfigType.COMPDB;
+      }
+    }
+    return CppConfigType.AUTOCONFIG;
+  }
+
+  enum CppConfigType {
+    BW_DEPRECATED, COMPDB, AUTOCONFIG
+  }
+}
diff --git a/server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/package-info.java b/server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/package-info.java
new file mode 100644 (file)
index 0000000..3d6bbd2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.telemetry.project;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-telemetry/src/test/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProviderTest.java b/server/sonar-telemetry/src/test/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProviderTest.java
new file mode 100644 (file)
index 0000000..ccbf1bc
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.project;
+
+import org.junit.jupiter.api.Test;
+import org.sonar.db.DbClient;
+import org.sonar.telemetry.Dimension;
+import org.sonar.telemetry.Granularity;
+import org.sonar.telemetry.TelemetryDataType;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+
+class ProjectCppAutoconfigTelemetryProviderTest {
+
+  @Test
+  void testGetters() {
+     ProjectCppAutoconfigTelemetryProvider provider = new ProjectCppAutoconfigTelemetryProvider(mock(DbClient.class));
+
+     assertEquals("project_cpp_config_type", provider.getMetricKey());
+     assertEquals(Dimension.PROJECT, provider.getDimension());
+     assertEquals(Granularity.WEEKLY, provider.getGranularity());
+     assertEquals(TelemetryDataType.STRING, provider.getType());
+  }
+}
index ecdf1cac6521c939f9e72faa79c6d0747e72cb7a..de12a259f893a18d693967583924f40d108fe835 100644 (file)
@@ -49,6 +49,7 @@ dependencies {
   api project(':sonar-markdown')
   api project(':sonar-plugin-api-impl')
   api project(':sonar-ws')
+  api project(':server:sonar-telemetry')
   implementation project(path: ':server:sonar-webserver-webapi')
 
   compileOnlyApi 'com.github.spotbugs:spotbugs-annotations'
index b606cb0045edb197e26c0c1705639ff917ee9636..d28815c25f44fce3e68dad60335b64b07921f784 100644 (file)
@@ -28,11 +28,11 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.plugin.PluginType;
 import org.sonar.core.util.UuidFactory;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.plugin.PluginDto;
-import org.sonar.core.plugin.PluginType;
 import org.sonar.server.plugins.ServerPlugin;
 import org.sonar.server.plugins.ServerPluginRepository;
 
index 59d0d908787547741b3c45473dfcf6231879a027..00b667efed20aee0fef723322d6c97586e100e27 100644 (file)
@@ -210,6 +210,7 @@ import org.sonar.server.plugins.ws.PluginsWs;
 import org.sonar.server.plugins.ws.UninstallAction;
 import org.sonar.server.plugins.ws.UpdatesAction;
 import org.sonar.server.project.DefaultBranchNameResolver;
+import org.sonar.server.project.ProjectCppAutoconfigTelemetryProvider;
 import org.sonar.server.project.ProjectQGChangeEventListener;
 import org.sonar.server.project.VisibilityService;
 import org.sonar.server.project.ws.ProjectsWsModule;
@@ -669,6 +670,7 @@ public class PlatformLevel4 extends PlatformLevel {
       //new telemetry metrics
       TelemetryVersionProvider.class,
       TelemetryNclocProvider.class,
+      ProjectCppAutoconfigTelemetryProvider.class,
 
       // monitoring
       ServerMonitoringMetrics.class,