aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2016-09-30 13:18:16 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-10-03 18:19:36 +0200
commit5a8da936d010fa0718b45e88dcf2863283ab61d2 (patch)
treec68475d76013ba5a6275c5554207fbd4bc48fb92
parentff71d066464343be9513e48b4dffa682c73228dc (diff)
downloadsonarqube-5a8da936d010fa0718b45e88dcf2863283ab61d2.tar.gz
sonarqube-5a8da936d010fa0718b45e88dcf2863283ab61d2.zip
SONAR-7782 Compute Security Rating on New Code
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/NewMaintainabilityMeasuresVisitor.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java93
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java21
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForReportTest.java62
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForViewsTest.java10
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java19
7 files changed, 154 insertions, 54 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/NewMaintainabilityMeasuresVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/NewMaintainabilityMeasuresVisitor.java
index d171579a00c..16328ee9f43 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/NewMaintainabilityMeasuresVisitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/NewMaintainabilityMeasuresVisitor.java
@@ -235,7 +235,6 @@ public class NewMaintainabilityMeasuresVisitor extends PathAwareVisitorAdapter<N
LongVariationValue getDevCost(Period period) {
return this.devCost.get(period);
}
-
}
private static class CounterFactory extends SimpleStackElementFactory<Counter> {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java
index 63fe040c109..d95f7a231dc 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java
@@ -21,51 +21,79 @@
package org.sonar.server.computation.task.projectanalysis.qualitymodel;
import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
import org.sonar.api.ce.measure.Issue;
import org.sonar.api.measures.CoreMetrics;
+import org.sonar.core.issue.DefaultIssue;
import org.sonar.server.computation.task.projectanalysis.component.Component;
-import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit;
import org.sonar.server.computation.task.projectanalysis.component.PathAwareVisitorAdapter;
import org.sonar.server.computation.task.projectanalysis.formula.counter.RatingVariationValue;
import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRepository;
import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository;
+import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
import org.sonar.server.computation.task.projectanalysis.metric.Metric;
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository;
+import org.sonar.server.computation.task.projectanalysis.period.Period;
+import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolder;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
import static org.sonar.api.rule.Severity.BLOCKER;
import static org.sonar.api.rule.Severity.CRITICAL;
+import static org.sonar.api.rule.Severity.INFO;
import static org.sonar.api.rule.Severity.MAJOR;
import static org.sonar.api.rule.Severity.MINOR;
import static org.sonar.api.rules.RuleType.BUG;
import static org.sonar.api.rules.RuleType.VULNERABILITY;
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit.LEAVES;
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.A;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.B;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.C;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.D;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.E;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.valueOf;
/**
* Compute following measures :
* {@link CoreMetrics#RELIABILITY_RATING_KEY}
* {@link CoreMetrics#SECURITY_RATING_KEY}
+ * {@link CoreMetrics#NEW_SECURITY_RATING_KEY}
*/
public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter<ReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
+ private static final Map<String, Rating> RATING_BY_SEVERITY = ImmutableMap.of(
+ BLOCKER, E,
+ CRITICAL, D,
+ MAJOR, C,
+ MINOR, B,
+ INFO, A);
+
private final MeasureRepository measureRepository;
private final ComponentIssuesRepository componentIssuesRepository;
+ private final PeriodsHolder periodsHolder;
// Output metrics
private final Metric reliabilityRatingMetric;
private final Metric securityRatingMetric;
+ private final Metric newSecurityRatingMetric;
- public ReliabilityAndSecurityRatingMeasuresVisitor(MetricRepository metricRepository, MeasureRepository measureRepository, ComponentIssuesRepository componentIssuesRepository) {
- super(CrawlerDepthLimit.LEAVES, POST_ORDER, ReliabilityAndSecurityRatingMeasuresVisitor.CounterFactory.INSTANCE);
+ public ReliabilityAndSecurityRatingMeasuresVisitor(MetricRepository metricRepository, MeasureRepository measureRepository, ComponentIssuesRepository componentIssuesRepository,
+ PeriodsHolder periodsHolder) {
+ super(LEAVES, POST_ORDER, CounterFactory.INSTANCE);
this.measureRepository = measureRepository;
this.componentIssuesRepository = componentIssuesRepository;
+ this.periodsHolder = periodsHolder;
// Output metrics
this.reliabilityRatingMetric = metricRepository.getByKey(RELIABILITY_RATING_KEY);
this.securityRatingMetric = metricRepository.getByKey(SECURITY_RATING_KEY);
+ this.newSecurityRatingMetric = metricRepository.getByKey(NEW_SECURITY_RATING_KEY);
}
@Override
@@ -102,11 +130,11 @@ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisito
public void visitProjectView(Component projectView, Path<Counter> path) {
Optional<Measure> reliabilityRatingMeasure = measureRepository.getRawMeasure(projectView, reliabilityRatingMetric);
if (reliabilityRatingMeasure.isPresent()) {
- path.parent().reliabilityRating.increment(RatingGrid.Rating.valueOf(reliabilityRatingMeasure.get().getData()));
+ path.parent().reliabilityRating.increment(valueOf(reliabilityRatingMeasure.get().getData()));
}
Optional<Measure> securityRatingMeasure = measureRepository.getRawMeasure(projectView, securityRatingMetric);
if (securityRatingMeasure.isPresent()) {
- path.parent().securityRating.increment(RatingGrid.Rating.valueOf(securityRatingMeasure.get().getData()));
+ path.parent().securityRating.increment(valueOf(securityRatingMeasure.get().getData()));
}
}
@@ -114,27 +142,39 @@ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisito
processIssues(component, path);
addReliabilityRatingMeasure(component, path);
addSecurityRatingMeasure(component, path);
+ addNewSecurityRatingMeasure(component, path);
addToParent(path);
}
private void processIssues(Component component, Path<Counter> path) {
for (Issue issue : componentIssuesRepository.getIssues(component)) {
if (issue.resolution() == null) {
- path.current().addIssue(issue);
+ path.current().processIssue(issue);
+ for (Period period : periodsHolder.getPeriods()) {
+ path.current().processIssue(issue, period);
+ }
}
}
}
private void addReliabilityRatingMeasure(Component component, Path<Counter> path) {
- RatingGrid.Rating rating = path.current().reliabilityRating.getValue();
+ Rating rating = path.current().reliabilityRating.getValue();
measureRepository.add(component, reliabilityRatingMetric, newMeasureBuilder().create(rating.getIndex(), rating.name()));
}
private void addSecurityRatingMeasure(Component component, Path<Counter> path) {
- RatingGrid.Rating rating = path.current().securityRating.getValue();
+ Rating rating = path.current().securityRating.getValue();
measureRepository.add(component, securityRatingMetric, newMeasureBuilder().create(rating.getIndex(), rating.name()));
}
+ private void addNewSecurityRatingMeasure(Component component, Path<Counter> path) {
+ java.util.Optional<MeasureVariations> measureVariations = path.current().newSecurityRating.toMeasureVariations();
+ if (measureVariations.isPresent()) {
+ Measure measure = newMeasureBuilder().setVariations(measureVariations.get()).createNoValue();
+ measureRepository.add(component, newSecurityRatingMetric, measure);
+ }
+ }
+
private static void addToParent(Path<Counter> path) {
if (!path.isRoot()) {
path.parent().add(path.current());
@@ -144,6 +184,7 @@ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisito
static final class Counter {
private RatingVariationValue reliabilityRating = new RatingVariationValue();
private RatingVariationValue securityRating = new RatingVariationValue();
+ private RatingVariationValue.Array newSecurityRating = new RatingVariationValue.Array();
private Counter() {
// prevents instantiation
@@ -152,10 +193,11 @@ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisito
void add(Counter otherCounter) {
reliabilityRating.increment(otherCounter.reliabilityRating);
securityRating.increment(otherCounter.securityRating);
+ newSecurityRating.incrementAll(otherCounter.newSecurityRating);
}
- void addIssue(Issue issue) {
- RatingGrid.Rating rating = getRatingFromSeverity(issue.severity());
+ void processIssue(Issue issue) {
+ Rating rating = RATING_BY_SEVERITY.get(issue.severity());
if (issue.type().equals(BUG)) {
reliabilityRating.increment(rating);
} else if (issue.type().equals(VULNERABILITY)) {
@@ -163,39 +205,38 @@ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisito
}
}
- private static RatingGrid.Rating getRatingFromSeverity(String severity) {
- switch (severity) {
- case BLOCKER:
- return RatingGrid.Rating.E;
- case CRITICAL:
- return RatingGrid.Rating.D;
- case MAJOR:
- return RatingGrid.Rating.C;
- case MINOR:
- return RatingGrid.Rating.B;
- default:
- return RatingGrid.Rating.A;
+ void processIssue(Issue issue, Period period) {
+ if (isOnPeriod((DefaultIssue) issue, period)) {
+ Rating rating = RATING_BY_SEVERITY.get(issue.severity());
+ if (issue.type().equals(VULNERABILITY)) {
+ newSecurityRating.increment(period, rating);
+ }
}
}
+
+ private static boolean isOnPeriod(DefaultIssue issue, Period period) {
+ // Add one second to not take into account issues created during current analysis
+ return issue.creationDate().getTime() >= period.getSnapshotDate() + 1000L;
+ }
}
private static final class CounterFactory extends PathAwareVisitorAdapter.SimpleStackElementFactory<ReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
- public static final ReliabilityAndSecurityRatingMeasuresVisitor.CounterFactory INSTANCE = new ReliabilityAndSecurityRatingMeasuresVisitor.CounterFactory();
+ public static final CounterFactory INSTANCE = new CounterFactory();
private CounterFactory() {
// prevents instantiation
}
@Override
- public ReliabilityAndSecurityRatingMeasuresVisitor.Counter createForAny(Component component) {
- return new ReliabilityAndSecurityRatingMeasuresVisitor.Counter();
+ public Counter createForAny(Component component) {
+ return new Counter();
}
/**
* Counter is not used at ProjectView level, saves on instantiating useless objects
*/
@Override
- public ReliabilityAndSecurityRatingMeasuresVisitor.Counter createForProjectView(Component projectView) {
+ public Counter createForProjectView(Component projectView) {
return null;
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java
index 91790dc4a4c..4cd15ce1941 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java
@@ -46,10 +46,7 @@ import static java.lang.String.format;
import static java.util.Arrays.stream;
import static org.sonar.api.measures.Metric.ValueType.RATING;
import static org.sonar.api.measures.Metric.ValueType.valueOf;
-import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN;
-import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THAN;
import static org.sonar.db.qualitygate.QualityGateConditionDto.isOperatorAllowed;
-import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.A;
import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.E;
public class QualityGateConditionsUpdater {
@@ -137,7 +134,7 @@ public class QualityGateConditionsUpdater {
checkOperator(metric, operator, errors);
checkThresholds(warningThreshold, errorThreshold, errors);
checkPeriod(metric, period, errors);
- checkRatingMetric(metric, operator, warningThreshold, errorThreshold, period, errors);
+ checkRatingMetric(metric, warningThreshold, errorThreshold, period, errors);
if (!errors.isEmpty()) {
throw new BadRequestException(errors);
}
@@ -186,8 +183,7 @@ public class QualityGateConditionsUpdater {
}
}
- private static void checkRatingMetric(MetricDto metric, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period,
- Errors errors) {
+ private static void checkRatingMetric(MetricDto metric, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period, Errors errors) {
if (!metric.getValueType().equals(RATING.name())) {
return;
}
@@ -202,13 +198,8 @@ public class QualityGateConditionsUpdater {
addInvalidRatingError(errorThreshold, errors);
return;
}
- if (OPERATOR_GREATER_THAN.equals(operator)) {
- checkRatingGreaterThanOperator(warningThreshold, errors);
- checkRatingGreaterThanOperator(errorThreshold, errors);
- } else if (OPERATOR_LESS_THAN.equals(operator)) {
- checkRatingLesserThanOperator(warningThreshold, errors);
- checkRatingLesserThanOperator(errorThreshold, errors);
- }
+ checkRatingGreaterThanOperator(warningThreshold, errors);
+ checkRatingGreaterThanOperator(errorThreshold, errors);
}
private static void addInvalidRatingError(@Nullable String value, Errors errors) {
@@ -219,10 +210,6 @@ public class QualityGateConditionsUpdater {
errors.check(isNullOrEmpty(value) || !Objects.equals(toRating(value), E), format("There's no worse rating than E (%s)", value));
}
- private static void checkRatingLesserThanOperator(@Nullable String value, Errors errors) {
- errors.check(isNullOrEmpty(value) || !Objects.equals(toRating(value), A), format("There's no better rating than A (%s)", value));
- }
-
private static Rating toRating(String value) {
return Rating.valueOf(parseInt(value));
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForReportTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForReportTest.java
index 528980387b3..24bfa5574d1 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForReportTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForReportTest.java
@@ -21,6 +21,7 @@
package org.sonar.server.computation.task.projectanalysis.qualitymodel;
import java.util.Arrays;
+import java.util.Date;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.rules.RuleType;
@@ -35,11 +36,16 @@ import org.sonar.server.computation.task.projectanalysis.component.VisitorsCrawl
import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRepositoryRule;
import org.sonar.server.computation.task.projectanalysis.issue.FillComponentIssuesVisitorRule;
import org.sonar.server.computation.task.projectanalysis.measure.Measure;
+import org.sonar.server.computation.task.projectanalysis.measure.MeasureAssert;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
+import org.sonar.server.computation.task.projectanalysis.period.Period;
+import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING;
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING;
@@ -60,6 +66,7 @@ import static org.sonar.server.computation.task.projectanalysis.component.Report
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.toEntries;
+import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating;
import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.A;
import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.B;
import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.C;
@@ -68,8 +75,12 @@ import static org.sonar.server.computation.task.projectanalysis.qualitymodel.Rat
public class ReliabilityAndSecurityRatingMeasuresVisitorForReportTest {
+ private static final long LEAK_PERIOD_SNAPSHOT_IN_MILLISEC = 12323l;
+ private static final Date DEFAULT_ISSUE_CREATION_DATE = new Date(1000l);
+ private static final Date BEFORE_LEAK_PERIOD_DATE = new Date(LEAK_PERIOD_SNAPSHOT_IN_MILLISEC - 5000L);
+ private static final Date AFTER_LEAK_PERIOD_DATE = new Date(LEAK_PERIOD_SNAPSHOT_IN_MILLISEC + 5000L);
+
static final String LANGUAGE_KEY_1 = "lKey1";
- static final String LANGUAGE_KEY_2 = "lKey2";
static final int PROJECT_REF = 1;
static final int MODULE_REF = 12;
@@ -95,19 +106,23 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorForReportTest {
@Rule
public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
.add(RELIABILITY_RATING)
- .add(SECURITY_RATING);
+ .add(SECURITY_RATING)
+ .add(NEW_SECURITY_RATING);
@Rule
public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
@Rule
+ public PeriodsHolderRule periodsHolder = new PeriodsHolderRule().setPeriods(new Period(1, "mode", null, LEAK_PERIOD_SNAPSHOT_IN_MILLISEC, "UUID"));
+
+ @Rule
public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
@Rule
public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
VisitorsCrawler underTest = new VisitorsCrawler(Arrays.asList(fillComponentIssuesVisitorRule,
- new ReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule)));
+ new ReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule, periodsHolder)));
@Test
public void measures_created_for_project_are_all_zero_when_they_have_no_FILE_child() {
@@ -118,8 +133,8 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorForReportTest {
assertThat(toEntries(measureRepository.getRawMeasures(root)))
.containsOnly(
- entryOf(RELIABILITY_RATING_KEY, createMaintainabilityRatingMeasure(A)),
- entryOf(SECURITY_RATING_KEY, createMaintainabilityRatingMeasure(A)));
+ entryOf(RELIABILITY_RATING_KEY, createRatingMeasure(A)),
+ entryOf(SECURITY_RATING_KEY, createRatingMeasure(A)));
}
@Test
@@ -227,11 +242,41 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorForReportTest {
verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, A);
}
- private void verifyAddedRawMeasure(int componentRef, String metricKey, RatingGrid.Rating rating) {
+ @Test
+ public void compute_new_security_rating() throws Exception {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+ fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
+ newVulnerabilityIssue(10L, MAJOR).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ // Should not be taken into account
+ newVulnerabilityIssue(1L, MAJOR).setCreationDate(BEFORE_LEAK_PERIOD_DATE),
+ newBugIssue(1L, MAJOR).setCreationDate(AFTER_LEAK_PERIOD_DATE));
+ fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
+ newVulnerabilityIssue(2L, CRITICAL).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ newVulnerabilityIssue(3L, MINOR).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ // Should not be taken into account
+ newVulnerabilityIssue(10L, BLOCKER).setCreationDate(AFTER_LEAK_PERIOD_DATE).setResolution(RESOLUTION_FIXED));
+ fillComponentIssuesVisitorRule.setIssues(MODULE_REF,
+ newVulnerabilityIssue(7L, BLOCKER).setCreationDate(AFTER_LEAK_PERIOD_DATE));
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SECURITY_RATING_KEY, C);
+ verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SECURITY_RATING_KEY, D);
+ verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SECURITY_RATING_KEY, D);
+ verifyAddedRawMeasureOnLeakPeriod(MODULE_REF, NEW_SECURITY_RATING_KEY, E);
+ verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, E);
+ }
+
+ private void verifyAddedRawMeasure(int componentRef, String metricKey, Rating rating) {
assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(rating.getIndex(), rating.name())));
}
- private static Measure createMaintainabilityRatingMeasure(RatingGrid.Rating rating) {
+ private void verifyAddedRawMeasureOnLeakPeriod(int componentRef, String metricKey, Rating rating) {
+ MeasureAssert.assertThat(measureRepository.getAddedRawMeasure(componentRef, metricKey))
+ .hasVariation1(rating.getIndex());
+ }
+
+ private static Measure createRatingMeasure(Rating rating) {
return newMeasureBuilder().create(rating.getIndex(), rating.name());
}
@@ -256,7 +301,8 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorForReportTest {
return new DefaultIssue()
.setKey(Uuids.create())
.setSeverity(severity)
- .setType(type);
+ .setType(type)
+ .setCreationDate(DEFAULT_ISSUE_CREATION_DATE);
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForViewsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForViewsTest.java
index 23aedf74a55..1a437fc9f04 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForViewsTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorForViewsTest.java
@@ -29,9 +29,11 @@ import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRe
import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
+import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule;
import org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING;
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING;
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING;
@@ -82,16 +84,20 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorForViewsTest {
@Rule
public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
.add(RELIABILITY_RATING)
- .add(SECURITY_RATING);
+ .add(SECURITY_RATING)
+ .add(NEW_SECURITY_RATING);
@Rule
public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
@Rule
+ public PeriodsHolderRule periodsHolder = new PeriodsHolderRule();
+
+ @Rule
public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
VisitorsCrawler underTest = new VisitorsCrawler(
- Arrays.asList(new ReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule)));
+ Arrays.asList(new ReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule, periodsHolder)));
@Test
public void measures_created_for_view_are_all_zero_when_no_child() {
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 86acc414ecb..72336fdd7c7 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -412,6 +412,8 @@ metric.new_overall_uncovered_lines.description=New lines that are not covered by
metric.new_overall_uncovered_lines.name=Overall Uncovered Lines on New Code
metric.new_reliability_remediation_effort.description=Reliability remediation effort on new code
metric.new_reliability_remediation_effort.name=Reliability Remediation Effort on New Code
+metric.new_security_rating.description=Security rating on new code
+metric.new_security_rating.name=Security Rating on New Code
metric.new_security_remediation_effort.description=Security remediation effort on new code
metric.new_security_remediation_effort.name=Security Remediation Effort on New Code
metric.new_sqale_debt_ratio.description=Technical Debt Ratio of new/changed code.
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
index 9fcc693cc81..f000227c474 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
@@ -2361,6 +2361,25 @@ public final class CoreMetrics {
.setWorstValue(5.0)
.create();
+ /**
+ * @since 6.2
+ */
+ public static final String NEW_SECURITY_RATING_KEY = "new_security_rating";
+
+ /**
+ * @since 6.2
+ */
+ public static final Metric<Integer> NEW_SECURITY_RATING = new Metric.Builder(NEW_SECURITY_RATING_KEY, "Security Rating on New Code", Metric.ValueType.RATING)
+ .setDescription("Security rating on new code")
+ .setDomain(DOMAIN_SECURITY)
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDeleteHistoricalData(true)
+ .setOptimizedBestValue(true)
+ .setQualitative(true)
+ .setBestValue(1.0)
+ .setWorstValue(5.0)
+ .create();
+
// --------------------------------------------------------------------------------------------------------------------
//
// FILE DATA