aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-ce-task-projectanalysis
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2019-06-05 11:51:31 +0200
committerSonarTech <sonartech@sonarsource.com>2019-06-14 20:21:10 +0200
commitf6028da2015f64cb71146b1c8736e800c9ed7b54 (patch)
tree20462b8054ac13eb5ee7e98edfc954e4f83ddf01 /server/sonar-ce-task-projectanalysis
parent00e91c1362a5c02384ba9145ad02d9289ba5e686 (diff)
downloadsonarqube-f6028da2015f64cb71146b1c8736e800c9ed7b54.tar.gz
sonarqube-f6028da2015f64cb71146b1c8736e800c9ed7b54.zip
SONAR-12131 Compute Security Review Rating measures on projects
* Compute Security Review Rating measures on projects * Live update Security Review Rating measures
Diffstat (limited to 'server/sonar-ce-task-projectanalysis')
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java4
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepository.java18
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitor.java67
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java36
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitorTest.java95
5 files changed, 171 insertions, 49 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java
index 99358168cc2..f507563326b 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java
@@ -77,9 +77,9 @@ import org.sonar.ce.task.projectanalysis.issue.RuleRepositoryImpl;
import org.sonar.ce.task.projectanalysis.issue.RuleTagsCopier;
import org.sonar.ce.task.projectanalysis.issue.ScmAccountToUser;
import org.sonar.ce.task.projectanalysis.issue.ScmAccountToUserLoader;
+import org.sonar.ce.task.projectanalysis.issue.ShortBranchOrPullRequestTrackerExecution;
import org.sonar.ce.task.projectanalysis.issue.SiblingsIssueMerger;
import org.sonar.ce.task.projectanalysis.issue.SiblingsIssuesLoader;
-import org.sonar.ce.task.projectanalysis.issue.ShortBranchOrPullRequestTrackerExecution;
import org.sonar.ce.task.projectanalysis.issue.TrackerBaseInputFactory;
import org.sonar.ce.task.projectanalysis.issue.TrackerExecution;
import org.sonar.ce.task.projectanalysis.issue.TrackerMergeOrTargetBranchInputFactory;
@@ -111,6 +111,7 @@ import org.sonar.ce.task.projectanalysis.qualitymodel.NewMaintainabilityMeasures
import org.sonar.ce.task.projectanalysis.qualitymodel.NewReliabilityAndSecurityRatingMeasuresVisitor;
import org.sonar.ce.task.projectanalysis.qualitymodel.RatingSettings;
import org.sonar.ce.task.projectanalysis.qualitymodel.ReliabilityAndSecurityRatingMeasuresVisitor;
+import org.sonar.ce.task.projectanalysis.qualitymodel.SecurityReviewRatingVisitor;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderImpl;
import org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepositoryImpl;
import org.sonar.ce.task.projectanalysis.scm.ScmInfoDbLoader;
@@ -265,6 +266,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop
NewMaintainabilityMeasuresVisitor.class,
ReliabilityAndSecurityRatingMeasuresVisitor.class,
NewReliabilityAndSecurityRatingMeasuresVisitor.class,
+ SecurityReviewRatingVisitor.class,
LastCommitVisitor.class,
MeasureComputersVisitor.class,
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepository.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepository.java
index 4d6aeba7a76..57d3d529bf3 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepository.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepository.java
@@ -32,8 +32,7 @@ public interface MeasureRepository {
* Retrieves the base measure (ie. the one currently existing in DB) for the specified {@link Component} for
* the specified {@link MetricImpl} if it exists.
* <p>
- * This method searches for Measure which are specific to the Component and not associated to a rule or a
- * characteristic.
+ * This method searches for Measure which are specific to the Component.
* </p>
*
* @throws NullPointerException if either argument is {@code null}
@@ -42,32 +41,23 @@ public interface MeasureRepository {
/**
* Retrieves the measure created during the current analysis for the specified {@link Component} for the specified
- * {@link Metric} if it exists (ie. one created by the Compute Engine or the Batch) and which is <strong>not</strong>
- * associated to a rule, a characteristic, or a developer.
+ * {@link Metric} if it exists (ie. one created by the Compute Engine or the Scanner).
*/
Optional<Measure> getRawMeasure(Component component, Metric metric);
/**
* Returns the {@link Measure}s for the specified {@link Component} and the specified {@link Metric}.
- * <p>
- * Their will be one measure not associated to rules, characteristics or developers, the other ones will be associated to rules or to characteristics
- * (see {@link Measure#equals(Object)}.
- * </p>
*/
Set<Measure> getRawMeasures(Component component, Metric metric);
/**
* Returns the {@link Measure}s for the specified {@link Component} mapped by their metric key.
- * <p>
- * Their can be multiple measures for the same Metric but only one which has no rule nor characteristic, one with a
- * specific ruleId and one with specific characteristicId (see {@link Measure#equals(Object)}.
- * </p>
*/
SetMultimap<String, Measure> getRawMeasures(Component component);
/**
* Adds the specified measure for the specified Component and Metric. There can be no more than one measure for a
- * specific combination of Component, Metric and association to a specific rule or characteristic.
+ * specific combination of Component, Metric.
*
* @throws NullPointerException if any of the arguments is null
* @throws UnsupportedOperationException when trying to add a measure when one already exists for the specified Component/Metric paar
@@ -76,7 +66,7 @@ public interface MeasureRepository {
/**
* Updates the specified measure for the specified Component and Metric. There can be no more than one measure for a
- * specific combination of Component, Metric and association to a specific rule or characteristic.
+ * specific combination of Component, Metric.
*
* @throws NullPointerException if any of the arguments is null
* @throws UnsupportedOperationException when trying to update a non existing measure
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitor.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitor.java
new file mode 100644
index 00000000000..6e5da70e2f1
--- /dev/null
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitor.java
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.qualitymodel;
+
+import java.util.Optional;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
+import org.sonar.ce.task.projectanalysis.measure.Measure;
+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.server.measure.Rating;
+import org.sonar.server.security.SecurityReviewRating;
+
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
+import static org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit.PROJECT;
+import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
+
+public class SecurityReviewRatingVisitor extends TypeAwareVisitorAdapter {
+
+ private final MeasureRepository measureRepository;
+ private final Metric nclocMetric;
+ private final Metric securityHostspotsMetric;
+ private final Metric securityReviewRatingMetric;
+
+ public SecurityReviewRatingVisitor(MeasureRepository measureRepository, MetricRepository metricRepository) {
+ super(PROJECT, Order.POST_ORDER);
+ this.measureRepository = measureRepository;
+ this.nclocMetric = metricRepository.getByKey(NCLOC_KEY);
+ this.securityHostspotsMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_KEY);
+ this.securityReviewRatingMetric = metricRepository.getByKey(SECURITY_REVIEW_RATING_KEY);
+ }
+
+ @Override
+ public void visitProject(Component project) {
+ Optional<Measure> nclocMeasure = measureRepository.getRawMeasure(project, nclocMetric);
+ Optional<Measure> securityHostspotsMeasure = measureRepository.getRawMeasure(project, securityHostspotsMetric);
+ if (!nclocMeasure.isPresent() || !securityHostspotsMeasure.isPresent()) {
+ return;
+ }
+ int ncloc = nclocMeasure.get().getIntValue();
+ int securityHotspots = securityHostspotsMeasure.get().getIntValue();
+ Rating rating = SecurityReviewRating.compute(ncloc, securityHotspots);
+ measureRepository.add(project, securityReviewRatingMetric, newMeasureBuilder().create(rating.getIndex(), rating.name()));
+ }
+
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java
index d83245d86ac..2c579151024 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java
@@ -23,7 +23,6 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.SetMultimap;
-import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -61,15 +60,8 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe
private final Map<InternalKey, Measure> baseMeasures = new HashMap<>();
private final Map<InternalKey, Measure> rawMeasures = new HashMap<>();
private final Map<InternalKey, Measure> initialRawMeasures = new HashMap<>();
- private Collection<Component> loadedAsRawComponents;
- private Collection<Metric> loadedAsRawMetrics;
- private final Predicate<Map.Entry<InternalKey, Measure>> isAddedMeasure = new Predicate<Map.Entry<InternalKey, Measure>>() {
- @Override
- public boolean apply(@Nonnull Map.Entry<InternalKey, Measure> input) {
- return !initialRawMeasures.containsKey(input.getKey())
- || !MeasureRepoEntry.deepEquals(input.getValue(), initialRawMeasures.get(input.getKey()));
- }
- };
+ private final Predicate<Map.Entry<InternalKey, Measure>> isAddedMeasure = input -> !initialRawMeasures.containsKey(input.getKey())
+ || !MeasureRepoEntry.deepEquals(input.getValue(), initialRawMeasures.get(input.getKey()));
private MeasureRepositoryRule(ComponentProvider componentProvider, @Nullable MetricRepositoryRule metricRepositoryRule) {
this.componentProvider = componentProvider;
@@ -95,18 +87,6 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe
return new MeasureRepositoryRule(new TreeComponentProvider(treeRoot), requireNonNull(metricRepositoryRule));
}
- public MeasureRepositoryRule addBaseMeasure(Component component, Metric metric, Measure measure) {
- checkAndInitProvidersState();
-
- InternalKey internalKey = new InternalKey(component, metric);
- checkState(!baseMeasures.containsKey(internalKey),
- format("Can not add a BaseMeasure twice for a Component (ref=%s) and Metric (key=%s)", getRef(component), metric.getKey()));
-
- baseMeasures.put(internalKey, measure);
-
- return this;
- }
-
public MeasureRepositoryRule addBaseMeasure(int componentRef, String metricKey, Measure measure) {
checkAndInitProvidersState();
@@ -188,23 +168,11 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe
return Optional.ofNullable(baseMeasures.get(new InternalKey(component, metric)));
}
- public Collection<Component> getComponentsLoadedAsRaw() {
- return loadedAsRawComponents;
- }
-
- public Collection<Metric> getMetricsLoadedAsRaw() {
- return loadedAsRawMetrics;
- }
-
@Override
public Optional<Measure> getRawMeasure(Component component, Metric metric) {
return Optional.ofNullable(rawMeasures.get(new InternalKey(component, metric)));
}
- public Optional<Measure> getRawRuleMeasure(Component component, Metric metric, int ruleId) {
- return Optional.ofNullable(rawMeasures.get(new InternalKey(component, metric)));
- }
-
@Override
public Set<Measure> getRawMeasures(Component component, Metric metric) {
return from(filterKeys(rawMeasures, hasComponentRef(component)).entrySet()).filter(new MatchMetric(metric)).transform(ToMeasure.INSTANCE).toSet();
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitorTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitorTest.java
new file mode 100644
index 00000000000..ee8e616336d
--- /dev/null
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/SecurityReviewRatingVisitorTest.java
@@ -0,0 +1,95 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.qualitymodel;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
+import org.sonar.ce.task.projectanalysis.component.VisitorsCrawler;
+import org.sonar.ce.task.projectanalysis.measure.Measure;
+import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
+import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
+import org.sonar.server.measure.Rating;
+
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.measures.CoreMetrics.NCLOC;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
+import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
+import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
+
+public class SecurityReviewRatingVisitorTest {
+
+ private static final int PROJECT_REF = 1;
+ private static final Component PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project").build();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+ @Rule
+ public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
+ .add(NCLOC)
+ .add(SECURITY_HOTSPOTS)
+ .add(SECURITY_REVIEW_RATING);
+
+ @Rule
+ public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+ private VisitorsCrawler underTest = new VisitorsCrawler(singletonList(new SecurityReviewRatingVisitor(measureRepository, metricRepository)));
+
+ @Test
+ public void compute_security_review_rating_on_project() {
+ treeRootHolder.setRoot(PROJECT);
+ measureRepository.addRawMeasure(PROJECT_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
+ measureRepository.addRawMeasure(PROJECT_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(12));
+
+ underTest.visit(PROJECT);
+
+ Measure measure = measureRepository.getAddedRawMeasure(PROJECT_REF, SECURITY_REVIEW_RATING_KEY).get();
+ assertThat(measure.getIntValue()).isEqualTo(Rating.C.getIndex());
+ assertThat(measure.getData()).isEqualTo(Rating.C.name());
+ }
+
+ @Test
+ public void compute_nothing_when_no_ncloc() {
+ treeRootHolder.setRoot(PROJECT);
+ measureRepository.addRawMeasure(PROJECT_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(2));
+
+ underTest.visit(PROJECT);
+
+ assertThat(measureRepository.getAddedRawMeasure(PROJECT_REF, SECURITY_REVIEW_RATING_KEY)).isEmpty();
+ }
+
+ @Test
+ public void compute_nothing_when_no_security_hotspot() {
+ treeRootHolder.setRoot(PROJECT);
+ measureRepository.addRawMeasure(PROJECT_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
+
+ underTest.visit(PROJECT);
+
+ assertThat(measureRepository.getAddedRawMeasure(PROJECT_REF, SECURITY_REVIEW_RATING_KEY)).isEmpty();
+ }
+}