You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NewReliabilityAndSecurityRatingMeasuresVisitor.java 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  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.
  10. *
  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.
  15. *
  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.
  19. */
  20. package org.sonar.ce.task.projectanalysis.qualitymodel;
  21. import com.google.common.collect.ImmutableMap;
  22. import java.util.Map;
  23. import org.sonar.api.ce.measure.Issue;
  24. import org.sonar.api.measures.CoreMetrics;
  25. import org.sonar.ce.task.projectanalysis.component.Component;
  26. import org.sonar.ce.task.projectanalysis.component.PathAwareVisitorAdapter;
  27. import org.sonar.ce.task.projectanalysis.formula.counter.RatingValue;
  28. import org.sonar.ce.task.projectanalysis.issue.ComponentIssuesRepository;
  29. import org.sonar.ce.task.projectanalysis.issue.NewIssueClassifier;
  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.core.issue.DefaultIssue;
  34. import org.sonar.server.measure.Rating;
  35. import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
  36. import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
  37. import static org.sonar.api.rule.Severity.BLOCKER;
  38. import static org.sonar.api.rule.Severity.CRITICAL;
  39. import static org.sonar.api.rule.Severity.INFO;
  40. import static org.sonar.api.rule.Severity.MAJOR;
  41. import static org.sonar.api.rule.Severity.MINOR;
  42. import static org.sonar.api.rules.RuleType.BUG;
  43. import static org.sonar.api.rules.RuleType.VULNERABILITY;
  44. import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
  45. import static org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit.LEAVES;
  46. import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
  47. import static org.sonar.server.measure.Rating.A;
  48. import static org.sonar.server.measure.Rating.B;
  49. import static org.sonar.server.measure.Rating.C;
  50. import static org.sonar.server.measure.Rating.D;
  51. import static org.sonar.server.measure.Rating.E;
  52. /**
  53. * Compute following measures :
  54. * {@link CoreMetrics#NEW_RELIABILITY_RATING_KEY}
  55. * {@link CoreMetrics#NEW_SECURITY_RATING_KEY}
  56. */
  57. public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
  58. private static final Map<String, Rating> RATING_BY_SEVERITY = ImmutableMap.of(
  59. BLOCKER, E,
  60. CRITICAL, D,
  61. MAJOR, C,
  62. MINOR, B,
  63. INFO, A);
  64. private final MeasureRepository measureRepository;
  65. private final ComponentIssuesRepository componentIssuesRepository;
  66. private final Map<String, Metric> metricsByKey;
  67. private final NewIssueClassifier newIssueClassifier;
  68. public NewReliabilityAndSecurityRatingMeasuresVisitor(MetricRepository metricRepository, MeasureRepository measureRepository,
  69. ComponentIssuesRepository componentIssuesRepository, NewIssueClassifier newIssueClassifier) {
  70. super(LEAVES, POST_ORDER, new CounterFactory(newIssueClassifier));
  71. this.measureRepository = measureRepository;
  72. this.componentIssuesRepository = componentIssuesRepository;
  73. // Output metrics
  74. this.metricsByKey = ImmutableMap.of(
  75. NEW_RELIABILITY_RATING_KEY, metricRepository.getByKey(NEW_RELIABILITY_RATING_KEY),
  76. NEW_SECURITY_RATING_KEY, metricRepository.getByKey(NEW_SECURITY_RATING_KEY));
  77. this.newIssueClassifier = newIssueClassifier;
  78. }
  79. @Override
  80. public void visitProject(Component project, Path<Counter> path) {
  81. computeAndSaveMeasures(project, path);
  82. }
  83. @Override
  84. public void visitDirectory(Component directory, Path<Counter> path) {
  85. computeAndSaveMeasures(directory, path);
  86. }
  87. @Override
  88. public void visitFile(Component file, Path<Counter> path) {
  89. computeAndSaveMeasures(file, path);
  90. }
  91. private void computeAndSaveMeasures(Component component, Path<Counter> path) {
  92. if (!newIssueClassifier.isEnabled()) {
  93. return;
  94. }
  95. initRatingsToA(path);
  96. processIssues(component, path);
  97. path.current().newRatingValueByMetric.entrySet()
  98. .stream()
  99. .filter(entry -> entry.getValue().isSet())
  100. .forEach(
  101. entry -> measureRepository.add(
  102. component,
  103. metricsByKey.get(entry.getKey()),
  104. newMeasureBuilder().create(entry.getValue().getValue().getIndex())));
  105. addToParent(path);
  106. }
  107. private static void initRatingsToA(Path<Counter> path) {
  108. path.current().newRatingValueByMetric.values().forEach(entry -> entry.increment(A));
  109. }
  110. private void processIssues(Component component, Path<Counter> path) {
  111. componentIssuesRepository.getIssues(component)
  112. .stream()
  113. .filter(issue -> issue.resolution() == null)
  114. .filter(issue -> issue.type().equals(BUG) || issue.type().equals(VULNERABILITY))
  115. .forEach(issue -> path.current().processIssue(issue));
  116. }
  117. private static void addToParent(Path<Counter> path) {
  118. if (!path.isRoot()) {
  119. path.parent().add(path.current());
  120. }
  121. }
  122. static class Counter {
  123. private final Map<String, RatingValue> newRatingValueByMetric = Map.of(
  124. NEW_RELIABILITY_RATING_KEY, new RatingValue(),
  125. NEW_SECURITY_RATING_KEY, new RatingValue());
  126. private final NewIssueClassifier newIssueClassifier;
  127. private final Component component;
  128. public Counter(NewIssueClassifier newIssueClassifier, Component component) {
  129. this.newIssueClassifier = newIssueClassifier;
  130. this.component = component;
  131. }
  132. void add(Counter otherCounter) {
  133. newRatingValueByMetric.forEach((metric, rating) -> rating.increment(otherCounter.newRatingValueByMetric.get(metric)));
  134. }
  135. void processIssue(Issue issue) {
  136. if (newIssueClassifier.isNew(component, (DefaultIssue) issue)) {
  137. Rating rating = RATING_BY_SEVERITY.get(issue.severity());
  138. if (issue.type().equals(BUG)) {
  139. newRatingValueByMetric.get(NEW_RELIABILITY_RATING_KEY).increment(rating);
  140. } else if (issue.type().equals(VULNERABILITY)) {
  141. newRatingValueByMetric.get(NEW_SECURITY_RATING_KEY).increment(rating);
  142. }
  143. }
  144. }
  145. }
  146. private static final class CounterFactory extends SimpleStackElementFactory<NewReliabilityAndSecurityRatingMeasuresVisitor.Counter> {
  147. private final NewIssueClassifier newIssueClassifier;
  148. private CounterFactory(NewIssueClassifier newIssueClassifier) {
  149. this.newIssueClassifier = newIssueClassifier;
  150. }
  151. @Override
  152. public Counter createForAny(Component component) {
  153. return new Counter(newIssueClassifier, component);
  154. }
  155. }
  156. }