From e0f897e2673d97683ebaeb3751023cd14ea329fe Mon Sep 17 00:00:00 2001 From: Klaudio Sinani Date: Tue, 4 Oct 2022 08:49:07 +0200 Subject: [PATCH] SONAR-17110 Register events on default quality profile updates * SONAR-17110 Exit earlier if `activatedRules` & `activatedRules` are empty * SONAR-17110 Add unit-tests for `QualityProfileDao#selectDefaultProfileUuid` method + remove logging * SONAR-17110 Overall improvements * SONAR-17110 Minor overall improvements --- .../java/org/sonar/db/project/ProjectDao.java | 5 + .../org/sonar/db/project/ProjectMapper.java | 3 + .../db/qualityprofile/QualityProfileDao.java | 5 + .../qualityprofile/QualityProfileMapper.java | 3 + .../org/sonar/db/project/ProjectMapper.xml | 17 +++ .../qualityprofile/QualityProfileMapper.xml | 7 +- .../org/sonar/db/project/ProjectDaoTest.java | 64 ++++++++++ .../qualityprofile/QualityProfileDaoTest.java | 8 ++ .../QualityProfileChangeEventServiceImpl.java | 75 ++++++++++-- ...lityProfileChangeEventServiceImplTest.java | 113 ++++++++++++++++-- 10 files changed, 278 insertions(+), 22 deletions(-) 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 ca78366e668..1d6128551cf 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 @@ -121,4 +121,9 @@ public class ProjectDao implements Dao { public List selectAllProjectUuids(DbSession session) { return mapper(session).selectAllProjectUuids(); } + + public Set selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(DbSession session, String language) { + Set languageFilters = Set.of(language + "=%", "%;" + language + "=%"); + return mapper(session).selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(languageFilters); + } } 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 e2715aafa4f..3fc983b8eb4 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 @@ -21,6 +21,7 @@ package org.sonar.db.project; import java.util.Collection; import java.util.List; +import java.util.Set; import javax.annotation.CheckForNull; import org.apache.ibatis.annotations.Param; @@ -61,4 +62,6 @@ public interface ProjectMapper { List selectApplicationsByKeys(@Param("kees") Collection kees); List selectAllProjectUuids(); + + Set selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(@Param("languageFilters") Set languageFilters); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java index 7d2d4c1838b..0b261675573 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java @@ -154,6 +154,11 @@ public class QualityProfileDao implements Dao { return mapper(dbSession).selectDefaultProfile(language); } + @CheckForNull + public String selectDefaultProfileUuid(DbSession dbSession, String language) { + return mapper(dbSession).selectDefaultProfileUuid(language); + } + @CheckForNull public QProfileDto selectAssociatedToProjectAndLanguage(DbSession dbSession, ProjectDto project, String language) { return mapper(dbSession).selectAssociatedToProjectUuidAndLanguage(project.getUuid(), language); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java index 27fc6f28def..ec6a84fd1f2 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java @@ -57,6 +57,9 @@ public interface QualityProfileMapper { List selectDefaultProfiles( @Param("languages") Collection languages); + @CheckForNull + String selectDefaultProfileUuid(@Param("language") String language); + @CheckForNull QProfileDto selectByNameAndLanguage( @Param("name") String name, 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 c8dd6a244a3..87ee3c5edce 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 @@ -111,6 +111,23 @@ p.kee=#{key,jdbcType=VARCHAR} + + INSERT INTO projects ( kee, diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml index fdcd8dc0b56..a48cbe39e7e 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml @@ -139,6 +139,12 @@ and rp.language = dp.language + + - diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/project/ProjectDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/project/ProjectDaoTest.java index ea65092c688..bdf9822bc33 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/project/ProjectDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/project/ProjectDaoTest.java @@ -21,11 +21,13 @@ package org.sonar.db.project; 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.Optional; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.annotation.Nullable; @@ -38,7 +40,12 @@ import org.sonar.api.utils.System2; import org.sonar.db.DbTester; import org.sonar.db.audit.AuditPersister; import org.sonar.db.audit.NoOpAuditPersister; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.measure.LiveMeasureDto; +import org.sonar.db.metric.MetricDto; +import org.sonar.db.qualityprofile.QProfileDto; +import static org.apache.commons.lang.math.RandomUtils.nextInt; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; @@ -46,6 +53,8 @@ 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; public class ProjectDaoTest { @@ -257,6 +266,61 @@ public class ProjectDaoTest { verify(auditPersister, times(1)).updateComponent(any(), any()); } + @Test + public void select_project_uuids_associated_to_default_quality_profile_for_specific_language() { + String language = "xoo"; + Set projects = insertProjects(nextInt(10)); + insertDefaultQualityProfile(language); + insertProjectsLiveMeasures(language, projects); + + Set projectUuids = projectDao.selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(db.getSession(), language); + + assertThat(projectUuids) + .containsExactlyInAnyOrderElementsOf(extractComponentUuids(projects)); + } + + private void insertDefaultQualityProfile(String language) { + QProfileDto profile = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage(language)); + db.qualityProfiles().setAsDefault(profile); + } + + private static Set extractComponentUuids(Collection components) { + return components + .stream() + .map(ComponentDto::uuid) + .collect(Collectors.toSet()); + } + + private Set insertProjects(int number) { + return IntStream + .rangeClosed(0, number) + .mapToObj(x -> db.components().insertPrivateProject()) + .collect(Collectors.toSet()); + } + + private Consumer configureLiveMeasure(String language, MetricDto metric, ComponentDto project) { + return liveMeasure -> liveMeasure + .setMetricUuid(metric.getUuid()) + .setComponentUuid(project.uuid()) + .setProjectUuid(project.uuid()) + .setData(language + "=" + nextInt(10)); + } + + private Consumer insertLiveMeasure(String language, MetricDto metric) { + return project -> db.measures().insertLiveMeasure(project, metric, configureLiveMeasure(language, metric, project)); + } + + private void insertProjectsLiveMeasures(String language, Set projects) { + Consumer 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) { assertThat(dto).extracting("name", "kee", "key", "uuid", "description", "tagsString", "private") .containsExactly(name, kee, kee, uuid, desc, tags, isPrivate); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java index 4ad2feca805..dee8e09339f 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java @@ -342,6 +342,14 @@ public class QualityProfileDaoTest { assertThat(underTest.selectDefaultProfile(dbSession, "js")).isNull(); } + @Test + public void selectDefaultProfileUuid() { + createSharedData(); + + assertThat(underTest.selectDefaultProfileUuid(dbSession, "java")).isEqualTo("java_sonar_way"); + assertThat(underTest.selectDefaultProfileUuid(dbSession, "js")).isNull(); + } + @Test public void selectDefaultProfiles() { createSharedData(); diff --git a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImpl.java b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImpl.java index bb4bd7a0461..99e0c44a6eb 100644 --- a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImpl.java +++ b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImpl.java @@ -23,14 +23,15 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; @@ -52,6 +53,7 @@ import org.sonar.db.rule.RuleDto; import org.sonar.server.qualityprofile.ActiveRuleChange; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Collections.emptyList; import static java.util.function.Predicate.not; import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; @@ -198,13 +200,13 @@ public class QualityProfileChangeEventServiceImpl implements QualityProfileChang .map(RuleKey::toString) .collect(Collectors.toSet()); - Map projectKeyAndUuids = getProjectKeyAndUuids(profiles); - if (activatedRules.isEmpty() && deactivatedRules.isEmpty()) { return; } - for (Map.Entry entry : projectKeyAndUuids.entrySet()) { + Map projectsUuidByKey = getProjectsUuidByKey(profiles, language); + + for (Map.Entry entry : projectsUuidByKey.entrySet()) { persistPushEvent(entry.getKey(), activatedRules.toArray(new RuleChange[0]), deactivatedRules, language, entry.getValue()); } } @@ -238,19 +240,66 @@ public class QualityProfileChangeEventServiceImpl implements QualityProfileChang return Optional.empty(); } - private Map getProjectKeyAndUuids(Collection profiles) { - Map projectKeyAndUuids = new HashMap<>(); + private Map getProjectsUuidByKey(Collection profiles, String language) { try (DbSession dbSession = dbClient.openSession(false)) { - for (QProfileDto profileDto : profiles) { - List associationDtos = dbClient.qualityProfileDao().selectSelectedProjects(dbSession, profileDto, null); - for (ProjectQprofileAssociationDto associationDto : associationDtos) { - projectKeyAndUuids.put(associationDto.getProjectKey(), associationDto.getProjectUuid()); - } - } - return projectKeyAndUuids; + Map> profilesByDefaultStatus = classifyQualityProfilesByDefaultStatus(dbSession, profiles, language); + + List defaultAssociatedProjects = getDefaultAssociatedQualityProfileProjects(dbSession, profilesByDefaultStatus.get(true), language); + List manuallyAssociatedProjects = getManuallyAssociatedQualityProfileProjects(dbSession, profilesByDefaultStatus.get(false)); + + return Stream + .concat(manuallyAssociatedProjects.stream(), defaultAssociatedProjects.stream()) + .collect(Collectors.toMap(ProjectDto::getKey, ProjectDto::getUuid)); } } + private Map> classifyQualityProfilesByDefaultStatus(DbSession dbSession, Collection profiles, String language) { + String defaultQualityProfileUuid = dbClient.qualityProfileDao().selectDefaultProfileUuid(dbSession, language); + Predicate isDefaultQualityProfile = profile -> profile.getKee().equals(defaultQualityProfileUuid); + + return profiles + .stream() + .collect(Collectors.partitioningBy(isDefaultQualityProfile)); + } + + private List getDefaultAssociatedQualityProfileProjects(DbSession dbSession, List defaultProfiles, String language) { + if (defaultProfiles.isEmpty()) { + return emptyList(); + } + + return getDefaultQualityProfileAssociatedProjects(dbSession, language); + } + + private List getDefaultQualityProfileAssociatedProjects(DbSession dbSession, String language) { + Set associatedProjectUuids = dbClient.projectDao().selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(dbSession, language); + return dbClient.projectDao().selectByUuids(dbSession, associatedProjectUuids); + } + + private List getManuallyAssociatedQualityProfileProjects(DbSession dbSession, List profiles) { + return profiles + .stream() + .map(profile -> getQualityProfileAssociatedProjects(dbSession, profile)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List getQualityProfileAssociatedProjects(DbSession dbSession, QProfileDto profile) { + Set projectUuids = getQualityProfileAssociatedProjectUuids(dbSession, profile); + return dbClient.projectDao().selectByUuids(dbSession, projectUuids); + } + + private Set getQualityProfileAssociatedProjectUuids(DbSession dbSession, QProfileDto profile) { + List associations = dbClient.qualityProfileDao().selectSelectedProjects(dbSession, profile, null); + + return associations + .stream() + .map(ProjectQprofileAssociationDto::getProjectUuid) + .collect(Collectors.toSet()); + } + + + + private static byte[] serializeIssueToPushEvent(RuleSetChangedEvent event) { return GSON.toJson(event).getBytes(UTF_8); } diff --git a/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImplTest.java b/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImplTest.java index 1cab5c35a69..3bc395f22c0 100644 --- a/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImplTest.java +++ b/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/qualityprofile/QualityProfileChangeEventServiceImplTest.java @@ -23,11 +23,16 @@ import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Collections; import java.util.Deque; +import java.util.List; import java.util.Set; +import java.util.function.Consumer; import org.junit.Rule; import org.junit.Test; import org.sonar.api.rule.RuleKey; import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +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; @@ -41,7 +46,10 @@ import org.sonarqube.ws.Common; import static java.util.List.of; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.apache.commons.lang.math.RandomUtils.nextInt; 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; @@ -67,10 +75,7 @@ public class QualityProfileChangeEventServiceImplTest { .setDescriptionFormat(RuleDto.Format.MARKDOWN); db.rules().insert(rule1); - ActiveRuleDto activeRuleDto = ActiveRuleDto.createFor(qualityProfileDto, rule1); - - ActiveRuleChange activeRuleChange = new ActiveRuleChange(ACTIVATED, activeRuleDto, rule1); - activeRuleChange.setParameter("paramChangeKey", "paramChangeValue"); + ActiveRuleChange activeRuleChange = changeActiveRule(qualityProfileDto, rule1, "paramChangeKey", "paramChangeValue"); Collection profiles = Collections.singleton(qualityProfileDto); @@ -79,8 +84,7 @@ public class QualityProfileChangeEventServiceImplTest { underTest.distributeRuleChangeEvent(profiles, of(activeRuleChange), "xoo"); - Deque events = db.getDbClient().pushEventDao() - .selectChunkByProjectUuids(db.getSession(), Set.of(project.getUuid()), 1l, null, 1); + Deque events = getProjectEvents(project.getUuid()); assertThat(events).isNotEmpty().hasSize(1); assertThat(events.getFirst()) @@ -97,6 +101,80 @@ public class QualityProfileChangeEventServiceImplTest { "\"deactivatedRules\":[]"); } + @Test + public void distributeRuleChangeEvent_when_project_has_only_default_quality_profiles() { + String language = "xoo"; + ComponentDto project = db.components().insertPrivateProject(); + RuleDto templateRule = insertTemplateRule(); + QProfileDto defaultQualityProfile = insertDefaultQualityProfile(language); + RuleDto rule = insertCustomRule(templateRule, language, "
line1\nline2
"); + ActiveRuleChange activeRuleChange = changeActiveRule(defaultQualityProfile, rule, "paramChangeKey", "paramChangeValue"); + insertQualityProfileLiveMeasure(project, language, NCLOC_LANGUAGE_DISTRIBUTION_KEY); + + db.getSession().commit(); + + underTest.distributeRuleChangeEvent(List.of(defaultQualityProfile), of(activeRuleChange), language); + + Deque events = getProjectEvents(project.projectUuid()); + + assertThat(events) + .hasSize(1); + + assertThat(events.getFirst()) + .extracting(PushEventDto::getName, PushEventDto::getLanguage) + .contains("RuleSetChanged", "xoo"); + + String ruleSetChangedEvent = new String(events.getFirst().getPayload(), StandardCharsets.UTF_8); + + assertThat(ruleSetChangedEvent) + .contains("\"activatedRules\":[{\"key\":\"repo:ruleKey\"," + + "\"language\":\"xoo\"," + + "\"templateKey\":\"xoo:template-key\"," + + "\"params\":[{\"key\":\"paramChangeKey\",\"value\":\"paramChangeValue\"}]}]," + + "\"deactivatedRules\":[]"); + } + + private Deque getProjectEvents(String projectUuid) { + return db.getDbClient() + .pushEventDao() + .selectChunkByProjectUuids(db.getSession(), Set.of(projectUuid), 1L, null, 1); + } + + private ActiveRuleChange changeActiveRule(QProfileDto defaultQualityProfile, RuleDto rule, String changeKey, String changeValue) { + ActiveRuleDto activeRuleDto = ActiveRuleDto.createFor(defaultQualityProfile, rule); + ActiveRuleChange activeRuleChange = new ActiveRuleChange(ACTIVATED, activeRuleDto, rule); + return activeRuleChange.setParameter(changeKey, changeValue); + } + + private RuleDto insertCustomRule(RuleDto templateRule, String language, String description) { + RuleDto rule = newCustomRule(templateRule, description) + .setLanguage(language) + .setRepositoryKey("repo") + .setRuleKey("ruleKey") + .setDescriptionFormat(RuleDto.Format.MARKDOWN); + + db.rules().insert(rule); + return rule; + } + + private QProfileDto insertDefaultQualityProfile(String language) { + Consumer configureQualityProfile = profile -> profile + .setIsBuiltIn(true) + .setLanguage(language); + + QProfileDto defaultQualityProfile = db.qualityProfiles().insert(configureQualityProfile); + db.qualityProfiles().setAsDefault(defaultQualityProfile); + + return defaultQualityProfile; + } + + private RuleDto insertTemplateRule() { + RuleKey key = RuleKey.of("xoo", "template-key"); + RuleDto templateRule = newTemplateRule(key); + db.rules().insert(templateRule); + return templateRule; + } + @Test public void publishRuleActivationToSonarLintClients() { ProjectDto projectDao = new ProjectDto().setUuid("project-uuid"); @@ -123,8 +201,7 @@ public class QualityProfileChangeEventServiceImplTest { underTest.publishRuleActivationToSonarLintClients(projectDao, activatedQualityProfile, deactivatedQualityProfile); - Deque events = db.getDbClient().pushEventDao() - .selectChunkByProjectUuids(db.getSession(), Set.of(projectDao.getUuid()), 1l, null, 1); + Deque events = getProjectEvents(projectDao.getUuid()); assertThat(events).isNotEmpty().hasSize(1); assertThat(events.getFirst()) @@ -140,4 +217,24 @@ public class QualityProfileChangeEventServiceImplTest { "\"deactivatedRules\":[\"repo2:ruleKey2\"]"); } + private void insertQualityProfileLiveMeasure(ComponentDto project, String language, String metricKey) { + MetricDto metric = insertMetric(metricKey); + + Consumer configureLiveMeasure = liveMeasure -> liveMeasure + .setMetricUuid(metric.getUuid()) + .setComponentUuid(project.uuid()) + .setProjectUuid(project.uuid()) + .setData(language + "=" + nextInt(10)); + + db.measures().insertLiveMeasure(project, metric, configureLiveMeasure); + } + + private MetricDto insertMetric(String metricKey) { + Consumer configureMetric = metric -> metric + .setUuid("uuid") + .setValueType(STRING.name()) + .setKey(metricKey); + + return db.measures().insertMetric(configureMetric); + } } -- 2.39.5