aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine
diff options
context:
space:
mode:
authorLéo Geoffroy <leo.geoffroy@sonarsource.com>2024-10-10 18:14:38 +0200
committersonartech <sonartech@sonarsource.com>2024-10-16 20:03:01 +0000
commite2cb22069d25733459a1d058be1a7c1f3ca370ef (patch)
tree8174db0874a9c60e1ed26ae7cea13fb025d6d9e6 /sonar-scanner-engine
parent5038a353ca5917a647e5613859fbf62e756f4a21 (diff)
downloadsonarqube-e2cb22069d25733459a1d058be1a7c1f3ca370ef.tar.gz
sonarqube-e2cb22069d25733459a1d058be1a7c1f3ca370ef.zip
SONAR-23250 handle impacts on active rules in scanner engine
Diffstat (limited to 'sonar-scanner-engine')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java11
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java8
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java15
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java55
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java14
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java8
6 files changed, 107 insertions, 4 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java
index d09209bb2c7..53d04e5faa5 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java
@@ -21,6 +21,7 @@ package org.sonar.scanner.issue;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -77,7 +78,7 @@ public class IssuePublisher {
return false;
}
- ScannerReport.Issue rawIssue = createReportIssue(issue, inputComponent.scannerId(), activeRule.severity());
+ ScannerReport.Issue rawIssue = createReportIssue(issue, inputComponent.scannerId(), activeRule.severity(), activeRule.impacts());
if (filters.accept(inputComponent, rawIssue)) {
write(inputComponent.scannerId(), rawIssue);
@@ -107,7 +108,8 @@ public class IssuePublisher {
return str;
}
- private static ScannerReport.Issue createReportIssue(Issue issue, int componentRef, String activeRuleSeverity) {
+ private static ScannerReport.Issue createReportIssue(Issue issue, int componentRef, String activeRuleSeverity,
+ Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> activeRuleImpacts) {
String primaryMessage = nullToEmpty(issue.primaryLocation().message());
org.sonar.api.batch.rule.Severity overriddenSeverity = issue.overriddenSeverity();
Severity severity = overriddenSeverity != null ? Severity.valueOf(overriddenSeverity.name()) : Severity.valueOf(activeRuleSeverity);
@@ -121,7 +123,10 @@ public class IssuePublisher {
builder.setRuleKey(issue.ruleKey().rule());
builder.setMsg(primaryMessage);
builder.addAllMsgFormatting(toProtobufMessageFormattings(issue.primaryLocation().messageFormattings()));
- builder.addAllOverridenImpacts(toProtobufImpacts(issue.overridenImpacts()));
+ Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> overriddenImpacts = new EnumMap<>(issue.overridenImpacts());
+ activeRuleImpacts.entrySet().forEach(e -> overriddenImpacts.putIfAbsent(e.getKey(), e.getValue()));
+ builder.addAllOverridenImpacts(toProtobufImpacts(overriddenImpacts));
+
locationBuilder.setMsg(primaryMessage);
locationBuilder.addAllMsgFormatting(toProtobufMessageFormattings(issue.primaryLocation().messageFormattings()));
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
index 4028fbbcd9a..8e0691a069e 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
@@ -29,6 +29,8 @@ import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.batch.rule.internal.NewActiveRule;
+import org.sonar.api.issue.impact.Severity;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -91,6 +93,12 @@ public class ActiveRulesProvider {
}
}
+ if (activeRule.getImpacts() != null) {
+ for (Map.Entry<SoftwareQuality, Severity> impact : activeRule.getImpacts().entrySet()) {
+ builder.setImpact(impact.getKey(), impact.getValue());
+ }
+ }
+
return builder.build();
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java
index 1bc34c0198c..9c2bb5d86d1 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/DefaultActiveRulesLoader.java
@@ -21,6 +21,7 @@ package org.sonar.scanner.rule;
import java.io.IOException;
import java.io.InputStream;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -29,9 +30,13 @@ import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils;
import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.impl.utils.ScannerUtils;
+import org.sonar.api.issue.impact.Severity;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.DateUtils;
+import org.sonar.core.rule.ImpactFormatter;
import org.sonar.scanner.http.ScannerWsClient;
+import org.sonarqube.ws.Common;
import org.sonarqube.ws.Common.Paging;
import org.sonarqube.ws.Rules;
import org.sonarqube.ws.Rules.Active;
@@ -109,6 +114,7 @@ public class DefaultActiveRulesLoader implements ActiveRulesLoader {
loadedRule.setRuleKey(RuleKey.parse(r.getKey()));
loadedRule.setName(r.getName());
loadedRule.setSeverity(active.getSeverity());
+
loadedRule.setCreatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(active.getCreatedAt())));
loadedRule.setUpdatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(active.getUpdatedAt())));
loadedRule.setLanguage(r.getLang());
@@ -128,7 +134,15 @@ public class DefaultActiveRulesLoader implements ActiveRulesLoader {
for (Param param : active.getParamsList()) {
params.put(param.getKey(), param.getValue());
}
+
loadedRule.setParams(params);
+
+ Map<SoftwareQuality, Severity> impacts = new EnumMap<>(SoftwareQuality.class);
+ for (Common.Impact impact : active.getImpacts().getImpactsList()) {
+ impacts.put(SoftwareQuality.valueOf(impact.getSoftwareQuality().name()), ImpactFormatter.mapImpactSeverity(impact.getSeverity()));
+ }
+ loadedRule.setImpacts(impacts);
+
loadedRule.setDeprecatedKeys(r.getDeprecatedKeys().getDeprecatedKeyList()
.stream()
.map(RuleKey::parse)
@@ -138,4 +152,5 @@ public class DefaultActiveRulesLoader implements ActiveRulesLoader {
return loadedRules;
}
+
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java
index 5a58ff47540..0c4b12443ec 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java
@@ -62,6 +62,7 @@ import static org.mockito.Mockito.when;
import static org.sonar.api.batch.sensor.issue.MessageFormatting.Type.CODE;
import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY;
+import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
@RunWith(MockitoJUnitRunner.class)
public class IssuePublisherTest {
@@ -149,7 +150,7 @@ public class IssuePublisherTest {
ScannerReport.Impact impact1 = ScannerReport.Impact.newBuilder().setSoftwareQuality(MAINTAINABILITY.name()).setSeverity("HIGH").build();
ScannerReport.Impact impact2 = ScannerReport.Impact.newBuilder().setSoftwareQuality(RELIABILITY.name()).setSeverity("LOW").build();
- assertThat(argument.getValue().getOverridenImpactsList()).containsExactly(impact1, impact2);
+ assertThat(argument.getValue().getOverridenImpactsList()).containsExactlyInAnyOrder(impact1, impact2);
}
@Test
@@ -243,6 +244,58 @@ public class IssuePublisherTest {
ArgumentCaptor<ScannerReport.Issue> argument = ArgumentCaptor.forClass(ScannerReport.Issue.class);
verify(reportPublisher.getWriter()).appendComponentIssue(eq(file.scannerId()), argument.capture());
assertThat(argument.getValue().getSeverity()).isEqualTo(org.sonar.scanner.protocol.Constants.Severity.INFO);
+ assertThat(argument.getValue().getOverridenImpactsList()).isEmpty();
+ }
+
+ @Test
+ public void initAndAddIssue_whenImpactsOverriddenOnActiveRule_shouldOverrideIssue() {
+ activeRulesBuilder.addRule(new NewActiveRule.Builder()
+ .setRuleKey(NOSONAR_RULE_KEY)
+ .setSeverity(Severity.INFO)
+ .setImpact(MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH)
+ .setQProfileKey("qp-1")
+ .build());
+ initModuleIssues();
+
+ DefaultIssue issue = new DefaultIssue(project)
+ .at(new DefaultIssueLocation().on(file).at(file.selectLine(3)).message("Foo"))
+ .forRule(NOSONAR_RULE_KEY);
+ when(filters.accept(any(InputComponent.class), any(ScannerReport.Issue.class))).thenReturn(true);
+ moduleIssues.initAndAddIssue(issue);
+
+ ArgumentCaptor<ScannerReport.Issue> argument = ArgumentCaptor.forClass(ScannerReport.Issue.class);
+ verify(reportPublisher.getWriter()).appendComponentIssue(eq(file.scannerId()), argument.capture());
+ assertThat(argument.getValue().getSeverity()).isEqualTo(org.sonar.scanner.protocol.Constants.Severity.INFO);
+ assertThat(argument.getValue().getOverridenImpactsList()).extracting(ScannerReport.Impact::getSoftwareQuality, ScannerReport.Impact::getSeverity)
+ .containsExactly(tuple(MAINTAINABILITY.name(), org.sonar.api.issue.impact.Severity.HIGH.name()));
+ }
+
+ @Test
+ public void initAndAddIssue_whenImpactsOverriddenOnActiveRuleAndInIssue_shouldCombineOverriddenImpacts() {
+ activeRulesBuilder.addRule(new NewActiveRule.Builder()
+ .setRuleKey(NOSONAR_RULE_KEY)
+ .setSeverity(Severity.INFO)
+ .setImpact(MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH)
+ .setImpact(SECURITY, org.sonar.api.issue.impact.Severity.INFO)
+ .setQProfileKey("qp-1")
+ .build());
+ initModuleIssues();
+
+ DefaultIssue issue = new DefaultIssue(project)
+ .at(new DefaultIssueLocation().on(file).at(file.selectLine(3)).message("Foo"))
+ .overrideImpact(RELIABILITY, org.sonar.api.issue.impact.Severity.MEDIUM)
+ .overrideImpact(MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW)
+ .forRule(NOSONAR_RULE_KEY);
+ when(filters.accept(any(InputComponent.class), any(ScannerReport.Issue.class))).thenReturn(true);
+ moduleIssues.initAndAddIssue(issue);
+
+ ArgumentCaptor<ScannerReport.Issue> argument = ArgumentCaptor.forClass(ScannerReport.Issue.class);
+ verify(reportPublisher.getWriter()).appendComponentIssue(eq(file.scannerId()), argument.capture());
+ assertThat(argument.getValue().getSeverity()).isEqualTo(org.sonar.scanner.protocol.Constants.Severity.INFO);
+ assertThat(argument.getValue().getOverridenImpactsList()).extracting(ScannerReport.Impact::getSoftwareQuality, ScannerReport.Impact::getSeverity)
+ .containsExactlyInAnyOrder(tuple(MAINTAINABILITY.name(), org.sonar.api.issue.impact.Severity.LOW.name()),
+ tuple(RELIABILITY.name(), org.sonar.api.issue.impact.Severity.MEDIUM.name()),
+ tuple(SECURITY.name(), org.sonar.api.issue.impact.Severity.INFO.name()));
}
@Test
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java
index 32611fb0cf2..14a5036e254 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java
@@ -25,11 +25,16 @@ import com.google.common.collect.ImmutableSet;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
import org.assertj.core.groups.Tuple;
import org.junit.Test;
+import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.batch.rule.internal.DefaultActiveRules;
+import org.sonar.api.issue.impact.Severity;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.DateUtils;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
@@ -50,6 +55,8 @@ public class ActiveRulesProviderTest {
LoadedActiveRule r2 = mockRule("rule2");
LoadedActiveRule r3 = mockRule("rule3");
+ r1.setImpacts(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
+
List<LoadedActiveRule> qp1Rules = ImmutableList.of(r1, r2);
List<LoadedActiveRule> qp2Rules = ImmutableList.of(r2, r3);
List<LoadedActiveRule> qp3Rules = ImmutableList.of(r1, r3);
@@ -65,6 +72,13 @@ public class ActiveRulesProviderTest {
assertThat(activeRules.findAll()).extracting("ruleKey").containsOnly(
RuleKey.of("rule1", "rule1"), RuleKey.of("rule2", "rule2"), RuleKey.of("rule3", "rule3"));
+ Map<String, ActiveRule> activeRuleByKey = activeRules.findAll().stream().collect(Collectors.toMap(e -> e.ruleKey().rule(), e -> e));
+ assertThat(activeRuleByKey.get("rule1").impacts())
+ .containsExactlyInAnyOrderEntriesOf(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
+
+ assertThat(activeRuleByKey.get("rule2").impacts()).isEmpty();
+ assertThat(activeRuleByKey.get("rule3").impacts()).isEmpty();
+
verify(loader).load("qp1");
verify(loader).load("qp2");
verify(loader).load("qp3");
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java
index bae17ee866d..ad70dd74d47 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java
@@ -27,6 +27,7 @@ import java.util.stream.IntStream;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.scanner.WsTestUtil;
@@ -82,6 +83,10 @@ public class DefaultActiveRulesLoaderTest {
.filteredOn(r -> r.getRuleKey().equals(EXAMPLE_KEY))
.extracting(LoadedActiveRule::getSeverity)
.containsExactly(SEVERITY_VALUE);
+ assertThat(activeRules)
+ .filteredOn(r -> r.getRuleKey().equals(EXAMPLE_KEY))
+ .extracting(LoadedActiveRule::getImpacts)
+ .containsExactlyInAnyOrder(Map.of(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH));
WsTestUtil.verifyCall(wsClient, urlOfPage(1));
WsTestUtil.verifyCall(wsClient, urlOfPage(2));
@@ -119,6 +124,9 @@ public class DefaultActiveRulesLoaderTest {
if (EXAMPLE_KEY.equals(key)) {
activeBuilder.addParams(Rules.Active.Param.newBuilder().setKey(FORMAT_KEY).setValue(FORMAT_VALUE));
activeBuilder.setSeverity(SEVERITY_VALUE);
+ activeBuilder.setImpacts(Rules.Impacts.newBuilder().addImpacts(Common.Impact.newBuilder()
+ .setSoftwareQuality(Common.SoftwareQuality.MAINTAINABILITY)
+ .setSeverity(Common.ImpactSeverity.HIGH).build()).build());
}
ActiveList activeList = Rules.ActiveList.newBuilder().addActiveList(activeBuilder).build();
actives.putAllActives(Map.of(key.toString(), activeList));