import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.metric.SoftwareQualitiesMetrics;
import org.sonar.server.measure.ImpactMeasureBuilder;
import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
* <li>issues per status (open, reopen, confirmed)</li>
* <li>issues per resolution (unresolved, false-positives, won't fix)</li>
* <li>issues per severity (from info to blocker)</li>
+ * <li>issues per impact severity (from info to blocker)</li>
* <li>issues per type (code smell, bug, vulnerability, security hotspots)</li>
* <li>issues per impact</li>
* </ul>
MINOR, NEW_MINOR_VIOLATIONS_KEY,
INFO, NEW_INFO_VIOLATIONS_KEY);
- static final Map<String, String> IMPACT_TO_METRIC_KEY = Map.of(
+ private static final Map<Severity, String> IMPACT_SEVERITY_TO_METRIC_KEY = ImmutableMap.of(
+ Severity.BLOCKER, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY,
+ Severity.HIGH, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES_KEY,
+ Severity.MEDIUM, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY,
+ Severity.LOW, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES_KEY,
+ Severity.INFO, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES_KEY);
+
+ private static final Map<Severity, String> IMPACT_SEVERITY_TO_NEW_METRIC_KEY = ImmutableMap.of(
+ Severity.BLOCKER, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY,
+ Severity.HIGH, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES_KEY,
+ Severity.MEDIUM, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY,
+ Severity.LOW, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES_KEY,
+ Severity.INFO, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES_KEY);
+
+ static final Map<String, String> IMPACT_TO_JSON_METRIC_KEY = Map.of(
SoftwareQuality.SECURITY.name(), SECURITY_ISSUES_KEY,
SoftwareQuality.RELIABILITY.name(), RELIABILITY_ISSUES_KEY,
SoftwareQuality.MAINTAINABILITY.name(), MAINTAINABILITY_ISSUES_KEY);
- static final Map<String, String> IMPACT_TO_NEW_METRIC_KEY = Map.of(
+ static final Map<String, String> IMPACT_TO_NEW_JSON_METRIC_KEY = Map.of(
SoftwareQuality.SECURITY.name(), NEW_SECURITY_ISSUES_KEY,
SoftwareQuality.RELIABILITY.name(), NEW_RELIABILITY_ISSUES_KEY,
SoftwareQuality.MAINTAINABILITY.name(), NEW_MAINTAINABILITY_ISSUES_KEY);
+ static final Map<String, String> IMPACT_TO_METRIC_KEY = Map.of(
+ SoftwareQuality.SECURITY.name(), SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES_KEY,
+ SoftwareQuality.RELIABILITY.name(), SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY,
+ SoftwareQuality.MAINTAINABILITY.name(), SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY);
+
+ static final Map<String, String> IMPACT_TO_NEW_METRIC_KEY = Map.of(
+ SoftwareQuality.SECURITY.name(), SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES_KEY,
+ SoftwareQuality.RELIABILITY.name(), SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY,
+ SoftwareQuality.MAINTAINABILITY.name(), SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY);
+
private static final Map<RuleType, String> TYPE_TO_METRIC_KEY = ImmutableMap.<RuleType, String>builder()
.put(CODE_SMELL, CODE_SMELLS_KEY)
.put(BUG, BUGS_KEY)
@Override
public void afterComponent(Component component) {
addMeasuresBySeverity(component);
+ addMeasuresByImpactSeverity(component);
addMeasuresByStatus(component);
addMeasuresByType(component);
addMeasuresByImpact(component);
}
private void addMeasuresBySeverity(Component component) {
- for (Map.Entry<String, String> entry : SEVERITY_TO_METRIC_KEY.entrySet()) {
- String severity = entry.getKey();
- String metricKey = entry.getValue();
- addMeasure(component, metricKey, currentCounters.counter().severityBag.count(severity));
- }
+ addMeasures(component, SEVERITY_TO_METRIC_KEY, currentCounters.counter().severityBag);
+ }
+
+ private void addMeasuresByImpactSeverity(Component component) {
+ addMeasures(component, IMPACT_SEVERITY_TO_METRIC_KEY, currentCounters.counter().impactSeverityBag);
}
private void addMeasuresByStatus(Component component) {
private void addMeasuresByImpact(Component component) {
for (Map.Entry<String, Map<String, Long>> impactEntry : currentCounters.counter().impactsBag.entrySet()) {
String json = ImpactMeasureBuilder.fromMap(impactEntry.getValue()).buildAsString();
- addMeasure(component, IMPACT_TO_METRIC_KEY.get(impactEntry.getKey()), json);
+ addMeasure(component, IMPACT_TO_JSON_METRIC_KEY.get(impactEntry.getKey()), json);
+ addMeasure(component, IMPACT_TO_METRIC_KEY.get(impactEntry.getKey()),
+ impactEntry.getValue().get(ImpactMeasureBuilder.TOTAL_KEY).intValue());
}
}
measureRepository.add(component, metric, Measure.newMeasureBuilder().create(data));
}
+ private <M> void addMeasures(Component component, Map<M, String> metrics, Multiset<M> countPerMetric) {
+ for (Map.Entry<M, String> entry : metrics.entrySet()) {
+ M entryKey = entry.getKey();
+ String metricKey = entry.getValue();
+ addMeasure(component, metricKey, countPerMetric.count(entryKey));
+ }
+ }
+
+
private void addNewMeasures(Component component) {
if (!newIssueClassifier.isEnabled()) {
return;
measureRepository.add(component, metricRepository.getByKey(NEW_VIOLATIONS_KEY), Measure.newMeasureBuilder()
.create(unresolved));
- for (Map.Entry<String, String> entry : SEVERITY_TO_NEW_METRIC_KEY.entrySet()) {
- String severity = entry.getKey();
- String metricKey = entry.getValue();
- Multiset<String> bag = currentCounters.counterForPeriod().severityBag;
- addMeasure(component, metricKey, bag.count(severity));
- }
+ addMeasures(component, SEVERITY_TO_NEW_METRIC_KEY, currentCounters.counterForPeriod().severityBag);
- // waiting for Java 8 lambda in order to factor this loop with the previous one
- // (see call currentCounters.counterForPeriod(period.getIndex()).xxx with xxx as severityBag or typeBag)
- for (Map.Entry<RuleType, String> entry : TYPE_TO_NEW_METRIC_KEY.entrySet()) {
- RuleType type = entry.getKey();
- String metricKey = entry.getValue();
- Multiset<RuleType> bag = currentCounters.counterForPeriod().typeBag;
- addMeasure(component, metricKey, bag.count(type));
- }
+ addMeasures(component, IMPACT_SEVERITY_TO_NEW_METRIC_KEY, currentCounters.counterForPeriod().impactSeverityBag);
+
+ addMeasures(component, TYPE_TO_NEW_METRIC_KEY, currentCounters.counterForPeriod().typeBag);
for (Map.Entry<String, Map<String, Long>> impactEntry : currentCounters.counterForPeriod().impactsBag.entrySet()) {
String json = ImpactMeasureBuilder.fromMap(impactEntry.getValue()).buildAsString();
- addMeasure(component, IMPACT_TO_NEW_METRIC_KEY.get(impactEntry.getKey()), json);
+ addMeasure(component, IMPACT_TO_NEW_JSON_METRIC_KEY.get(impactEntry.getKey()), json);
+ addMeasure(component, IMPACT_TO_NEW_METRIC_KEY.get(impactEntry.getKey()),
+ impactEntry.getValue().get(ImpactMeasureBuilder.TOTAL_KEY).intValue());
}
addMeasure(component, NEW_ACCEPTED_ISSUES_KEY, currentCounters.counterForPeriod().accepted);
private int accepted = 0;
private int highImpactAccepted = 0;
private final Multiset<String> severityBag = HashMultiset.create();
+ private final Multiset<Severity> impactSeverityBag = HashMultiset.create();
/**
* This map contains the number of issues per software quality along with their distribution based on (new) severity.
*/
accepted += counter.accepted;
highImpactAccepted += counter.highImpactAccepted;
severityBag.addAll(counter.severityBag);
+ impactSeverityBag.addAll(counter.impactSeverityBag);
typeBag.addAll(counter.typeBag);
// Add impacts
default:
// Other statuses are ignored
}
- addIssueToImpactsBag(issue);
+ countIssueImpacts(issue);
}
- private void addIssueToImpactsBag(DefaultIssue issue) {
+ private void countIssueImpacts(DefaultIssue issue) {
if (IssueStatus.OPEN == issue.issueStatus() || IssueStatus.CONFIRMED == issue.issueStatus()) {
for (Map.Entry<SoftwareQuality, Severity> impact : issue.impacts().entrySet()) {
impactsBag.compute(impact.getKey().name(), (key, value) -> {
return value;
});
}
+ issue.impacts().values().stream().distinct().forEach(impactSeverityBag::add);
}
}
}
import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
import static org.sonar.api.issue.Issue.STATUS_OPEN;
import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
+import static org.sonar.api.issue.impact.Severity.BLOCKER;
import static org.sonar.api.issue.impact.Severity.HIGH;
import static org.sonar.api.issue.impact.Severity.INFO;
import static org.sonar.api.issue.impact.Severity.LOW;
import static org.sonar.api.issue.impact.Severity.MEDIUM;
+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;
import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES;
import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES_KEY;
import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS;
import static org.sonar.api.rules.RuleType.CODE_SMELL;
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
-import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_METRIC_KEY;
-import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_NEW_METRIC_KEY;
+import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_JSON_METRIC_KEY;
+import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_NEW_JSON_METRIC_KEY;
import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES;
+import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES_KEY;
import static org.sonar.test.JsonAssert.assertJson;
class IssueCounterTest {
.add(SECURITY_ISSUES)
.add(NEW_RELIABILITY_ISSUES)
.add(NEW_MAINTAINABILITY_ISSUES)
- .add(NEW_SECURITY_ISSUES);
+ .add(NEW_SECURITY_ISSUES)
+ .add(SOFTWARE_QUALITY_BLOCKER_ISSUES)
+ .add(SOFTWARE_QUALITY_HIGH_ISSUES)
+ .add(SOFTWARE_QUALITY_MEDIUM_ISSUES)
+ .add(SOFTWARE_QUALITY_LOW_ISSUES)
+ .add(SOFTWARE_QUALITY_INFO_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_HIGH_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_LOW_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_INFO_ISSUES)
+ .add(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES)
+ .add(SOFTWARE_QUALITY_RELIABILITY_ISSUES)
+ .add(SOFTWARE_QUALITY_SECURITY_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES)
+ .add(NEW_SOFTWARE_QUALITY_SECURITY_ISSUES);
@RegisterExtension
private final MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
when(newIssueClassifier.isEnabled()).thenReturn(true);
underTest.beforeComponent(FILE1);
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, MEDIUM));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.MAINTAINABILITY, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, MEDIUM));
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH));
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM));
Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet();
- assertOverallSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0, 0, 0), entries);
+ assertOverallSoftwareQualityMeasures(MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0, 0, 0), entries);
assertOverallSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0, 0, 0), entries);
- assertOverallSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0, 0, 0), entries);
+ assertOverallSoftwareQualityMeasures(RELIABILITY, getImpactMeasure(0, 0, 0, 0, 0, 0), entries);
+ }
+
+ @Test
+ void onIssue_shouldCountByImpactSeverity() {
+ when(newIssueClassifier.isEnabled()).thenReturn(true);
+
+ underTest.beforeComponent(FILE1);
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(MAINTAINABILITY, BLOCKER, SECURITY, BLOCKER)));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(MAINTAINABILITY, HIGH, SECURITY, BLOCKER)));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, RELIABILITY, HIGH));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(SECURITY, MEDIUM, MAINTAINABILITY, LOW)));
+ // Should not count because it is resolved
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, Map.of(SECURITY, BLOCKER, MAINTAINABILITY, INFO)));
+
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(SECURITY, MEDIUM, MAINTAINABILITY, LOW)));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(MAINTAINABILITY, INFO, SECURITY, INFO)));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(MAINTAINABILITY, INFO, SECURITY, INFO)));
+
+ underTest.afterComponent(FILE1);
+
+ underTest.beforeComponent(PROJECT);
+ underTest.onIssue(PROJECT, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(SECURITY, MEDIUM, MAINTAINABILITY, LOW)));
+ underTest.afterComponent(PROJECT);
+
+ assertIntValue(FILE1,
+ entry(SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY, 2),
+ entry(SOFTWARE_QUALITY_HIGH_ISSUES_KEY, 3),
+ entry(SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY, 2),
+ entry(SOFTWARE_QUALITY_LOW_ISSUES_KEY, 2),
+ entry(SOFTWARE_QUALITY_INFO_ISSUES_KEY, 2)
+ );
+
+ assertIntValue(FILE1,
+ entry(NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY, 0),
+ entry(NEW_SOFTWARE_QUALITY_HIGH_ISSUES_KEY, 1),
+ entry(NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY, 1),
+ entry(NEW_SOFTWARE_QUALITY_LOW_ISSUES_KEY, 1),
+ entry(NEW_SOFTWARE_QUALITY_INFO_ISSUES_KEY, 2)
+ );
+
+ assertIntValue(PROJECT,
+ entry(SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY, 2),
+ entry(SOFTWARE_QUALITY_HIGH_ISSUES_KEY, 3),
+ entry(SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY, 3),
+ entry(SOFTWARE_QUALITY_LOW_ISSUES_KEY, 3),
+ entry(SOFTWARE_QUALITY_INFO_ISSUES_KEY, 2)
+ );
+
+ assertIntValue(PROJECT,
+ entry(NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES_KEY, 0),
+ entry(NEW_SOFTWARE_QUALITY_HIGH_ISSUES_KEY, 1),
+ entry(NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES_KEY, 2),
+ entry(NEW_SOFTWARE_QUALITY_LOW_ISSUES_KEY, 2),
+ entry(NEW_SOFTWARE_QUALITY_INFO_ISSUES_KEY, 2)
+ );
+ }
+
+ @Test
+ void onIssue_shouldCountBySoftwareQuality() {
+ when(newIssueClassifier.isEnabled()).thenReturn(true);
+
+ underTest.beforeComponent(FILE1);
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(MAINTAINABILITY, HIGH, SECURITY, BLOCKER)));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, RELIABILITY, HIGH));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(SECURITY, MEDIUM, MAINTAINABILITY, LOW)));
+ // Should not count because it is resolved
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, Map.of(SECURITY, BLOCKER, MAINTAINABILITY, INFO)));
+
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(SECURITY, MEDIUM, MAINTAINABILITY, LOW)));
+
+ underTest.afterComponent(FILE1);
+
+ underTest.beforeComponent(PROJECT);
+ underTest.onIssue(PROJECT, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, Map.of(SECURITY, MEDIUM, MAINTAINABILITY, LOW)));
+ underTest.afterComponent(PROJECT);
+
+ assertIntValue(FILE1,
+ entry(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY, 4),
+ entry(SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY, 1),
+ entry(SOFTWARE_QUALITY_SECURITY_ISSUES_KEY, 3)
+ );
+
+ assertIntValue(FILE1,
+ entry(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY, 2),
+ entry(NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY, 0),
+ entry(NEW_SOFTWARE_QUALITY_SECURITY_ISSUES_KEY, 1)
+ );
+
+ assertIntValue(PROJECT,
+ entry(SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY, 5),
+ entry(SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY, 1),
+ entry(SOFTWARE_QUALITY_SECURITY_ISSUES_KEY, 4)
+ );
+
+ assertIntValue(PROJECT,
+ entry(NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES_KEY, 3),
+ entry(NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY, 0),
+ entry(NEW_SOFTWARE_QUALITY_SECURITY_ISSUES_KEY, 2)
+ );
}
@Test
when(newIssueClassifier.isEnabled()).thenReturn(true);
underTest.beforeComponent(FILE1);
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.MAINTAINABILITY, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MAINTAINABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, MAINTAINABILITY, MEDIUM));
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, LOW));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.RELIABILITY, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, MEDIUM));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, RELIABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, RELIABILITY, LOW));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, RELIABILITY, HIGH));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, RELIABILITY, MEDIUM));
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, LOW));
Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet();
- assertNewSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(2, 1, 1, 0, 0, 0), entries);
- assertNewSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(2, 0, 1, 1, 0, 0), entries);
+ assertNewSoftwareQualityMeasures(MAINTAINABILITY, getImpactMeasure(2, 1, 1, 0, 0, 0), entries);
+ assertNewSoftwareQualityMeasures(RELIABILITY, getImpactMeasure(2, 0, 1, 1, 0, 0), entries);
assertNewSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(4, 2, 1, 1, 0, 0), entries);
}
private static Map<String, Long> getImpactMeasure(long total, long high, long medium, long low, long info, long blocker) {
Map<String, Long> map = getImpactMeasure(total, high, medium, low);
map.put(INFO.name(), info);
- map.put(Severity.BLOCKER.name(), blocker);
+ map.put(BLOCKER.name(), blocker);
return map;
}
private void assertOverallSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap,
Set<Map.Entry<String, Measure>> actualRaw) {
- assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_METRIC_KEY);
+ assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_JSON_METRIC_KEY);
}
private void assertNewSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap,
Set<Map.Entry<String, Measure>> actualRaw) {
- assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_NEW_METRIC_KEY);
+ assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_NEW_JSON_METRIC_KEY);
}
private void assertSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap,
// created before -> existing issues with 2 high impact accepted (High and Blocker)
underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, HIGH));
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, HIGH));
- underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, Severity.BLOCKER));
+ underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, Map.of(MAINTAINABILITY, BLOCKER, RELIABILITY, HIGH)));
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MEDIUM));
// created after -> 2 high impact accepted
underTest.onIssue(FILE1, createNewIssue(null, STATUS_OPEN, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, HIGH));
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, HIGH));
- underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MEDIUM));
+ underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, Map.of(MAINTAINABILITY, MEDIUM, RELIABILITY, HIGH)));
underTest.onIssue(FILE1, createNewSecurityHotspot());
underTest.afterComponent(FILE1);
underTest.afterComponent(PROJECT);
assertIntValue(FILE1, entry(VIOLATIONS_KEY, 2), entry(NEW_VIOLATIONS_KEY, 1), entry(NEW_ACCEPTED_ISSUES_KEY, 3),
- entry(HIGH_IMPACT_ACCEPTED_ISSUES_KEY, 4));
+ entry(HIGH_IMPACT_ACCEPTED_ISSUES_KEY, 5));
assertIntValue(PROJECT, entry(VIOLATIONS_KEY, 2), entry(NEW_VIOLATIONS_KEY, 1), entry(NEW_ACCEPTED_ISSUES_KEY, 3),
- entry(HIGH_IMPACT_ACCEPTED_ISSUES_KEY, 4));
+ entry(HIGH_IMPACT_ACCEPTED_ISSUES_KEY, 5));
}
@Test
}
private DefaultIssue createNewIssue(@Nullable String resolution, String status, Severity impactSeverity) {
- return createNewIssue(resolution, status, SoftwareQuality.MAINTAINABILITY, impactSeverity);
+ return createNewIssue(resolution, status, MAINTAINABILITY, impactSeverity);
}
private DefaultIssue createNewIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality,
return issue;
}
+ private DefaultIssue createNewIssue(@Nullable String resolution, String status, Map<SoftwareQuality, Severity> impaxts) {
+ DefaultIssue issue = createNewIssue(resolution, status, MAJOR, CODE_SMELL);
+ issue.replaceImpacts(impaxts);
+ return issue;
+ }
+
private DefaultIssue createNewIssue(@Nullable String resolution, String status, String severity, RuleType ruleType) {
DefaultIssue issue = createIssue(resolution, status, severity, ruleType);
when(newIssueClassifier.isNew(any(), eq(issue))).thenReturn(true);
}
private static DefaultIssue createIssue(@Nullable String resolution, String status, Severity impactSeverity) {
- return createIssue(resolution, status, SoftwareQuality.MAINTAINABILITY, impactSeverity);
+ return createIssue(resolution, status, MAINTAINABILITY, impactSeverity);
}
private static DefaultIssue createIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality,
return issue;
}
+ private static DefaultIssue createIssue(@Nullable String resolution, String status, Map<SoftwareQuality, Severity> impacts) {
+ DefaultIssue issue = createIssue(resolution, status, MAJOR, CODE_SMELL);
+ issue.replaceImpacts(impacts);
+ return issue;
+ }
+
private static DefaultIssue createIssue(@Nullable String resolution, String status, String severity, RuleType ruleType) {
return new DefaultIssue()
.setKey(String.valueOf(++issueCounter))
import static org.sonar.api.issue.Issue.STATUS_REOPENED;
import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
import static org.sonar.api.issue.Issue.STATUS_REVIEWED;
+import static org.sonar.api.issue.impact.Severity.BLOCKER;
import static org.sonar.api.issue.impact.Severity.HIGH;
+import static org.sonar.api.issue.impact.Severity.INFO;
import static org.sonar.api.issue.impact.Severity.LOW;
import static org.sonar.api.issue.impact.Severity.MEDIUM;
import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
}
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void selectIssueImpactSeverityGroupsByComponent_shouldReturnImpactSeverityGroups(boolean inLeak) {
+
+ ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
+ ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
+ RuleDto rule = db.rules().insert();
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_OPEN).setEffort(60L).replaceAllImpacts(List.of(createImpact(RELIABILITY, BLOCKER), createImpact(SECURITY,
+ BLOCKER))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_OPEN).setEffort(60L).replaceAllImpacts(List.of(createImpact(RELIABILITY, BLOCKER))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_REOPENED).setEffort(60L).replaceAllImpacts(List.of(createImpact(RELIABILITY, INFO))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_REOPENED).setEffort(60L).replaceAllImpacts(List.of(createImpact(RELIABILITY, INFO), createImpact(SECURITY,
+ BLOCKER))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_RESOLVED).setEffort(60L).setResolution(RESOLUTION_WONT_FIX).replaceAllImpacts(List.of(createImpact(MAINTAINABILITY, HIGH), createImpact(RELIABILITY, INFO), createImpact(SECURITY, BLOCKER))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_RESOLVED).setEffort(60L).setResolution(RESOLUTION_WONT_FIX).replaceAllImpacts(List.of(createImpact(SECURITY
+ , HIGH))));
+ // issues in ignored status
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(Issue.STATUS_CLOSED).setEffort(60L).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_RESOLVED).setEffort(60L).setResolution(RESOLUTION_FALSE_POSITIVE).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
+
+ Collection<IssueImpactSeverityGroupDto> result = underTest.selectIssueImpactSeverityGroupsByComponent(db.getSession(), file, inLeak ?
+ 1L : Long.MAX_VALUE);
+
+ assertThat(result).hasSize(6);
+ assertThat(result.stream().filter(IssueImpactSeverityGroupDto::isInLeak)).hasSize(inLeak ? 6 : 0);
+ // 6 issues, but 1 has 2 different severity impact, and 1 has 3 different severity impact
+ // The total count should then be 6 + 1 (1 additional severity for 1 issue) + 2 (2 additional severities from 1 issue)
+ assertThat(result.stream().mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isEqualTo(6 + 1 + 2);
+
+ assertThat(result.stream().filter(g -> g.getSeverity() == BLOCKER).mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isEqualTo(4);
+ assertThat(result.stream().filter(g -> g.getSeverity() == HIGH).mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isEqualTo(2);
+ assertThat(result.stream().filter(g -> g.getSeverity() == MEDIUM).mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isZero();
+ assertThat(result.stream().filter(g -> g.getSeverity() == LOW).mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isZero();
+ assertThat(result.stream().filter(g -> g.getSeverity() == INFO).mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isEqualTo(3);
+
+ assertThat(result.stream().filter(g -> RESOLUTION_WONT_FIX.equals(g.getResolution())).mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isEqualTo(4);
+ assertThat(result.stream().filter(g -> g.getResolution() == null).mapToLong(IssueImpactSeverityGroupDto::getCount).sum()).isEqualTo(5);
+
+ assertThat(result.stream().noneMatch(g -> STATUS_CLOSED.equals(g.getResolution()))).isTrue();
+ assertThat(result.stream().noneMatch(g -> RESOLUTION_FALSE_POSITIVE.equals(g.getResolution()))).isTrue();
+ assertThat(result.stream().noneMatch(g -> MEDIUM == g.getSeverity())).isTrue();
+
+ }
+
@Test
void selectIssueImpactGroupsByComponent_whenNewCodeFromReferenceBranch_shouldReturnImpactGroups() {
return mapper(dbSession).selectIssueImpactGroupsByComponent(component, leakPeriodBeginningDate);
}
+ public Collection<IssueImpactSeverityGroupDto> selectIssueImpactSeverityGroupsByComponent(DbSession dbSession, ComponentDto component,
+ long leakPeriodBeginningDate) {
+ return mapper(dbSession).selectIssueImpactSeverityGroupsByComponent(component, leakPeriodBeginningDate);
+ }
+
public Cursor<IndexedIssueDto> scrollIssuesForIndexation(DbSession dbSession, @Nullable @Param("branchUuid") String branchUuid,
@Nullable @Param("issueKeys") Collection<String> issueKeys) {
return mapper(dbSession).scrollIssuesForIndexation(branchUuid, issueKeys);
--- /dev/null
+/*
+ * 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.db.issue;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.issue.impact.Severity;
+
+public class IssueImpactSeverityGroupDto {
+
+ private String resolution;
+ private Severity severity;
+ private long count;
+ private boolean inLeak;
+
+ public IssueImpactSeverityGroupDto() {
+ // nothing to do
+ }
+
+ public boolean isInLeak() {
+ return inLeak;
+ }
+
+ public void setInLeak(boolean inLeak) {
+ this.inLeak = inLeak;
+ }
+
+ @CheckForNull
+ public String getResolution() {
+ return resolution;
+ }
+
+ public void setResolution(@Nullable String resolution) {
+ this.resolution = resolution;
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public void setCount(long count) {
+ this.count = count;
+ }
+
+ public Severity getSeverity() {
+ return severity;
+ }
+
+ public void setSeverity(Severity severity) {
+ this.severity = severity;
+ }
+
+}
Collection<IssueImpactGroupDto> selectIssueImpactGroupsByComponent(@Param("component") ComponentDto component, @Param("leakPeriodBeginningDate") long leakPeriodBeginningDate);
+ Collection<IssueImpactSeverityGroupDto> selectIssueImpactSeverityGroupsByComponent(@Param("component") ComponentDto component,
+ @Param("leakPeriodBeginningDate") long leakPeriodBeginningDate);
+
List<IssueDto> selectByBranch(@Param("keys") Set<String> keys, @Nullable @Param("changedSince") Long changedSince);
List<String> selectRecentlyClosedIssues(@Param("queryParams") IssueQueryParams issueQueryParams);
group by i2.status, i2.resolution, i2.software_quality, i2.severity, i2.inLeak
</select>
+ <select id="selectIssueImpactSeverityGroupsByComponent" resultType="org.sonar.db.issue.IssueImpactSeverityGroupDto" parameterType="map">
+ select
+ i2.status as status,
+ i2.resolution as resolution,
+ i2.severity as severity,
+ count(i2.kee) as "count",
+ i2.inLeak as inLeak
+ from (
+ <!-- We need to use distinct keyword to not count twice issues with same impact severity on multiple software qualities -->
+ <!-- Sample RELIABILITY=BLOCKER and SECURITY=BLOCKER will be counted as 2 without the distinct keyword -->
+ select distinct
+ i.status,
+ i.resolution,
+ i.kee,
+ ii.severity,
+ <if test="leakPeriodBeginningDate >= 0">
+ case when i.issue_creation_date > #{leakPeriodBeginningDate,jdbcType=BIGINT} then ${_true} else ${_false} end as inLeak
+ </if>
+ <if test="leakPeriodBeginningDate < 0">
+ case when n.uuid is null then ${_false} else ${_true} end as inLeak
+ </if>
+ from issues i
+ inner join issues_impacts ii on i.kee = ii.issue_key
+ <if test="leakPeriodBeginningDate < 0">
+ left join new_code_reference_issues n on n.issue_key = i.kee
+ </if>
+ where i.status <> 'CLOSED'
+ and (i.resolution is null or i.resolution = 'WONTFIX')
+ and i.component_uuid = #{component.uuid,jdbcType=VARCHAR}
+ ) i2
+ group by i2.status, i2.resolution, i2.severity, i2.inLeak
+ </select>
+
<select id="selectIssueKeysByComponentUuid" parameterType="string" resultType="string">
select
i.kee
import org.sonar.api.rules.RuleType;
import org.sonar.db.issue.IssueGroupDto;
import org.sonar.db.issue.IssueImpactGroupDto;
+import org.sonar.db.issue.IssueImpactSeverityGroupDto;
import org.sonar.db.rule.SeverityUtil;
import org.sonar.server.measure.ImpactMeasureBuilder;
private final Map<RuleType, HighestSeverity> highestSeverityOfUnresolved = new EnumMap<>(RuleType.class);
private final Map<RuleType, Effort> effortOfUnresolved = new EnumMap<>(RuleType.class);
private final Map<String, Count> unresolvedBySeverity = new HashMap<>();
+ private final Map<Severity, Count> unresolvedByImpactSeverity = new EnumMap<>(Severity.class);
private final Map<RuleType, Count> unresolvedByType = new EnumMap<>(RuleType.class);
private final Map<String, Count> byResolution = new HashMap<>();
private final Map<String, Count> byStatus = new HashMap<>();
private final Map<SoftwareQuality, Effort> effortOfUnresolvedBySoftwareQuality = new EnumMap<>(SoftwareQuality.class);
private final Map<SoftwareQuality, HighestImpactSeverity> highestSeverityOfUnresolvedBySoftwareQuality = new EnumMap<>(SoftwareQuality.class);
- IssueCounter(Collection<IssueGroupDto> groups, Collection<IssueImpactGroupDto> impactGroups) {
+ IssueCounter(Collection<IssueGroupDto> groups, Collection<IssueImpactGroupDto> impactGroups,
+ Collection<IssueImpactSeverityGroupDto> impactSeverityGroups) {
for (IssueGroupDto group : groups) {
if (RuleType.valueOf(group.getRuleType()).equals(SECURITY_HOTSPOT)) {
processHotspotGroup(group);
for (IssueImpactGroupDto group : impactGroups) {
processImpactGroup(group);
}
+
+ for (IssueImpactSeverityGroupDto group : impactSeverityGroups) {
+ processImpactSeverityGroup(group);
+ }
}
private void processHotspotGroup(IssueGroupDto group) {
}
}
- public Optional<String> getHighestSeverityOfUnresolved(RuleType ruleType, boolean onlyInLeak) {
+ private void processImpactSeverityGroup(IssueImpactSeverityGroupDto group) {
+ if (group.getResolution() == null) {
+ unresolvedByImpactSeverity.computeIfAbsent(group.getSeverity(), k -> new Count()).add(group);
+ }
+ }
+ public Optional<String> getHighestSeverityOfUnresolved(RuleType ruleType, boolean onlyInLeak) {
return Optional.ofNullable(highestSeverityOfUnresolved.get(ruleType))
.map(hs -> hs.severity(onlyInLeak));
}
return value(unresolvedBySeverity.get(severity), onlyInLeak);
}
+ public long countUnresolvedByImpactSeverity(Severity severity, boolean onlyInLeak) {
+ return value(unresolvedByImpactSeverity.get(severity), onlyInLeak);
+ }
+
public long countByResolution(String resolution, boolean onlyInLeak) {
return value(byResolution.get(resolution), onlyInLeak);
}
return onlyInLeak ? count.leak : count.absolute;
}
- public String getBySoftwareQuality(SoftwareQuality softwareQuality, boolean onlyInLeak) {
+ public long countBySoftwareQuality(SoftwareQuality softwareQuality, boolean onlyInLeak) {
+ Map<Severity, Count> severityToCount = bySoftwareQualityAndSeverity.get(softwareQuality);
+ if (severityToCount == null) {
+ return 0;
+ }
+ return severityToCount.values().stream().mapToLong(count -> value(count, onlyInLeak)).sum();
+ }
+
+ public String getImpactJsonBySoftwareQuality(SoftwareQuality softwareQuality, boolean onlyInLeak) {
Map<Severity, Count> severityToCount = bySoftwareQualityAndSeverity.get(softwareQuality);
ImpactMeasureBuilder impactMeasureBuilder;
leak += group.getCount();
}
}
+
+ public void add(IssueImpactSeverityGroupDto group) {
+ absolute += group.getCount();
+ if (group.isInLeak()) {
+ leak += group.getCount();
+ }
+ }
}
private static class Effort {
FormulaContextImpl context = new FormulaContextImpl(matrix, components, debtRatingGrid);
components.getSortedTree().forEach(c -> {
- IssueCounter issueCounter = new IssueCounter(dbClient.issueDao().selectIssueGroupsByComponent(dbSession, c, beginningOfLeak),
- dbClient.issueDao().selectIssueImpactGroupsByComponent(dbSession, c, beginningOfLeak));
+ IssueCounter issueCounter = new IssueCounter(
+ dbClient.issueDao().selectIssueGroupsByComponent(dbSession, c, beginningOfLeak),
+ dbClient.issueDao().selectIssueImpactGroupsByComponent(dbSession, c, beginningOfLeak),
+ dbClient.issueDao().selectIssueImpactSeverityGroupsByComponent(dbSession, c, beginningOfLeak)
+ );
for (MeasureUpdateFormula formula : formulaFactory.getFormulas()) {
if (shouldComputeMetric(formula, useLeakFormulas, components.getBranch(), matrix)) {
context.change(c, formula);
import org.sonar.api.measures.Metric;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
+import org.sonar.core.metric.SoftwareQualitiesMetrics;
import org.sonar.server.measure.ImpactMeasureBuilder;
import org.sonar.server.measure.Rating;
(context, issues) -> context.setValue(issues.countUnresolvedByType(RuleType.SECURITY_HOTSPOT, false))),
new MeasureUpdateFormula(CoreMetrics.RELIABILITY_ISSUES, false, true, new ImpactAddChildren(),
- (context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.RELIABILITY, false))),
+ (context, issues) -> context.setValue(issues.getImpactJsonBySoftwareQuality(SoftwareQuality.RELIABILITY, false))),
new MeasureUpdateFormula(CoreMetrics.MAINTAINABILITY_ISSUES, false, true, new ImpactAddChildren(),
- (context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, false))),
+ (context, issues) -> context.setValue(issues.getImpactJsonBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, false))),
new MeasureUpdateFormula(CoreMetrics.SECURITY_ISSUES, false, true, new ImpactAddChildren(),
- (context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.SECURITY, false))),
+ (context, issues) -> context.setValue(issues.getImpactJsonBySoftwareQuality(SoftwareQuality.SECURITY, false))),
new MeasureUpdateFormula(CoreMetrics.NEW_RELIABILITY_ISSUES, true, true, new ImpactAddChildren(),
- (context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.RELIABILITY, true))),
+ (context, issues) -> context.setValue(issues.getImpactJsonBySoftwareQuality(SoftwareQuality.RELIABILITY, true))),
new MeasureUpdateFormula(CoreMetrics.NEW_MAINTAINABILITY_ISSUES, true, true, new ImpactAddChildren(),
- (context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, true))),
+ (context, issues) -> context.setValue(issues.getImpactJsonBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, true))),
new MeasureUpdateFormula(CoreMetrics.NEW_SECURITY_ISSUES, true, true, new ImpactAddChildren(),
- (context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.SECURITY, true))),
+ (context, issues) -> context.setValue(issues.getImpactJsonBySoftwareQuality(SoftwareQuality.SECURITY, true))),
new MeasureUpdateFormula(CoreMetrics.VIOLATIONS, false, new AddChildren(),
(context, issues) -> context.setValue(issues.countUnresolved(false))),
asList(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_DEVELOPMENT_COST)),
// Metrics based on Software Qualities
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.BLOCKER, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.HIGH, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.MEDIUM, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.LOW, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.INFO, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.BLOCKER, true))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.HIGH, true))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.MEDIUM, true))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.LOW, true))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countUnresolvedByImpactSeverity(org.sonar.api.issue.impact.Severity.INFO, true))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countBySoftwareQuality(SoftwareQuality.RELIABILITY, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES, false, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countBySoftwareQuality(SoftwareQuality.SECURITY, false))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, true))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countBySoftwareQuality(SoftwareQuality.RELIABILITY, true))),
+
+ new MeasureUpdateFormula(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES, true, new AddChildren(),
+ (context, issues) -> context.setValue(issues.countBySoftwareQuality(SoftwareQuality.SECURITY, true))),
+
new MeasureUpdateFormula(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, false, true, new AddChildren(),
(context, issues) -> context.setValue(issues.sumEffortOfUnresolvedBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, false))),
import org.sonar.db.component.ComponentDto;
import org.sonar.db.issue.IssueGroupDto;
import org.sonar.db.issue.IssueImpactGroupDto;
+import org.sonar.db.issue.IssueImpactSeverityGroupDto;
import org.sonar.server.measure.DebtRatingGrid;
import org.sonar.server.measure.Rating;
.assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8 + 2);
}
+ @Test
+ void compute_shouldComputeCountPerImpactSeverityOnOverallCode() {
+ withNoIssues()
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES, 0)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES, 0)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES, 0)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES, 0)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES, 0);
+
+ with(
+ newImpactSeverityGroup(HIGH, 3),
+ newImpactSeverityGroup(MEDIUM, 4),
+ newImpactSeverityGroup(LOW, 1),
+ newImpactSeverityGroup(LOW, 1),
+ newImpactSeverityGroup(BLOCKER, 7),
+ newImpactSeverityGroup(INFO, 12),
+ newImpactSeverityGroup(INFO, 3),
+
+ // Should not be counted due to status
+ newImpactSeverityGroup(HIGH, Issue.STATUS_RESOLVED, 4),
+ newImpactSeverityGroup(BLOCKER, Issue.STATUS_RESOLVED, 4),
+ newImpactSeverityGroup(BLOCKER, Issue.STATUS_RESOLVED, 4))
+
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES, 7)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES, 3)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES, 4)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES, 1 + 1)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES, 12 + 3)
+ ;
+ }
+
+ @Test
+ void compute_shouldComputeCountPerImpactSeverityOnNewCode() {
+ withNoIssues()
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES, 0)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES, 0)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES, 0)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES, 0)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES, 0);
+
+ with(
+ newImpactSeverityGroup(HIGH, 3, true),
+ newImpactSeverityGroup(MEDIUM, 4, true),
+ newImpactSeverityGroup(LOW, 1, true),
+ newImpactSeverityGroup(LOW, 1, true),
+ newImpactSeverityGroup(BLOCKER, 7, true),
+ newImpactSeverityGroup(INFO, 12, true),
+ newImpactSeverityGroup(INFO, 3, true),
+
+ // Should not be counted due to status
+ newImpactSeverityGroup(HIGH, Issue.RESOLUTION_WONT_FIX, 4, true),
+ newImpactSeverityGroup(BLOCKER, Issue.RESOLUTION_WONT_FIX, 4, true),
+ newImpactSeverityGroup(BLOCKER, Issue.RESOLUTION_FALSE_POSITIVE, 4, true),
+
+ //Should not be counted because on overall code
+ newImpactSeverityGroup(BLOCKER, 7, false))
+
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES, 7)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES, 3)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES, 4)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES, 1 + 1)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES, 12 + 3)
+ ;
+ }
+
+ @Test
+ void compute_shouldComputeCountPerSoftwareQualityOnOverallCode() {
+ withNoIssues()
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 0)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES, 0)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES, 0);
+
+ with(
+ newImpactGroup(RELIABILITY, HIGH, 3),
+ newImpactGroup(RELIABILITY, MEDIUM, 1, true),
+ newImpactGroup(SECURITY, MEDIUM, 1),
+ newImpactGroup(MAINTAINABILITY, MEDIUM, 1),
+ newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
+ // Should not count due to status
+ newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
+ newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
+ newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false))
+
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 1 + 1)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES, 3 + 1)
+ .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES, 1)
+ ;
+ }
+
+ @Test
+ void compute_shouldComputeCountPerSoftwareQualityOnNewCode() {
+ withNoIssues()
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 0)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES, 0)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES, 0);
+
+ with(
+ newImpactGroup(RELIABILITY, HIGH, 3, true),
+ newImpactGroup(RELIABILITY, MEDIUM, 1, true),
+ newImpactGroup(SECURITY, MEDIUM, 1, true),
+ newImpactGroup(SECURITY, MEDIUM, 12, true),
+ newImpactGroup(MAINTAINABILITY, MEDIUM, 1, true),
+ newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
+ // Should not count due to status
+ newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
+ newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
+ newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
+ // Should not be counted because on overall code
+ newImpactGroup(MAINTAINABILITY, MEDIUM, 1, false))
+
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 1 + 1)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES, 3 + 1)
+ .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES, 1 + 12)
+ ;
+ }
+
@Test
void compute_shouldComputeRemediationEffortBasedOnSoftwareQuality() {
withNoIssues()
return new Verifier(groups);
}
+ private Verifier with(IssueImpactSeverityGroupDto... groups) {
+ return new Verifier(groups);
+ }
+
private Verifier withNoIssues() {
return new Verifier(new IssueGroupDto[0]);
}
private class Verifier {
private IssueGroupDto[] groups = {};
private IssueImpactGroupDto[] impactGroups = {};
+ private IssueImpactSeverityGroupDto[] impactSeverityGroups = {};
private final InitialValues initialValues = new InitialValues();
private Verifier(IssueGroupDto[] groups) {
this.impactGroups = impactGroups;
}
+ private Verifier(IssueImpactSeverityGroupDto[] impactSeverityGroups) {
+ this.impactSeverityGroups = impactSeverityGroups;
+ }
+
Verifier and(Metric metric, double value) {
this.initialValues.values.put(metric, value);
return this;
.get();
assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula);
TestContext context = new TestContext(formula.getDependentMetrics(), initialValues);
- formula.compute(context, newIssueCounter(groups, impactGroups));
+ formula.compute(context, newIssueCounter(groups, impactGroups, impactSeverityGroups));
return context;
}
}
- private static IssueCounter newIssueCounter(IssueGroupDto[] groups, IssueImpactGroupDto[] impactGroups) {
- return new IssueCounter(asList(groups), asList(impactGroups));
+ private static IssueCounter newIssueCounter(IssueGroupDto[] groups, IssueImpactGroupDto[] impactGroups,
+ IssueImpactSeverityGroupDto[] impactSeverityGroups) {
+ return new IssueCounter(asList(groups), asList(impactGroups), asList(impactSeverityGroups));
}
private static IssueGroupDto newGroup() {
return dto;
}
+ private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity,
+ @Nullable String resolution, long count, boolean inLeak) {
+ IssueImpactSeverityGroupDto dto = new IssueImpactSeverityGroupDto();
+ dto.setSeverity(severity);
+ dto.setResolution(resolution);
+ dto.setCount(count);
+ dto.setInLeak(inLeak);
+ return dto;
+ }
+
private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
String status, @Nullable String resolution, long count) {
return newImpactGroup(softwareQuality, severity, status, resolution, count, 0, false);
return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, inLeak);
}
+ private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity, long count) {
+ return newImpactSeverityGroup(severity, null, count, false);
+ }
+
+ private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity, long count,
+ boolean inLeak) {
+ return newImpactSeverityGroup(severity, null, count, inLeak);
+ }
+
+ private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity,
+ @Nullable String resolution, long count) {
+ return newImpactSeverityGroup(severity, resolution, count, false);
+ }
+
private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
}