3 * Copyright (C) 2009-2021 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.server.measure.live;
22 import java.util.Collection;
23 import java.util.HashSet;
25 import java.util.Optional;
26 import java.util.OptionalDouble;
28 import java.util.stream.Stream;
29 import org.sonar.api.measures.CoreMetrics;
30 import org.sonar.api.measures.Metric;
31 import org.sonar.db.DbClient;
32 import org.sonar.db.DbSession;
33 import org.sonar.db.component.BranchDto;
34 import org.sonar.db.component.BranchType;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.measure.LiveMeasureDto;
37 import org.sonar.db.metric.MetricDto;
38 import org.sonar.db.project.ProjectDto;
39 import org.sonar.db.qualitygate.QualityGateConditionDto;
40 import org.sonar.db.qualitygate.QualityGateDto;
41 import org.sonar.server.qualitygate.Condition;
42 import org.sonar.server.qualitygate.EvaluatedQualityGate;
43 import org.sonar.server.qualitygate.QualityGate;
44 import org.sonar.server.qualitygate.QualityGateConverter;
45 import org.sonar.server.qualitygate.QualityGateEvaluator;
46 import org.sonar.server.qualitygate.QualityGateFinder;
48 import static org.sonar.core.util.stream.MoreCollectors.toHashSet;
49 import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
51 public class LiveQualityGateComputerImpl implements LiveQualityGateComputer {
53 private final DbClient dbClient;
54 private final QualityGateFinder qGateFinder;
55 private final QualityGateEvaluator evaluator;
57 public LiveQualityGateComputerImpl(DbClient dbClient, QualityGateFinder qGateFinder, QualityGateEvaluator evaluator) {
58 this.dbClient = dbClient;
59 this.qGateFinder = qGateFinder;
60 this.evaluator = evaluator;
64 public QualityGate loadQualityGate(DbSession dbSession, ProjectDto project, BranchDto branch) {
65 QualityGateDto gateDto = qGateFinder.getQualityGate(dbSession, project)
67 Collection<QualityGateConditionDto> conditionDtos = dbClient.gateConditionDao().selectForQualityGate(dbSession, gateDto.getUuid());
68 Set<String> metricUuids = conditionDtos.stream().map(QualityGateConditionDto::getMetricUuid)
69 .collect(toHashSet(conditionDtos.size()));
70 Map<String, MetricDto> metricsByUuid = dbClient.metricDao().selectByUuids(dbSession, metricUuids).stream()
71 .collect(uniqueIndex(MetricDto::getUuid));
73 Stream<Condition> conditions = conditionDtos.stream().map(conditionDto -> {
74 String metricKey = metricsByUuid.get(conditionDto.getMetricUuid()).getKey();
75 Condition.Operator operator = Condition.Operator.fromDbValue(conditionDto.getOperator());
76 return new Condition(metricKey, operator, conditionDto.getErrorThreshold());
79 if (branch.getBranchType() == BranchType.PULL_REQUEST) {
80 conditions = conditions.filter(Condition::isOnLeakPeriod);
83 return new QualityGate(String.valueOf(gateDto.getUuid()), gateDto.getName(), conditions.collect(toHashSet(conditionDtos.size())));
87 public EvaluatedQualityGate refreshGateStatus(ComponentDto project, QualityGate gate, MeasureMatrix measureMatrix) {
88 QualityGateEvaluator.Measures measures = metricKey -> {
89 Optional<LiveMeasureDto> liveMeasureDto = measureMatrix.getMeasure(project, metricKey);
90 if (!liveMeasureDto.isPresent()) {
91 return Optional.empty();
93 MetricDto metric = measureMatrix.getMetricByUuid(liveMeasureDto.get().getMetricUuid());
94 return Optional.of(new LiveMeasure(liveMeasureDto.get(), metric));
97 EvaluatedQualityGate evaluatedGate = evaluator.evaluate(gate, measures);
99 measureMatrix.setValue(project, CoreMetrics.ALERT_STATUS_KEY, evaluatedGate.getStatus().name());
100 measureMatrix.setValue(project, CoreMetrics.QUALITY_GATE_DETAILS_KEY, QualityGateConverter.toJson(evaluatedGate));
102 return evaluatedGate;
106 public Set<String> getMetricsRelatedTo(QualityGate gate) {
107 Set<String> metricKeys = new HashSet<>();
108 metricKeys.add(CoreMetrics.ALERT_STATUS_KEY);
109 metricKeys.add(CoreMetrics.QUALITY_GATE_DETAILS_KEY);
110 metricKeys.addAll(evaluator.getMetricKeys(gate));
114 private static class LiveMeasure implements QualityGateEvaluator.Measure {
115 private final LiveMeasureDto dto;
116 private final MetricDto metric;
118 LiveMeasure(LiveMeasureDto dto, MetricDto metric) {
120 this.metric = metric;
124 public Metric.ValueType getType() {
125 return Metric.ValueType.valueOf(metric.getValueType());
129 public OptionalDouble getValue() {
130 if (dto.getValue() == null) {
131 return OptionalDouble.empty();
133 return OptionalDouble.of(dto.getValue());
137 public Optional<String> getStringValue() {
138 return Optional.ofNullable(dto.getTextValue());
142 public OptionalDouble getNewMetricValue() {
143 if (dto.getVariation() == null) {
144 return OptionalDouble.empty();
146 return OptionalDouble.of(dto.getVariation());