From: Dejan Milisavljevic Date: Fri, 11 Oct 2024 08:27:08 +0000 (+0200) Subject: SONAR-23260 Publish impact changes to SonarQube IDE X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b674c5e3184ceeab636035f733aae09269dbdc8c;p=sonarqube.git SONAR-23260 Publish impact changes to SonarQube IDE --- diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDto.java index 8e08e754dc5..906cdb4a2c7 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDto.java @@ -214,6 +214,7 @@ public class ActiveRuleDto { dto.setProfileUuid(profile.getRulesProfileUuid()); dto.setRuleUuid(ruleDto.getUuid()); dto.setKey(ActiveRuleKey.of(profile, ruleDto.getKey())); + dto.setImpacts(ruleDto.getDefaultImpactsMap()); return dto; } 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 ddffddaab99..a0dda22d239 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 @@ -105,15 +105,17 @@ public class QualityProfileChangeEventServiceImpl implements QualityProfileChang Map> paramsByActiveRuleUuid = dbClient.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, activeRuleUuids) .stream().collect(Collectors.groupingBy(ActiveRuleParamDto::getActiveRuleUuid)); - Map activeRuleUuidByRuleUuid = activeRuleDtos.stream().collect(Collectors.toMap(ActiveRuleDto::getRuleUuid, ActiveRuleDto::getUuid)); + Map activeRuleByRuleUuid = activeRuleDtos.stream().collect(Collectors.toMap(ActiveRuleDto::getRuleUuid, + r -> r)); List ruleUuids = activeRuleDtos.stream().map(ActiveRuleDto::getRuleUuid).toList(); List ruleDtos = dbClient.ruleDao().selectByUuids(dbSession, ruleUuids); for (RuleDto ruleDto : ruleDtos) { - String activeRuleUuid = activeRuleUuidByRuleUuid.get(ruleDto.getUuid()); + OrgActiveRuleDto activeRule = activeRuleByRuleUuid.get(ruleDto.getUuid()); + String activeRuleUuid = activeRule.getUuid(); List params = paramsByActiveRuleUuid.getOrDefault(activeRuleUuid, new ArrayList<>()); - RuleChange ruleChange = toRuleChange(ruleDto, params); + RuleChange ruleChange = toRuleChange(ruleDto, activeRule, params); ruleChanges.add(ruleChange); } } @@ -137,11 +139,12 @@ public class QualityProfileChangeEventServiceImpl implements QualityProfileChang } @NotNull - private RuleChange toRuleChange(RuleDto ruleDto, List activeRuleParamDtos) { + private RuleChange toRuleChange(RuleDto ruleDto, OrgActiveRuleDto activeRule, List activeRuleParamDtos) { RuleChange ruleChange = new RuleChange(); ruleChange.setKey(ruleDto.getKey().toString()); ruleChange.setLanguage(ruleDto.getLanguage()); - ruleChange.setSeverity(ruleDto.getSeverityString()); + ruleChange.setSeverity(activeRule.getSeverityString()); + activeRule.getImpacts().forEach(ruleChange::addImpact); List paramChanges = new ArrayList<>(); for (ActiveRuleParamDto activeRuleParam : activeRuleParamDtos) { @@ -179,6 +182,8 @@ public class QualityProfileChangeEventServiceImpl implements QualityProfileChang ruleChange.setSeverity(arc.getSeverity()); ruleChange.setLanguage(language); + arc.getImpactSeverities().forEach(ruleChange::addImpact); + Optional templateKey = templateKey(arc); templateKey.ifPresent(ruleChange::setTemplateKey); @@ -313,9 +318,6 @@ public class QualityProfileChangeEventServiceImpl implements QualityProfileChang .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 0ba4583234b..c6fee35dd7d 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 @@ -24,10 +24,14 @@ import java.util.Collection; import java.util.Collections; import java.util.Deque; import java.util.List; +import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.function.Consumer; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.sonar.api.issue.impact.Severity; +import org.sonar.api.issue.impact.SoftwareQuality; import org.sonar.api.rule.RuleKey; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; @@ -41,7 +45,6 @@ import org.sonar.db.qualityprofile.QualityProfileTesting; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleParamDto; import org.sonar.server.qualityprofile.ActiveRuleChange; -import org.sonarqube.ws.Common; import static java.util.List.of; import static org.apache.commons.lang3.RandomStringUtils.secure; @@ -51,15 +54,14 @@ 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 { +class QualityProfileChangeEventServiceImplTest { - @Rule - public DbTester db = DbTester.create(); - - public final QualityProfileChangeEventServiceImpl underTest = new QualityProfileChangeEventServiceImpl(db.getDbClient()); + @RegisterExtension + private final DbTester db = DbTester.create(); + private final QualityProfileChangeEventServiceImpl underTest = new QualityProfileChangeEventServiceImpl(db.getDbClient()); @Test - public void distributeRuleChangeEvent() { + void distributeRuleChangeEvent() { QProfileDto qualityProfileDto = QualityProfileTesting.newQualityProfileDto(); RuleDto templateRule = newTemplateRule(RuleKey.of("xoo", "template-key")); @@ -73,6 +75,7 @@ public class QualityProfileChangeEventServiceImplTest { db.rules().insert(rule1); ActiveRuleChange activeRuleChange = changeActiveRule(qualityProfileDto, rule1, "paramChangeKey", "paramChangeValue"); + activeRuleChange.setImpactSeverities(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.LOW)); Collection profiles = Collections.singleton(qualityProfileDto); @@ -94,19 +97,21 @@ public class QualityProfileChangeEventServiceImplTest { .contains("\"activatedRules\":[{\"key\":\"repo:ruleKey\"," + "\"language\":\"xoo\"," + "\"templateKey\":\"xoo:template-key\"," + - "\"params\":[{\"key\":\"paramChangeKey\",\"value\":\"paramChangeValue\"}]}]," + + "\"params\":[{\"key\":\"paramChangeKey\",\"value\":\"paramChangeValue\"}]," + + "\"impacts\":[{\"softwareQuality\":\"MAINTAINABILITY\",\"severity\":\"LOW\"}]}]," + "\"deactivatedRules\":[]"); } @Test - public void distributeRuleChangeEvent_when_project_has_only_default_quality_profiles() { + void distributeRuleChangeEvent_when_project_has_only_default_quality_profiles() { String language = "xoo"; ProjectData projectData = db.components().insertPrivateProject(); ComponentDto mainBranch = projectData.getMainBranchComponent(); RuleDto templateRule = insertTemplateRule(); QProfileDto defaultQualityProfile = insertDefaultQualityProfile(language); RuleDto rule = insertCustomRule(templateRule, language, "
line1\nline2
"); - ActiveRuleChange activeRuleChange = changeActiveRule(defaultQualityProfile, rule, "paramChangeKey", "paramChangeValue"); + ActiveRuleChange activeRuleChange = changeActiveRule(defaultQualityProfile, rule, "paramChangeKey", "paramChangeValue") + .setImpactSeverities(Map.of(SoftwareQuality.RELIABILITY, Severity.MEDIUM)); db.measures().insertMeasure(mainBranch, m -> m.addValue(NCLOC_LANGUAGE_DISTRIBUTION_KEY, language + "=100")); db.getSession().commit(); @@ -128,7 +133,8 @@ public class QualityProfileChangeEventServiceImplTest { .contains("\"activatedRules\":[{\"key\":\"repo:ruleKey\"," + "\"language\":\"xoo\"," + "\"templateKey\":\"xoo:template-key\"," + - "\"params\":[{\"key\":\"paramChangeKey\",\"value\":\"paramChangeValue\"}]}]," + + "\"params\":[{\"key\":\"paramChangeKey\",\"value\":\"paramChangeValue\"}]," + + "\"impacts\":[{\"softwareQuality\":\"RELIABILITY\",\"severity\":\"MEDIUM\"}]}]," + "\"deactivatedRules\":[]"); } @@ -174,7 +180,7 @@ public class QualityProfileChangeEventServiceImplTest { } @Test - public void publishRuleActivationToSonarLintClients() { + void publishRuleActivationToSonarLintClients() { ProjectDto projectDto = new ProjectDto().setUuid("project-uuid"); QProfileDto activatedQualityProfile = QualityProfileTesting.newQualityProfileDto(); activatedQualityProfile.setLanguage("xoo"); @@ -182,7 +188,7 @@ public class QualityProfileChangeEventServiceImplTest { RuleDto rule1 = db.rules().insert(r -> r.setLanguage("xoo").setRepositoryKey("repo").setRuleKey("ruleKey")); RuleParamDto rule1Param = db.rules().insertRuleParam(rule1); - ActiveRuleDto activeRule1 = db.qualityProfiles().activateRule(activatedQualityProfile, rule1); + ActiveRuleDto activeRule1 = db.qualityProfiles().activateRule(activatedQualityProfile, rule1, ar -> ar.setImpacts(Map.of(SoftwareQuality.SECURITY, Severity.BLOCKER))); ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param).setValue(secure().nextAlphanumeric(20)); db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRule1, activeRuleParam1); db.getSession().commit(); @@ -210,8 +216,9 @@ public class QualityProfileChangeEventServiceImplTest { assertThat(ruleSetChangedEvent) .contains("\"activatedRules\":[{\"key\":\"repo:ruleKey\"," + - "\"language\":\"xoo\",\"severity\":\"" + Common.Severity.forNumber(rule1.getSeverity()).name() + "\"," + - "\"params\":[{\"key\":\"" + activeRuleParam1.getKey() + "\",\"value\":\"" + activeRuleParam1.getValue() + "\"}]}]," + + "\"language\":\"xoo\",\"severity\":\"" + activeRule1.getSeverityString() + "\"," + + "\"params\":[{\"key\":\"" + activeRuleParam1.getKey() + "\",\"value\":\"" + activeRuleParam1.getValue() + "\"}]," + + "\"impacts\":[{\"softwareQuality\":\"SECURITY\",\"severity\":\"BLOCKER\"}]}]," + "\"deactivatedRules\":[\"repo2:ruleKey2\"]"); } } diff --git a/sonar-core/src/main/java/org/sonar/core/util/rule/RuleChange.java b/sonar-core/src/main/java/org/sonar/core/util/rule/RuleChange.java index a43b0716a69..c3b99a2834c 100644 --- a/sonar-core/src/main/java/org/sonar/core/util/rule/RuleChange.java +++ b/sonar-core/src/main/java/org/sonar/core/util/rule/RuleChange.java @@ -20,8 +20,12 @@ package org.sonar.core.util.rule; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.sonar.api.issue.impact.Severity; +import org.sonar.api.issue.impact.SoftwareQuality; import org.sonar.core.util.ParamChange; public class RuleChange implements Serializable { @@ -30,6 +34,7 @@ public class RuleChange implements Serializable { private String templateKey; private String severity; private ParamChange[] params = new ParamChange[0]; + private final List impacts = new ArrayList<>(); public String getKey() { return key; @@ -77,4 +82,30 @@ public class RuleChange implements Serializable { this.params = params; return this; } + + public List getImpacts() { + return impacts; + } + + public void addImpact(SoftwareQuality softwareQuality, Severity severity) { + impacts.add(new Impact(softwareQuality, severity)); + } + + static class Impact implements Serializable { + private final SoftwareQuality softwareQuality; + private final Severity severity; + + Impact(SoftwareQuality softwareQuality, Severity severity) { + this.softwareQuality = softwareQuality; + this.severity = severity; + } + + public SoftwareQuality getSoftwareQuality() { + return softwareQuality; + } + + public Severity getSeverity() { + return severity; + } + } } diff --git a/sonar-core/src/test/java/org/sonar/core/util/rule/RuleChangeTest.java b/sonar-core/src/test/java/org/sonar/core/util/rule/RuleChangeTest.java new file mode 100644 index 00000000000..a1f5c8119bc --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/util/rule/RuleChangeTest.java @@ -0,0 +1,63 @@ +/* + * 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.core.util.rule; + +import org.junit.jupiter.api.Test; +import org.sonar.api.issue.impact.Severity; +import org.sonar.api.issue.impact.SoftwareQuality; +import org.sonar.core.util.ParamChange; + +import static org.assertj.core.api.Assertions.assertThat; + +class RuleChangeTest { + + @Test + void valuesAreStoredAndReturnedCorrectly() { + RuleChange ruleChange = new RuleChange(); + + ruleChange.setKey("key"); + ruleChange.setTemplateKey("templateKey"); + ruleChange.setLanguage("language"); + ruleChange.setSeverity("severity"); + ruleChange.setParams(new ParamChange[]{new ParamChange("paramKey", "paramValue")}); + ruleChange.addImpact(SoftwareQuality.MAINTAINABILITY, Severity.HIGH); + + assertThat(ruleChange).extracting( + RuleChange::getKey, + RuleChange::getTemplateKey, + RuleChange::getLanguage, + RuleChange::getSeverity) + .containsExactly( + "key", + "templateKey", + "language", + "severity"); + + assertThat(ruleChange.getParams()).hasSize(1); + assertThat(ruleChange.getParams()[0]) + .extracting(ParamChange::getKey, ParamChange::getValue) + .containsExactly("paramKey", "paramValue"); + + assertThat(ruleChange.getImpacts()).hasSize(1); + assertThat(ruleChange.getImpacts().get(0)) + .extracting(RuleChange.Impact::getSoftwareQuality, RuleChange.Impact::getSeverity) + .containsExactly(SoftwareQuality.MAINTAINABILITY, Severity.HIGH); + } +}