3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.ce.task.projectanalysis.qualitymodel;
22 import com.google.common.collect.ImmutableMap;
24 import org.sonar.api.ce.measure.Issue;
25 import org.sonar.api.measures.CoreMetrics;
26 import org.sonar.ce.task.projectanalysis.component.Component;
27 import org.sonar.ce.task.projectanalysis.component.PathAwareVisitorAdapter;
28 import org.sonar.ce.task.projectanalysis.formula.counter.RatingValue;
29 import org.sonar.ce.task.projectanalysis.issue.ComponentIssuesRepository;
30 import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
31 import org.sonar.ce.task.projectanalysis.metric.Metric;
32 import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
33 import org.sonar.ce.task.projectanalysis.period.Period;
34 import org.sonar.ce.task.projectanalysis.period.PeriodHolder;
35 import org.sonar.core.issue.DefaultIssue;
36 import org.sonar.server.measure.Rating;
38 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
39 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
40 import static org.sonar.api.rule.Severity.BLOCKER;
41 import static org.sonar.api.rule.Severity.CRITICAL;
42 import static org.sonar.api.rule.Severity.INFO;
43 import static org.sonar.api.rule.Severity.MAJOR;
44 import static org.sonar.api.rule.Severity.MINOR;
45 import static org.sonar.api.rules.RuleType.BUG;
46 import static org.sonar.api.rules.RuleType.VULNERABILITY;
47 import static org.sonar.api.utils.DateUtils.truncateToSeconds;
48 import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
49 import static org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit.LEAVES;
50 import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
51 import static org.sonar.server.measure.Rating.A;
52 import static org.sonar.server.measure.Rating.B;
53 import static org.sonar.server.measure.Rating.C;
54 import static org.sonar.server.measure.Rating.D;
55 import static org.sonar.server.measure.Rating.E;
58 * Compute following measures :
59 * {@link CoreMetrics#NEW_RELIABILITY_RATING_KEY}
60 * {@link CoreMetrics#NEW_SECURITY_RATING_KEY}
62 public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
64 private static final Map<String, Rating> RATING_BY_SEVERITY = ImmutableMap.of(
71 private final MeasureRepository measureRepository;
72 private final ComponentIssuesRepository componentIssuesRepository;
73 private final PeriodHolder periodHolder;
75 private final Map<String, Metric> metricsByKey;
77 public NewReliabilityAndSecurityRatingMeasuresVisitor(MetricRepository metricRepository, MeasureRepository measureRepository, ComponentIssuesRepository componentIssuesRepository,
78 PeriodHolder periodHolder) {
79 super(LEAVES, POST_ORDER, CounterFactory.INSTANCE);
80 this.measureRepository = measureRepository;
81 this.componentIssuesRepository = componentIssuesRepository;
82 this.periodHolder = periodHolder;
85 this.metricsByKey = ImmutableMap.of(
86 NEW_RELIABILITY_RATING_KEY, metricRepository.getByKey(NEW_RELIABILITY_RATING_KEY),
87 NEW_SECURITY_RATING_KEY, metricRepository.getByKey(NEW_SECURITY_RATING_KEY));
91 public void visitProject(Component project, Path<Counter> path) {
92 computeAndSaveMeasures(project, path);
96 public void visitDirectory(Component directory, Path<Counter> path) {
97 computeAndSaveMeasures(directory, path);
101 public void visitFile(Component file, Path<Counter> path) {
102 computeAndSaveMeasures(file, path);
105 private void computeAndSaveMeasures(Component component, Path<Counter> path) {
106 if (!periodHolder.hasPeriod()) {
109 initRatingsToA(path);
110 processIssues(component, path);
111 path.current().newRatingValueByMetric.entrySet()
113 .filter(entry -> entry.getValue().isSet())
115 entry -> measureRepository.add(
117 metricsByKey.get(entry.getKey()),
118 newMeasureBuilder().setVariation(entry.getValue().getValue().getIndex()).createNoValue()));
122 private static void initRatingsToA(Path<Counter> path) {
123 path.current().newRatingValueByMetric.values().forEach(entry -> entry.increment(A));
126 private void processIssues(Component component, Path<Counter> path) {
127 componentIssuesRepository.getIssues(component)
129 .filter(issue -> issue.resolution() == null)
130 .filter(issue -> issue.type().equals(BUG) || issue.type().equals(VULNERABILITY))
131 .forEach(issue -> path.current().processIssue(issue, periodHolder.getPeriod()));
134 private static void addToParent(Path<Counter> path) {
135 if (!path.isRoot()) {
136 path.parent().add(path.current());
140 static final class Counter {
141 private Map<String, RatingValue> newRatingValueByMetric = ImmutableMap.of(
142 NEW_RELIABILITY_RATING_KEY, new RatingValue(),
143 NEW_SECURITY_RATING_KEY, new RatingValue());
146 // prevents instantiation
149 void add(Counter otherCounter) {
150 newRatingValueByMetric.entrySet().forEach(e -> e.getValue().increment(otherCounter.newRatingValueByMetric.get(e.getKey())));
153 void processIssue(Issue issue, Period period) {
154 if (isOnPeriod((DefaultIssue) issue, period)) {
155 Rating rating = RATING_BY_SEVERITY.get(issue.severity());
156 if (issue.type().equals(BUG)) {
157 newRatingValueByMetric.get(NEW_RELIABILITY_RATING_KEY).increment(rating);
158 } else if (issue.type().equals(VULNERABILITY)) {
159 newRatingValueByMetric.get(NEW_SECURITY_RATING_KEY).increment(rating);
164 private static boolean isOnPeriod(DefaultIssue issue, Period period) {
165 // Add one second to not take into account issues created during current analysis
166 return issue.creationDate().getTime() > truncateToSeconds(period.getSnapshotDate());
170 private static final class CounterFactory extends SimpleStackElementFactory<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
171 public static final CounterFactory INSTANCE = new CounterFactory();
173 private CounterFactory() {
174 // prevents instantiation
178 public Counter createForAny(Component component) {
179 return new Counter();