diff options
author | lukasz-jarocki-sonarsource <lukasz.jarocki@sonarsource.com> | 2024-07-15 11:50:02 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-07-24 20:02:48 +0000 |
commit | c9d48b7138e2f73637da4ead7ee9c54c78447381 (patch) | |
tree | 52d856b4686ddac49ce960d45c344b9f93338cc7 /server | |
parent | 2b2f246731c4052c4052e2f2d56416352132114f (diff) | |
download | sonarqube-c9d48b7138e2f73637da4ead7ee9c54c78447381.tar.gz sonarqube-c9d48b7138e2f73637da4ead7ee9c54c78447381.zip |
SONAR-22479 added new metric project_cpp_config_type
Diffstat (limited to 'server')
11 files changed, 359 insertions, 3 deletions
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java index 83b1fdfff64..cf41906c23c 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java @@ -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); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java index 49b01aebe1c..7da97de7eef 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java @@ -20,9 +20,11 @@ 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); + } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java index ee8a0d8e15b..c31542346f4 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java @@ -76,4 +76,6 @@ public interface ProjectMapper { int countIndexedProjects(); int countProjects(); + + List<ProjectDto> selectProjectsByLanguage(@Param("languageFilters") Set<String> languageFilters); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml index aba8dbdf0b2..c1594315c72 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml @@ -147,6 +147,23 @@ </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 index 00000000000..aa53b737069 --- /dev/null +++ b/server/sonar-telemetry/src/it/java/org/sonar/telemetry/legacy/project/ProjectCppAutoconfigTelemetryProviderIT.java @@ -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 index 00000000000..caa0b900485 --- /dev/null +++ b/server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProvider.java @@ -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 index 00000000000..3d6bbd23974 --- /dev/null +++ b/server/sonar-telemetry/src/main/java/org/sonar/telemetry/project/package-info.java @@ -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 index 00000000000..ccbf1bc9198 --- /dev/null +++ b/server/sonar-telemetry/src/test/java/org/sonar/telemetry/project/ProjectCppAutoconfigTelemetryProviderTest.java @@ -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()); + } +} diff --git a/server/sonar-webserver-core/build.gradle b/server/sonar-webserver-core/build.gradle index ecdf1cac652..de12a259f89 100644 --- a/server/sonar-webserver-core/build.gradle +++ b/server/sonar-webserver-core/build.gradle @@ -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' diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterPlugins.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterPlugins.java index b606cb0045e..d28815c25f4 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterPlugins.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterPlugins.java @@ -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; diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 59d0d908787..00b667efed2 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -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, |