@@ -21,6 +21,7 @@ package org.sonar.ce.task.projectanalysis.formula; | |||
import java.util.Optional; | |||
import org.sonar.ce.task.projectanalysis.measure.Measure; | |||
import org.sonar.server.measure.ImpactMeasureBuilder; | |||
import static java.util.Objects.requireNonNull; | |||
@@ -56,14 +57,14 @@ public class ImpactSumFormula implements Formula<ImpactSumFormula.ImpactCounter> | |||
private boolean initialized = false; | |||
private boolean hasEmptyValue = false; | |||
private final MeasureImpactBuilder measureImpactBuilder = new MeasureImpactBuilder(); | |||
private final ImpactMeasureBuilder measureImpactBuilder = ImpactMeasureBuilder.createEmpty(); | |||
@Override | |||
public void aggregate(ImpactSumFormula.ImpactCounter counter) { | |||
Optional<String> value = counter.getValue(); | |||
if (value.isPresent()) { | |||
initialized = true; | |||
measureImpactBuilder.add(value.get()); | |||
measureImpactBuilder.add(ImpactMeasureBuilder.fromString(value.get())); | |||
} else { | |||
hasEmptyValue = true; | |||
} | |||
@@ -75,7 +76,7 @@ public class ImpactSumFormula implements Formula<ImpactSumFormula.ImpactCounter> | |||
String data = measureOptional.map(Measure::getData).orElse(null); | |||
if (data != null) { | |||
initialized = true; | |||
measureImpactBuilder.add(data); | |||
measureImpactBuilder.add(ImpactMeasureBuilder.fromString(data)); | |||
} else { | |||
hasEmptyValue = true; | |||
} | |||
@@ -83,7 +84,7 @@ public class ImpactSumFormula implements Formula<ImpactSumFormula.ImpactCounter> | |||
public Optional<String> getValue() { | |||
if (initialized && !hasEmptyValue) { | |||
return Optional.ofNullable(measureImpactBuilder.build()); | |||
return Optional.ofNullable(measureImpactBuilder.buildAsString()); | |||
} | |||
return Optional.empty(); | |||
} |
@@ -1,42 +0,0 @@ | |||
/* | |||
* 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.ce.task.projectanalysis.formula; | |||
import com.google.gson.Gson; | |||
import com.google.gson.reflect.TypeToken; | |||
import java.lang.reflect.Type; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
public class MeasureImpactBuilder { | |||
private static final Type GSON_MAP_TYPE = new TypeToken<Map<String, Integer>>() { | |||
}.getType(); | |||
private static final Gson gson = new Gson(); | |||
private final Map<String, Integer> map = new LinkedHashMap<>(); | |||
public void add(String value) { | |||
Map<String, Integer> impactMap = gson.fromJson(value, GSON_MAP_TYPE); | |||
impactMap.forEach((key, val) -> map.merge(key, val, Integer::sum)); | |||
} | |||
public String build() { | |||
return gson.toJson(map); | |||
} | |||
} |
@@ -23,7 +23,6 @@ import com.google.common.collect.EnumMultiset; | |||
import com.google.common.collect.HashMultiset; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.google.common.collect.Multiset; | |||
import com.google.gson.Gson; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import javax.annotation.Nullable; | |||
@@ -37,6 +36,7 @@ import org.sonar.ce.task.projectanalysis.measure.MeasureRepository; | |||
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.server.measure.ImpactMeasureBuilder; | |||
import static org.sonar.api.issue.Issue.STATUS_CONFIRMED; | |||
import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
@@ -126,8 +126,6 @@ public class IssueCounter extends IssueVisitor { | |||
.put(SECURITY_HOTSPOT, NEW_SECURITY_HOTSPOTS_KEY) | |||
.build(); | |||
private static final Gson gson = new Gson(); | |||
private final MetricRepository metricRepository; | |||
private final MeasureRepository measureRepository; | |||
private final NewIssueClassifier newIssueClassifier; | |||
@@ -191,7 +189,7 @@ public class IssueCounter extends IssueVisitor { | |||
private void addMeasuresByImpact(Component component) { | |||
for (Map.Entry<String, Map<String, Long>> impactEntry : currentCounters.counter().impactsBag.entrySet()) { | |||
String json = gson.toJson(impactEntry.getValue()); | |||
String json = ImpactMeasureBuilder.fromMap(impactEntry.getValue()).buildAsString(); | |||
addMeasure(component, IMPACT_TO_METRIC_KEY.get(impactEntry.getKey()), json); | |||
} | |||
} | |||
@@ -267,12 +265,7 @@ public class IssueCounter extends IssueVisitor { | |||
private void initImpactsBag() { | |||
for (SoftwareQuality quality : SoftwareQuality.values()) { | |||
Map<String, Long> severityMap = new HashMap<>(); | |||
for (Severity severity : Severity.values()) { | |||
severityMap.put(severity.name(), 0L); | |||
} | |||
severityMap.put("total", 0L); | |||
impactsBag.put(quality.name(), severityMap); | |||
impactsBag.put(quality.name(), ImpactMeasureBuilder.createEmpty().buildAsMap()); | |||
} | |||
} | |||
@@ -336,7 +329,7 @@ public class IssueCounter extends IssueVisitor { | |||
for (Map.Entry<SoftwareQuality, Severity> impact : issue.impacts().entrySet()) { | |||
impactsBag.compute(impact.getKey().name(), (key, value) -> { | |||
value.compute(impact.getValue().name(), (severity, count) -> count == null ? 1 : count + 1); | |||
value.compute("total", (total, count) -> count == null ? 1 : count + 1); | |||
value.compute(ImpactMeasureBuilder.TOTAL_KEY, (total, count) -> count == null ? 1 : count + 1); | |||
return value; | |||
}); | |||
} |
@@ -20,7 +20,7 @@ | |||
package org.sonar.ce.task.projectanalysis.formula; | |||
import com.google.gson.Gson; | |||
import java.util.Map; | |||
import java.util.LinkedHashMap; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.junit.Test; | |||
@@ -131,7 +131,12 @@ public class ImpactSumFormulaTest { | |||
public String newImpactJson(Integer total, Integer high, Integer medium, Integer low) { | |||
return gson.toJson(Map.of("total", total, Severity.HIGH.name(), high, Severity.MEDIUM.name(), medium, Severity.LOW.name(), low)); | |||
LinkedHashMap<Object, Object> map = new LinkedHashMap<>(); | |||
map.put(Severity.LOW.name(), low); | |||
map.put(Severity.MEDIUM.name(), medium); | |||
map.put(Severity.HIGH.name(), high); | |||
map.put("total", total); | |||
return gson.toJson(map); | |||
} | |||
private void addMeasure(String metricKey, @Nullable String value) { |
@@ -1,57 +0,0 @@ | |||
/* | |||
* 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.ce.task.projectanalysis.formula; | |||
import com.google.gson.Gson; | |||
import java.util.Map; | |||
import org.assertj.core.api.Assertions; | |||
import org.junit.Test; | |||
import org.sonar.api.issue.impact.Severity; | |||
public class MeasureImpactBuilderTest { | |||
Gson gson = new Gson(); | |||
@Test | |||
public void add_shouldAddExpectedInitialValues() { | |||
MeasureImpactBuilder measureImpactBuilder = new MeasureImpactBuilder(); | |||
Assertions.assertThat(measureImpactBuilder.build()).isEqualTo("{}"); | |||
measureImpactBuilder = new MeasureImpactBuilder(); | |||
Map<String, Integer> map = Map.of("total", 3, Severity.HIGH.name(), 2, Severity.MEDIUM.name(), 1, Severity.LOW.name(), 4); | |||
measureImpactBuilder.add(gson.toJson(map)); | |||
Assertions.assertThat(measureImpactBuilder.build()).isEqualTo(gson.toJson(map)); | |||
} | |||
@Test | |||
public void add_shouldMergeValuesFromDifferentMaps() { | |||
MeasureImpactBuilder measureImpactBuilder = new MeasureImpactBuilder(); | |||
Map<String, Integer> map = Map.of("total", 3, Severity.HIGH.name(), 2, Severity.MEDIUM.name(), 1, Severity.LOW.name(), 4); | |||
measureImpactBuilder.add(gson.toJson(map)); | |||
Map<String, Integer> map2 = Map.of("total", 6, Severity.HIGH.name(), 4, Severity.MEDIUM.name(), 2, Severity.LOW.name(), 1); | |||
measureImpactBuilder.add(gson.toJson(map2)); | |||
Assertions.assertThat(measureImpactBuilder.build()).isEqualTo(gson.toJson(Map.of("total", 9, Severity.HIGH.name(), 6, Severity.MEDIUM.name(), 3, Severity.LOW.name(), 5))); | |||
} | |||
} |
@@ -20,12 +20,11 @@ | |||
package org.sonar.ce.task.projectanalysis.issue; | |||
import com.google.gson.Gson; | |||
import java.lang.constant.Constable; | |||
import java.util.Arrays; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.assertj.core.data.MapEntry; | |||
import org.junit.Rule; | |||
@@ -42,6 +41,7 @@ import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule; | |||
import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.db.rule.RuleTesting; | |||
import org.sonar.server.measure.ImpactMeasureBuilder; | |||
import static java.util.Arrays.stream; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -360,14 +360,22 @@ public class IssueCounterTest { | |||
Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet(); | |||
assertSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, Map.of(HIGH, 2, MEDIUM, 2, LOW, 0, "total", 4), entries); | |||
assertSoftwareQualityMeasures(SoftwareQuality.SECURITY, Map.of(HIGH, 1, MEDIUM, 1, LOW, 0, "total", 2), entries); | |||
assertSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, Map.of(HIGH, 0, MEDIUM, 0, LOW, 0, "total", 0), entries); | |||
assertSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0), entries); | |||
assertSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0), entries); | |||
assertSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0), entries); | |||
} | |||
private void assertSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends Constable, Integer> expectedRaw, | |||
private static Map<String, Long> getImpactMeasure(long total, long high, long medium, long low) { | |||
Map<String, Long> map = new LinkedHashMap<>(); | |||
map.put(LOW.name(), low); | |||
map.put(MEDIUM.name(), medium); | |||
map.put(HIGH.name(), high); | |||
map.put(ImpactMeasureBuilder.TOTAL_KEY, total); | |||
return map; | |||
} | |||
private void assertSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, | |||
Set<Map.Entry<String, Measure>> actualRaw) { | |||
Map<String, Long> expectedMap = expectedRaw.entrySet().stream().collect(Collectors.toMap(k -> k.getKey().toString(), v -> v.getValue().longValue())); | |||
Map.Entry<String, Measure> softwareQualityMap = actualRaw.stream() | |||
.filter(e -> e.getKey().equals(IMPACT_TO_METRIC_KEY.get(softwareQuality.name()))) |
@@ -0,0 +1,102 @@ | |||
/* | |||
* 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.measure; | |||
import com.google.gson.Gson; | |||
import com.google.gson.GsonBuilder; | |||
import com.google.gson.reflect.TypeToken; | |||
import java.lang.reflect.Type; | |||
import java.util.Arrays; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
import org.sonar.api.issue.impact.Severity; | |||
import static org.sonar.api.utils.Preconditions.checkArgument; | |||
/** | |||
* Builder class to help build measures based on impacts with payload such as @{link {@link org.sonar.api.measures.CoreMetrics#RELIABILITY_ISSUES}}. | |||
*/ | |||
public class ImpactMeasureBuilder { | |||
private static final Gson GSON = new GsonBuilder().create(); | |||
private static final Type GSON_MAP_TYPE = new TypeToken<Map<String, Long>>() { | |||
}.getType(); | |||
public static final String TOTAL_KEY = "total"; | |||
private final Map<String, Long> map; | |||
private ImpactMeasureBuilder(Map<String, Long> map) { | |||
this.map = new LinkedHashMap<>(map); | |||
} | |||
public static ImpactMeasureBuilder createEmpty() { | |||
Map<String, Long> severityMap = new LinkedHashMap<>(); | |||
for (Severity severity : Severity.values()) { | |||
severityMap.put(severity.name(), 0L); | |||
} | |||
severityMap.put(TOTAL_KEY, 0L); | |||
return new ImpactMeasureBuilder(severityMap); | |||
} | |||
public static ImpactMeasureBuilder newInstance() { | |||
return new ImpactMeasureBuilder(new LinkedHashMap<>()); | |||
} | |||
public static ImpactMeasureBuilder fromMap(Map<String, Long> map) { | |||
checkImpactMap(map); | |||
return new ImpactMeasureBuilder(map); | |||
} | |||
private static void checkImpactMap(Map<String, Long> map) { | |||
checkArgument(map.containsKey(TOTAL_KEY), "Map must contain a total key"); | |||
Arrays.stream(Severity.values()).forEach(severity -> checkArgument(map.containsKey(severity.name()), "Map must contain a key for severity " + severity.name())); | |||
} | |||
public static ImpactMeasureBuilder fromString(String value) { | |||
Map<String, Long> impactMap = GSON.fromJson(value, GSON_MAP_TYPE); | |||
checkImpactMap(impactMap); | |||
return new ImpactMeasureBuilder(impactMap); | |||
} | |||
public ImpactMeasureBuilder setSeverity(Severity severity, long value) { | |||
map.put(severity.name(), value); | |||
return this; | |||
} | |||
public ImpactMeasureBuilder setTotal(long value) { | |||
map.put(TOTAL_KEY, value); | |||
return this; | |||
} | |||
public ImpactMeasureBuilder add(ImpactMeasureBuilder other) { | |||
other.buildAsMap().forEach((key, val) -> map.merge(key, val, Long::sum)); | |||
return this; | |||
} | |||
public String buildAsString() { | |||
checkImpactMap(map); | |||
return GSON.toJson(map); | |||
} | |||
public Map<String, Long> buildAsMap() { | |||
checkImpactMap(map); | |||
return map; | |||
} | |||
} |
@@ -0,0 +1,129 @@ | |||
/* | |||
* 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.measure; | |||
import java.util.Map; | |||
import org.junit.Test; | |||
import org.sonar.api.issue.impact.Severity; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
public class ImpactMeasureBuilderTest { | |||
@Test | |||
public void createEmptyMeasure_shouldReturnMeasureWithAllFields() { | |||
ImpactMeasureBuilder builder = ImpactMeasureBuilder.createEmpty(); | |||
assertThat(builder.buildAsMap()) | |||
.containsAllEntriesOf(getImpactMap(0L, 0L, 0L, 0L)); | |||
} | |||
private static Map<String, Long> getImpactMap(Long total, Long high, Long medium, Long low) { | |||
return Map.of("total", total, Severity.HIGH.name(), high, Severity.MEDIUM.name(), medium, Severity.LOW.name(), low); | |||
} | |||
@Test | |||
public void fromMap_shouldInitializeCorrectlyTheBuilder() { | |||
Map<String, Long> map = getImpactMap(6L, 3L, 2L, 1L); | |||
ImpactMeasureBuilder builder = ImpactMeasureBuilder.fromMap(map); | |||
assertThat(builder.buildAsMap()) | |||
.isEqualTo(map); | |||
} | |||
@Test | |||
public void fromMap_whenMissingField_shouldThrowException() { | |||
Map<String, Long> map = Map.of(); | |||
assertThatThrownBy(() -> ImpactMeasureBuilder.fromMap(map)) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Map must contain a total key"); | |||
} | |||
@Test | |||
public void toString_shouldInitializeCorrectlyTheBuilder() { | |||
ImpactMeasureBuilder builder = ImpactMeasureBuilder.fromString(""" | |||
{ | |||
total: 6, | |||
HIGH: 3, | |||
MEDIUM: 2, | |||
LOW: 1 | |||
} | |||
"""); | |||
assertThat(builder.buildAsMap()) | |||
.isEqualTo(getImpactMap(6L, 3L, 2L, 1L)); | |||
} | |||
@Test | |||
public void buildAsMap_whenIsEmpty_shouldThrowException() { | |||
ImpactMeasureBuilder impactMeasureBuilder = ImpactMeasureBuilder.newInstance(); | |||
assertThatThrownBy(impactMeasureBuilder::buildAsMap) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Map must contain a total key"); | |||
} | |||
@Test | |||
public void buildAsMap_whenMissingSeverity_shouldThrowException() { | |||
ImpactMeasureBuilder impactMeasureBuilder = ImpactMeasureBuilder.newInstance() | |||
.setTotal(1L) | |||
.setSeverity(Severity.HIGH, 1L) | |||
.setSeverity(Severity.MEDIUM, 1L); | |||
assertThatThrownBy(impactMeasureBuilder::buildAsMap) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Map must contain a key for severity LOW"); | |||
} | |||
@Test | |||
public void buildAsString_whenMissingSeverity_shouldThrowException() { | |||
ImpactMeasureBuilder impactMeasureBuilder = ImpactMeasureBuilder.newInstance() | |||
.setTotal(1L) | |||
.setSeverity(Severity.HIGH, 1L) | |||
.setSeverity(Severity.MEDIUM, 1L); | |||
assertThatThrownBy(impactMeasureBuilder::buildAsString) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Map must contain a key for severity LOW"); | |||
} | |||
@Test | |||
public void setSeverity_shouldInitializeSeverityValues() { | |||
ImpactMeasureBuilder builder = ImpactMeasureBuilder.newInstance() | |||
.setSeverity(Severity.HIGH, 3L) | |||
.setSeverity(Severity.MEDIUM, 2L) | |||
.setSeverity(Severity.LOW, 1L) | |||
.setTotal(6L); | |||
assertThat(builder.buildAsMap()) | |||
.isEqualTo(getImpactMap(6L, 3L, 2L, 1L)); | |||
} | |||
@Test | |||
public void add_shouldSumImpactsAndTotal() { | |||
ImpactMeasureBuilder builder = ImpactMeasureBuilder.fromMap(getImpactMap(6L, 3L, 2L, 1L)) | |||
.add(ImpactMeasureBuilder.newInstance().setTotal(6L).setSeverity(Severity.HIGH, 3L).setSeverity(Severity.MEDIUM, 2L).setSeverity(Severity.LOW, 1L)); | |||
assertThat(builder.buildAsMap()) | |||
.isEqualTo(getImpactMap(12L, 6L, 4L, 2L)); | |||
} | |||
@Test | |||
public void add_whenOtherMapHasMissingField_shouldThrowException() { | |||
ImpactMeasureBuilder impactMeasureBuilder = ImpactMeasureBuilder.newInstance(); | |||
assertThatThrownBy(() -> impactMeasureBuilder.add(ImpactMeasureBuilder.newInstance())) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Map must contain a total key"); | |||
} | |||
} |
@@ -19,8 +19,6 @@ | |||
*/ | |||
package org.sonar.server.measure.live; | |||
import com.google.gson.Gson; | |||
import com.google.gson.GsonBuilder; | |||
import java.util.Collection; | |||
import java.util.EnumMap; | |||
import java.util.HashMap; | |||
@@ -34,6 +32,7 @@ import org.sonar.api.rules.RuleType; | |||
import org.sonar.db.issue.IssueGroupDto; | |||
import org.sonar.db.issue.IssueImpactGroupDto; | |||
import org.sonar.db.rule.SeverityUtil; | |||
import org.sonar.server.measure.ImpactMeasureBuilder; | |||
import static org.sonar.api.rule.Severity.INFO; | |||
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; | |||
@@ -50,7 +49,6 @@ class IssueCounter { | |||
private final Count unresolved = new Count(); | |||
private final Count highImpactAccepted = new Count(); | |||
private final Map<SoftwareQuality, Map<Severity, Count>> bySoftwareQualityAndSeverity = new EnumMap<>(SoftwareQuality.class); | |||
private final Gson gson = new GsonBuilder().create(); | |||
IssueCounter(Collection<IssueGroupDto> groups, Collection<IssueImpactGroupDto> impactGroups) { | |||
for (IssueGroupDto group : groups) { | |||
@@ -172,20 +170,18 @@ class IssueCounter { | |||
public String getBySoftwareQuality(SoftwareQuality softwareQuality) { | |||
Map<Severity, Count> severityToCount = bySoftwareQualityAndSeverity.get(softwareQuality); | |||
Map<String, Long> impactMap = new HashMap<>(); | |||
ImpactMeasureBuilder impactMeasureBuilder; | |||
if (severityToCount != null) { | |||
impactMap.put("total", severityToCount.values().stream().mapToLong(count -> count.absolute).sum()); | |||
impactMeasureBuilder = ImpactMeasureBuilder.newInstance(); | |||
for (Severity severity : Severity.values()) { | |||
impactMap.put(severity.name(), Optional.ofNullable(severityToCount.get(severity)).map(count -> count.absolute).orElse(0L)); | |||
impactMeasureBuilder = impactMeasureBuilder.setSeverity(severity, Optional.ofNullable(severityToCount.get(severity)).map(count -> count.absolute).orElse(0L)); | |||
} | |||
impactMeasureBuilder = impactMeasureBuilder.setTotal(severityToCount.values().stream().mapToLong(count -> count.absolute).sum()); | |||
} else { | |||
impactMap.put("total", 0L); | |||
for (Severity severity : Severity.values()) { | |||
impactMap.put(severity.name(), 0L); | |||
} | |||
impactMeasureBuilder = ImpactMeasureBuilder.createEmpty(); | |||
} | |||
return gson.toJson(impactMap); | |||
return impactMeasureBuilder.buildAsString(); | |||
} | |||
private static class Count { |
@@ -19,24 +19,18 @@ | |||
*/ | |||
package org.sonar.server.measure.live; | |||
import com.google.gson.Gson; | |||
import com.google.gson.GsonBuilder; | |||
import com.google.gson.reflect.TypeToken; | |||
import java.lang.reflect.Type; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.OptionalInt; | |||
import java.util.Set; | |||
import java.util.function.BiConsumer; | |||
import java.util.stream.Collectors; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.impact.SoftwareQuality; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.server.measure.ImpactMeasureBuilder; | |||
import org.sonar.server.measure.Rating; | |||
import static java.util.Arrays.asList; | |||
@@ -255,9 +249,6 @@ public class MeasureUpdateFormulaFactoryImpl implements MeasureUpdateFormulaFact | |||
private static final Set<Metric> FORMULA_METRICS = MeasureUpdateFormulaFactory.extractMetrics(FORMULAS); | |||
private static final Gson GSON = new GsonBuilder().create(); | |||
private static final Type MAP_TYPE = new TypeToken<Map<String, Long>>() {}.getType(); | |||
private static double debtDensity(MeasureUpdateFormula.Context context) { | |||
double debt = Math.max(context.getValue(CoreMetrics.TECHNICAL_DEBT).orElse(0.0D), 0.0D); | |||
Optional<Double> devCost = context.getText(CoreMetrics.DEVELOPMENT_COST).map(Double::parseDouble); | |||
@@ -305,22 +296,12 @@ public class MeasureUpdateFormulaFactoryImpl implements MeasureUpdateFormulaFact | |||
private static class ImpactAddChildren implements BiConsumer<MeasureUpdateFormula.Context, MeasureUpdateFormula> { | |||
@Override | |||
public void accept(MeasureUpdateFormula.Context context, MeasureUpdateFormula formula) { | |||
List<Map<String, Long>> measures = context.getChildrenTextValues().stream() | |||
.map(ImpactAddChildren::toMap) | |||
.collect(Collectors.toList()); | |||
context.getText(formula.getMetric()).ifPresent(value -> measures.add(toMap(value))); | |||
Map<String, Long> newValue = new HashMap<>(); | |||
newValue.put("total", measures.stream().mapToLong(map -> map.get("total")).sum()); | |||
for (org.sonar.api.issue.impact.Severity severity : org.sonar.api.issue.impact.Severity.values()) { | |||
newValue.put(severity.name(), measures.stream().mapToLong(map -> map.get(severity.name())).sum()); | |||
} | |||
context.setValue(GSON.toJson(newValue)); | |||
} | |||
private static Map<String, Long> toMap(String value) { | |||
return GSON.fromJson(value, MAP_TYPE); | |||
ImpactMeasureBuilder impactMeasureBuilder = ImpactMeasureBuilder.createEmpty(); | |||
context.getChildrenTextValues().stream() | |||
.map(ImpactMeasureBuilder::fromString) | |||
.forEach(impactMeasureBuilder::add); | |||
context.getText(formula.getMetric()).ifPresent(value -> impactMeasureBuilder.add(ImpactMeasureBuilder.fromString(value))); | |||
context.setValue(impactMeasureBuilder.buildAsString()); | |||
} | |||
} | |||