diff options
author | Pierre Guillot <pierre.guillot@sonarsource.com> | 2024-12-10 15:29:09 +0100 |
---|---|---|
committer | Steve Marion <steve.marion@sonarsource.com> | 2024-12-18 11:13:21 +0100 |
commit | d639a965bce7acafb004906cd07a8f0b5f7af993 (patch) | |
tree | 647cd646abddb12dfeeef7e637aa33b4658f1049 /server/sonar-server-common | |
parent | 451c1c2e4856ec3df87f86189fcdb25b31794027 (diff) | |
download | sonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.tar.gz sonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.zip |
SONAR-22998 fetch active rules with a dedicated endpoint
Co-authored-by: Julien HENRY <julien.henry@sonarsource.com>
Diffstat (limited to 'server/sonar-server-common')
3 files changed, 506 insertions, 0 deletions
diff --git a/server/sonar-server-common/src/it/java/org/sonar/server/rule/ActiveRuleServiceIT.java b/server/sonar-server-common/src/it/java/org/sonar/server/rule/ActiveRuleServiceIT.java new file mode 100644 index 00000000000..2d36a185236 --- /dev/null +++ b/server/sonar-server-common/src/it/java/org/sonar/server/rule/ActiveRuleServiceIT.java @@ -0,0 +1,206 @@ +/* + * 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.server.rule; + +import java.util.List; +import org.assertj.core.groups.Tuple; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.Languages; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; +import org.sonar.db.component.ProjectData; +import org.sonar.db.qualityprofile.ActiveRuleDto; +import org.sonar.db.qualityprofile.ActiveRuleKey; +import org.sonar.db.qualityprofile.ActiveRuleParamDto; +import org.sonar.db.qualityprofile.QProfileDto; +import org.sonar.db.rule.RuleDto; +import org.sonar.db.rule.RuleParamDto; +import org.sonar.server.rule.ActiveRuleRestReponse.ActiveRule; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.api.utils.DateUtils.formatDateTime; + +class ActiveRuleServiceIT { + + public static final Language XOO_LANGUAGE = mock(Language.class); + public static final Language XOO2_LANGUAGE = mock(Language.class); + + public static final String XOO_LANGUAGE_KEY = "xoo"; + public static final String XOO2_LANGUAGE_KEY = "xoo2"; + + static { + when(XOO_LANGUAGE.getKey()).thenReturn(XOO_LANGUAGE_KEY); + when(XOO2_LANGUAGE.getKey()).thenReturn(XOO2_LANGUAGE_KEY); + } + + @RegisterExtension + DbTester db = DbTester.create(System2.INSTANCE); + + private final ActiveRuleService activeRuleService = new ActiveRuleService(db.getDbClient(), new Languages(XOO_LANGUAGE, XOO2_LANGUAGE)); + + @Test + void buildDefaultActiveRules() { + QProfileDto qProfileDto1 = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO_LANGUAGE_KEY)); + db.qualityProfiles().setAsDefault(qProfileDto1); + RuleDto rule1 = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY), r -> r.setName("rule1")); + ActiveRuleDto activatedRule1 = db.qualityProfiles().activateRule(qProfileDto1, rule1); + RuleDto rule2 = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY), r -> r.setName("rule2")); + ActiveRuleDto activatedRule2 = db.qualityProfiles().activateRule(qProfileDto1, rule2); + + QProfileDto qProfileDto2 = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO2_LANGUAGE_KEY)); + db.qualityProfiles().setAsDefault(qProfileDto2); + RuleDto rule3 = db.rules().insert(r -> r.setLanguage(XOO2_LANGUAGE_KEY), r -> r.setName("rule3")); + ActiveRuleDto activatedRule3 = db.qualityProfiles().activateRule(qProfileDto2, rule3); + + List<ActiveRule> activeRules = activeRuleService.buildDefaultActiveRules(); + assertThat(activeRules).isNotNull().hasSize(3) + .extracting(ActiveRule::ruleKey, ActiveRule::name, ActiveRule::severity, + ActiveRule::createdAt, ActiveRule::updatedAt, ActiveRule::internalKey, + ActiveRule::language, ActiveRule::templateRuleKey, ActiveRule::qProfileKey, + ActiveRule::deprecatedKeys, ActiveRule::params) + .containsExactlyInAnyOrder( + toTuple(activatedRule1, XOO_LANGUAGE_KEY, qProfileDto1, List.of()), + toTuple(activatedRule2, XOO_LANGUAGE_KEY, qProfileDto1, List.of()), + toTuple(activatedRule3, XOO2_LANGUAGE_KEY, qProfileDto2, List.of())); + } + + @Test + void buildActiveRule_with_default_profile() { + QProfileDto qProfileDto1 = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO_LANGUAGE_KEY)); + db.qualityProfiles().setAsDefault(qProfileDto1); + RuleDto rule1 = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY), r -> r.setName("rule1")); + ActiveRuleDto activatedRule1 = db.qualityProfiles().activateRule(qProfileDto1, rule1); + RuleDto rule2 = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY), r -> r.setName("rule2")); + ActiveRuleDto activatedRule2 = db.qualityProfiles().activateRule(qProfileDto1, rule2); + + QProfileDto qProfileDto2 = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO2_LANGUAGE_KEY)); + db.qualityProfiles().setAsDefault(qProfileDto2); + RuleDto rule3 = db.rules().insert(r -> r.setLanguage(XOO2_LANGUAGE_KEY), r -> r.setName("rule3")); + ActiveRuleDto activatedRule3 = db.qualityProfiles().activateRule(qProfileDto2, rule3); + + var removedLanguageKey = "removed"; + QProfileDto qProfileDtoRemovedLanguage = db.qualityProfiles().insert(qp -> qp.setLanguage(removedLanguageKey)); + db.qualityProfiles().setAsDefault(qProfileDtoRemovedLanguage); + RuleDto ruleRemovedLanguage = db.rules().insert(r -> r.setLanguage(removedLanguageKey), r -> r.setName("ruleRemovedLanguage")); + db.qualityProfiles().activateRule(qProfileDtoRemovedLanguage, ruleRemovedLanguage); + + List<ActiveRule> activeRules = activeRuleService.buildActiveRules("myProjectUuid"); + assertThat(activeRules).isNotNull().hasSize(3) + .extracting(ActiveRule::ruleKey, ActiveRule::name, ActiveRule::severity, + ActiveRule::createdAt, ActiveRule::updatedAt, ActiveRule::internalKey, + ActiveRule::language, ActiveRule::templateRuleKey, ActiveRule::qProfileKey, + ActiveRule::deprecatedKeys, ActiveRule::params) + .containsExactlyInAnyOrder( + toTuple(activatedRule1, XOO_LANGUAGE_KEY, qProfileDto1, List.of()), + toTuple(activatedRule2, XOO_LANGUAGE_KEY, qProfileDto1, List.of()), + toTuple(activatedRule3, XOO2_LANGUAGE_KEY, qProfileDto2, List.of())); + } + + @Test + void projectProfile_overrides_defaultProfile() { + QProfileDto qProfileDto1 = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO_LANGUAGE_KEY)); + db.qualityProfiles().setAsDefault(qProfileDto1); + RuleDto rule1 = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY), r -> r.setName("rule1")); + db.qualityProfiles().activateRule(qProfileDto1, rule1); + + QProfileDto qProfileDto2 = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO_LANGUAGE_KEY)); + ProjectData project = db.components().insertPrivateProject(); + db.qualityProfiles().associateWithProject(project.getProjectDto(), qProfileDto2); + ActiveRuleDto activatedRule2 = db.qualityProfiles().activateRule(qProfileDto2, rule1); + + List<ActiveRule> activeRules = activeRuleService.buildActiveRules(project.projectUuid()); + assertThat(activeRules).hasSize(1) + .extracting(ActiveRule::ruleKey, ActiveRule::name, ActiveRule::severity, + ActiveRule::createdAt, ActiveRule::updatedAt, ActiveRule::internalKey, + ActiveRule::language, ActiveRule::templateRuleKey, ActiveRule::qProfileKey, + ActiveRule::deprecatedKeys, ActiveRule::params) + .containsExactlyInAnyOrder( + toTuple(activatedRule2, XOO_LANGUAGE_KEY, qProfileDto2, List.of())); + } + + @Test + void customRuleParam_overrides_defaultRuleParamValue() { + RuleDto rule = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY), r -> r.setName("rule")); + RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setDefaultValue("defaultValue")); + QProfileDto defaultQualityProfile = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO_LANGUAGE_KEY)); + db.qualityProfiles().setAsDefault(defaultQualityProfile); + db.qualityProfiles().activateRule(defaultQualityProfile, rule); + + QProfileDto qProfileDto2 = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO_LANGUAGE_KEY)); + ProjectData project = db.components().insertPrivateProject(); + db.qualityProfiles().associateWithProject(project.getProjectDto(), qProfileDto2); + ActiveRuleDto activatedRule2 = db.qualityProfiles().activateRule(qProfileDto2, rule); + db.getDbClient().activeRuleDao().insertParam(db.getSession(), activatedRule2, new ActiveRuleParamDto() + .setRulesParameterUuid(ruleParam.getUuid()) + .setKey(ruleParam.getName()) + .setValue("overriddenValue")); + + db.commit(); + + List<ActiveRule> activeRules = activeRuleService.buildActiveRules(project.projectUuid()); + assertThat(activeRules).hasSize(1) + .extracting(ActiveRule::ruleKey, ActiveRule::name, ActiveRule::severity, + ActiveRule::createdAt, ActiveRule::updatedAt, ActiveRule::internalKey, + ActiveRule::language, ActiveRule::templateRuleKey, ActiveRule::qProfileKey, + ActiveRule::deprecatedKeys, ActiveRule::params) + .containsExactlyInAnyOrder( + toTuple(activatedRule2, XOO_LANGUAGE_KEY, qProfileDto2, List.of(new ActiveRuleRestReponse.Param(ruleParam.getName(), "overriddenValue")))); + } + + @Test + void returnsRuleTemplate() { + RuleDto templateRule = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY) + .setIsTemplate(true)); + RuleDto rule = db.rules().insert(r -> r.setLanguage(XOO_LANGUAGE_KEY) + .setTemplateUuid(templateRule.getUuid())); + RuleParamDto ruleParam = db.rules().insertRuleParam(rule); + QProfileDto defaultQualityProfile = db.qualityProfiles().insert(qp -> qp.setLanguage(XOO_LANGUAGE_KEY)); + db.qualityProfiles().setAsDefault(defaultQualityProfile); + ActiveRuleDto activeRule = db.qualityProfiles().activateRule(defaultQualityProfile, rule); + ProjectData project = db.components().insertPrivateProject(); + + List<ActiveRule> activeRules = activeRuleService.buildActiveRules(project.projectUuid()); + assertThat(activeRules).hasSize(1) + .extracting(ActiveRule::ruleKey, ActiveRule::name, ActiveRule::severity, + ActiveRule::createdAt, ActiveRule::updatedAt, ActiveRule::internalKey, + ActiveRule::language, ActiveRule::templateRuleKey, ActiveRule::qProfileKey, + ActiveRule::deprecatedKeys, ActiveRule::params) + .containsExactlyInAnyOrder( + tuple(toRuleKey(activeRule.getKey()), activeRule.getName(), activeRule.getSeverityString(), formatDateTime(activeRule.getCreatedAt()), + formatDateTime(activeRule.getUpdatedAt()), activeRule.getConfigKey(), XOO_LANGUAGE_KEY, templateRule.getKey().toString(), defaultQualityProfile.getKee(), List.of(), + List.of(new ActiveRuleRestReponse.Param(ruleParam.getName(), ruleParam.getDefaultValue())))); + + } + + private Tuple toTuple(ActiveRuleDto activatedRule, String language, QProfileDto qProfileDto, List<ActiveRuleRestReponse.Param> expectedParams) { + return tuple(toRuleKey(activatedRule.getKey()), activatedRule.getName(), activatedRule.getSeverityString(), formatDateTime(activatedRule.getCreatedAt()), + formatDateTime(activatedRule.getUpdatedAt()), activatedRule.getConfigKey(), language, null, qProfileDto.getKee(), List.of(), expectedParams); + } + + private ActiveRuleRestReponse.RuleKey toRuleKey(ActiveRuleKey key) { + return new ActiveRuleRestReponse.RuleKey(key.getRuleKey().repository(), key.getRuleKey().rule()); + } + +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/ActiveRuleRestReponse.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/ActiveRuleRestReponse.java new file mode 100644 index 00000000000..f802e7f004d --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/ActiveRuleRestReponse.java @@ -0,0 +1,123 @@ +/* + * 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.server.rule; + +import com.fasterxml.jackson.annotation.JsonInclude; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; +import org.sonar.api.issue.impact.Severity; +import org.sonar.api.issue.impact.SoftwareQuality; + +public class ActiveRuleRestReponse { + + public record ActiveRule( + RuleKey ruleKey, + String name, + String severity, + String createdAt, + String updatedAt, + @JsonInclude(JsonInclude.Include.NON_NULL) @Nullable String internalKey, + String language, + @JsonInclude(JsonInclude.Include.NON_NULL) @Nullable String templateRuleKey, + String qProfileKey, + @JsonInclude(JsonInclude.Include.NON_EMPTY) List<RuleKey> deprecatedKeys, + @JsonInclude(JsonInclude.Include.NON_EMPTY) List<Param> params, + @JsonInclude(JsonInclude.Include.NON_EMPTY) Map<SoftwareQuality, Severity> impacts) { + } + + public record RuleKey(String repository, String rule) { + } + + public record Param(String key, String value) { + } + + public static class Builder { + private RuleKey ruleKey; + private String name; + private String severity; + private String createdAt; + private String updatedAt; + private String internalKey; + private String language; + private String templateRuleKey; + private String qProfilKey; + private final List<RuleKey> deprecatedKeys = new ArrayList<>(); + private final List<Param> params = new ArrayList<>(); + private final Map<SoftwareQuality, Severity> impacts = new EnumMap<>(SoftwareQuality.class); + + public void setRuleKey(RuleKey ruleKey) { + this.ruleKey = ruleKey; + } + + public void setName(String name) { + this.name = name; + } + + public void setSeverity(String severity) { + this.severity = severity; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + + public void setInternalKey(String internalKey) { + this.internalKey = internalKey; + } + + public void setLanguage(String language) { + this.language = language; + } + + public void setTemplateRuleKey(String templateRuleKey) { + this.templateRuleKey = templateRuleKey; + } + + public void setQProfilKey(String qProfilKey) { + this.qProfilKey = qProfilKey; + } + + public void setParams(List<Param> params) { + this.params.clear(); + this.params.addAll(params); + } + + public void addAllDeprecatedKeys(List<RuleKey> deprecatedKeys) { + this.deprecatedKeys.addAll(deprecatedKeys); + } + + public void setImpacts(Map<SoftwareQuality, Severity> impacts) { + this.impacts.clear(); + this.impacts.putAll(impacts); + } + + public ActiveRule build() { + return new ActiveRule(ruleKey, name, severity, createdAt, updatedAt, internalKey, language, templateRuleKey, qProfilKey, deprecatedKeys, params, impacts); + } + } + +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/ActiveRuleService.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/ActiveRuleService.java new file mode 100644 index 00000000000..5a7960a6010 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/ActiveRuleService.java @@ -0,0 +1,177 @@ +/* + * 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.server.rule; + +import com.google.common.base.Strings; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.Languages; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.DateUtils; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.qualityprofile.ActiveRuleParamDto; +import org.sonar.db.qualityprofile.OrgActiveRuleDto; +import org.sonar.db.qualityprofile.QProfileDto; +import org.sonar.db.rule.DeprecatedRuleKeyDto; +import org.sonar.db.rule.RuleDto; +import org.sonar.db.rule.RuleParamDto; + +import static java.util.Optional.ofNullable; + +public class ActiveRuleService { + + private final DbClient dbClient; + private final Languages languages; + + public ActiveRuleService(DbClient dbClient, Languages languages) { + this.dbClient = dbClient; + this.languages = languages; + } + + public List<ActiveRuleRestReponse.ActiveRule> buildDefaultActiveRules() { + try (DbSession dbSession = dbClient.openSession(false)) { + List<QProfileDto> qualityProfiles = dbClient.qualityProfileDao().selectDefaultProfiles(dbSession, getLanguageKeys()); + return loadActiveRules(qualityProfiles, dbSession); + } + } + + public List<ActiveRuleRestReponse.ActiveRule> buildActiveRules(String projectUuid) { + try (DbSession dbSession = dbClient.openSession(false)) { + List<QProfileDto> qualityProfiles = getQualityProfiles(dbSession, projectUuid); + return loadActiveRules(qualityProfiles, dbSession); + } + } + + private Set<String> getLanguageKeys() { + return Arrays.stream(languages.all()).map(Language::getKey).collect(Collectors.toSet()); + } + + private List<ActiveRuleRestReponse.ActiveRule> loadActiveRules(List<QProfileDto> qualityProfiles, DbSession dbSession) { + + Map<String, QProfileDto> profilesByUuids = qualityProfiles.stream().collect(Collectors.toMap(QProfileDto::getKee, Function.identity())); + + Map<String, List<RuleParamDto>> ruleParamsByRuleUuid = dbClient.ruleDao().selectAllRuleParams(dbSession).stream() + .collect(Collectors.groupingBy(RuleParamDto::getRuleUuid)); + + Map<String, List<ActiveRuleParamDto>> activeRuleParamsByActiveRuleUuid = dbClient.activeRuleDao().selectAllParamsByProfileUuids(dbSession, profilesByUuids.keySet()).stream() + .collect(Collectors.groupingBy(ActiveRuleParamDto::getActiveRuleUuid)); + + List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByProfileUuids(dbSession, profilesByUuids.keySet()); + Map<String, RuleDto> templateRulesByUuid = getTemplateRulesByUuid(dbSession, activeRuleDtos); + Map<String, List<DeprecatedRuleKeyDto>> deprecatedRuleKeysByRuleUuid = getDeprecatedRuleKeysByRuleUuid(dbSession); + + return activeRuleDtos.stream() + .map( + activeRuleDto -> buildActiveRule(activeRuleDto, profilesByUuids, templateRulesByUuid, deprecatedRuleKeysByRuleUuid, ruleParamsByRuleUuid, activeRuleParamsByActiveRuleUuid)) + .toList(); + } + + private static ActiveRuleRestReponse.ActiveRule buildActiveRule(OrgActiveRuleDto activeRuleDto, + Map<String, QProfileDto> profilesByUuids, + Map<String, RuleDto> templateRulesByUuid, + Map<String, List<DeprecatedRuleKeyDto>> deprecatedRuleKeysByRuleUuid, + Map<String, List<RuleParamDto>> ruleParamsByRuleUuid, + Map<String, List<ActiveRuleParamDto>> activeRuleParamsByActiveRuleUuid) { + ActiveRuleRestReponse.Builder activeRuleBuilder = new ActiveRuleRestReponse.Builder(); + activeRuleBuilder.setRuleKey(toRuleKey(activeRuleDto.getRuleKey())); + activeRuleBuilder.setName(activeRuleDto.getName()); + activeRuleBuilder.setSeverity(activeRuleDto.getSeverityString()); + activeRuleBuilder.setCreatedAt(DateUtils.formatDateTime(activeRuleDto.getCreatedAt())); + activeRuleBuilder.setUpdatedAt(DateUtils.formatDateTime(activeRuleDto.getUpdatedAt())); + // same as RuleForIndexingDto mapping + activeRuleBuilder.setInternalKey(activeRuleDto.getConfigKey()); + activeRuleBuilder.setQProfilKey(profilesByUuids.get(activeRuleDto.getOrgProfileUuid()).getKee()); + activeRuleBuilder.setLanguage(activeRuleDto.getLanguage()); + Optional<RuleDto> templateRule = ofNullable(templateRulesByUuid.get(activeRuleDto.getTemplateUuid())); + templateRule.ifPresent(template -> activeRuleBuilder.setTemplateRuleKey(template.getKey().toString())); + + List<ActiveRuleRestReponse.RuleKey> deprecatedKeys = buildDeprecatedKeys(activeRuleDto, deprecatedRuleKeysByRuleUuid); + activeRuleBuilder.addAllDeprecatedKeys(deprecatedKeys); + + List<RuleParamDto> ruleParams = ruleParamsByRuleUuid.get(activeRuleDto.getRuleUuid()); + List<ActiveRuleParamDto> activeRuleParams = ofNullable(activeRuleParamsByActiveRuleUuid.get(activeRuleDto.getUuid())).orElse(List.of()); + List<ActiveRuleRestReponse.Param> params = buildParams(ruleParams, activeRuleParams); + activeRuleBuilder.setParams(params); + + activeRuleBuilder.setImpacts(activeRuleDto.getImpacts()); + + return activeRuleBuilder.build(); + } + + private static List<ActiveRuleRestReponse.Param> buildParams(@Nullable List<RuleParamDto> ruleParams, List<ActiveRuleParamDto> activeRuleParams) { + if (ruleParams == null) { + return List.of(); + } + return ruleParams.stream() + .map(parameter -> { + Optional<ActiveRuleParamDto> activeRuleParamDto = activeRuleParams.stream() + .filter(arp -> arp.getRulesParameterUuid().equals(parameter.getUuid())) + .findAny(); + String paramValue = activeRuleParamDto.map(ActiveRuleParamDto::getValue).orElse(parameter.getDefaultValue()); + return new ActiveRuleRestReponse.Param(parameter.getName(), Strings.nullToEmpty(paramValue)); + }) + .toList(); + } + + private static List<ActiveRuleRestReponse.RuleKey> buildDeprecatedKeys(OrgActiveRuleDto activeRuleDto, Map<String, List<DeprecatedRuleKeyDto>> deprecatedRuleKeysByRuleUuid) { + List<DeprecatedRuleKeyDto> deprecatedRuleKeyDtos = deprecatedRuleKeysByRuleUuid.getOrDefault(activeRuleDto.getUuid(), List.of()); + return deprecatedRuleKeyDtos.stream() + .map(ActiveRuleService::toRuleKey) + .toList(); + } + + private List<QProfileDto> getQualityProfiles(DbSession dbSession, String projectUuid) { + List<QProfileDto> defaultProfiles = dbClient.qualityProfileDao().selectDefaultProfiles(dbSession, getLanguageKeys()); + Map<String, QProfileDto> projectProfiles = dbClient.qualityProfileDao().selectAssociatedToProjectAndLanguages(dbSession, projectUuid, getLanguageKeys()) + .stream().collect(Collectors.toMap(QProfileDto::getLanguage, Function.identity())); + + return defaultProfiles.stream() + .map(defaultProfile -> projectProfiles.getOrDefault(defaultProfile.getLanguage(), defaultProfile)) + .toList(); + } + + private Map<String, RuleDto> getTemplateRulesByUuid(DbSession dbSession, List<OrgActiveRuleDto> activeRuleDtos) { + Set<String> templateRuleUuids = activeRuleDtos.stream().map(OrgActiveRuleDto::getTemplateUuid).filter(Objects::nonNull).collect(Collectors.toSet()); + return dbClient.ruleDao().selectByUuids(dbSession, templateRuleUuids).stream().collect(Collectors.toMap(RuleDto::getUuid, p -> p)); + } + + private static ActiveRuleRestReponse.RuleKey toRuleKey(RuleKey ruleKey) { + return new ActiveRuleRestReponse.RuleKey(ruleKey.repository(), ruleKey.rule()); + } + + private static ActiveRuleRestReponse.RuleKey toRuleKey(DeprecatedRuleKeyDto r) { + return new ActiveRuleRestReponse.RuleKey(r.getOldRepositoryKey(), r.getOldRuleKey()); + } + + private Map<String, List<DeprecatedRuleKeyDto>> getDeprecatedRuleKeysByRuleUuid(DbSession dbSession) { + return dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbSession).stream() + .collect(Collectors.groupingBy(DeprecatedRuleKeyDto::getRuleUuid)); + } + +} |