diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-09-30 13:18:16 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-10-03 18:19:36 +0200 |
commit | 5a8da936d010fa0718b45e88dcf2863283ab61d2 (patch) | |
tree | c68475d76013ba5a6275c5554207fbd4bc48fb92 | |
parent | ff71d066464343be9513e48b4dffa682c73228dc (diff) | |
download | sonarqube-5a8da936d010fa0718b45e88dcf2863283ab61d2.tar.gz sonarqube-5a8da936d010fa0718b45e88dcf2863283ab61d2.zip |
SONAR-7782 Compute Security Rating on New Code
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 |