]> source.dussan.org Git - sonarqube.git/blob
d95dd78c98c089ab402acc0ee5564921f8e09e54
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 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.server.qualitygate.ws;
21
22 import com.google.gson.JsonArray;
23 import com.google.gson.JsonElement;
24 import com.google.gson.JsonObject;
25 import com.google.gson.JsonParser;
26 import java.util.Optional;
27 import java.util.function.Predicate;
28 import java.util.stream.StreamSupport;
29 import javax.annotation.Nullable;
30 import org.sonar.db.component.SnapshotDto;
31 import org.sonarqube.ws.Qualitygates.ProjectStatusResponse;
32 import org.sonarqube.ws.Qualitygates.ProjectStatusResponse.NewCodePeriod;
33 import org.sonarqube.ws.Qualitygates.ProjectStatusResponse.Period;
34
35 import static com.google.common.base.Strings.isNullOrEmpty;
36 import static org.sonar.api.utils.DateUtils.formatDateTime;
37
38 public class QualityGateDetailsFormatter {
39   private final Optional<String> optionalMeasureData;
40   private final Optional<SnapshotDto> optionalSnapshot;
41   private final ProjectStatusResponse.ProjectStatus.Builder projectStatusBuilder;
42
43   public QualityGateDetailsFormatter(Optional<String> measureData, Optional<SnapshotDto> snapshot) {
44     this.optionalMeasureData = measureData;
45     this.optionalSnapshot = snapshot;
46     this.projectStatusBuilder = ProjectStatusResponse.ProjectStatus.newBuilder();
47   }
48
49   public ProjectStatusResponse.ProjectStatus format() {
50     if (!optionalMeasureData.isPresent()) {
51       return newResponseWithoutQualityGateDetails();
52     }
53
54     JsonObject json = JsonParser.parseString(optionalMeasureData.get()).getAsJsonObject();
55
56     ProjectStatusResponse.Status qualityGateStatus = measureLevelToQualityGateStatus(json.get("level").getAsString());
57     projectStatusBuilder.setStatus(qualityGateStatus);
58
59     formatIgnoredConditions(json);
60     formatConditions(json.getAsJsonArray("conditions"));
61     formatPeriods();
62
63     return projectStatusBuilder.build();
64   }
65
66   private void formatIgnoredConditions(JsonObject json) {
67     JsonElement ignoredConditions = json.get("ignoredConditions");
68     if (ignoredConditions != null) {
69       projectStatusBuilder.setIgnoredConditions(ignoredConditions.getAsBoolean());
70     } else {
71       projectStatusBuilder.setIgnoredConditions(false);
72     }
73   }
74
75   private void formatPeriods() {
76     if (!optionalSnapshot.isPresent()) {
77       return;
78     }
79
80     Period.Builder periodsBuilder = Period.newBuilder();
81     NewCodePeriod.Builder periodBuilder = NewCodePeriod.newBuilder();
82
83     SnapshotDto snapshot = this.optionalSnapshot.get();
84
85     if (isNullOrEmpty(snapshot.getPeriodMode())) {
86       return;
87     }
88     periodsBuilder.setIndex(1);
89     periodsBuilder.setMode(snapshot.getPeriodMode());
90     periodBuilder.setMode(snapshot.getPeriodMode());
91     Long periodDate = snapshot.getPeriodDate();
92     if (periodDate != null) {
93       String formattedDateTime = formatDateTime(periodDate);
94       periodsBuilder.setDate(formattedDateTime);
95       periodBuilder.setDate(formattedDateTime);
96     }
97     String periodModeParameter = snapshot.getPeriodModeParameter();
98     if (!isNullOrEmpty(periodModeParameter)) {
99       periodsBuilder.setParameter(periodModeParameter);
100       periodBuilder.setParameter(periodModeParameter);
101     }
102     projectStatusBuilder.addPeriods(periodsBuilder);
103     projectStatusBuilder.setPeriod(periodBuilder);
104   }
105
106   private void formatConditions(@Nullable JsonArray jsonConditions) {
107     if (jsonConditions == null) {
108       return;
109     }
110
111     StreamSupport.stream(jsonConditions.spliterator(), false)
112       .map(JsonElement::getAsJsonObject)
113       .filter(isConditionOnValidPeriod())
114       .forEach(this::formatCondition);
115   }
116
117   private void formatCondition(JsonObject jsonCondition) {
118     ProjectStatusResponse.Condition.Builder conditionBuilder = ProjectStatusResponse.Condition.newBuilder();
119
120     formatConditionLevel(conditionBuilder, jsonCondition);
121     formatConditionMetric(conditionBuilder, jsonCondition);
122     formatConditionOperation(conditionBuilder, jsonCondition);
123     formatConditionPeriod(conditionBuilder, jsonCondition);
124     formatConditionWarningThreshold(conditionBuilder, jsonCondition);
125     formatConditionErrorThreshold(conditionBuilder, jsonCondition);
126     formatConditionActual(conditionBuilder, jsonCondition);
127
128     projectStatusBuilder.addConditions(conditionBuilder);
129   }
130
131   private static void formatConditionActual(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
132     JsonElement actual = jsonCondition.get("actual");
133     if (actual != null && !isNullOrEmpty(actual.getAsString())) {
134       conditionBuilder.setActualValue(actual.getAsString());
135     }
136   }
137
138   private static void formatConditionErrorThreshold(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
139     JsonElement error = jsonCondition.get("error");
140     if (error != null && !isNullOrEmpty(error.getAsString())) {
141       conditionBuilder.setErrorThreshold(error.getAsString());
142     }
143   }
144
145   private static void formatConditionWarningThreshold(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
146     JsonElement warning = jsonCondition.get("warning");
147     if (warning != null && !isNullOrEmpty(warning.getAsString())) {
148       conditionBuilder.setWarningThreshold(warning.getAsString());
149     }
150   }
151
152   private static void formatConditionPeriod(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
153     JsonElement periodIndex = jsonCondition.get("period");
154     if (periodIndex == null) {
155       return;
156     }
157     conditionBuilder.setPeriodIndex(periodIndex.getAsInt());
158   }
159
160   private static void formatConditionOperation(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
161     JsonElement op = jsonCondition.get("op");
162     if (op != null && !isNullOrEmpty(op.getAsString())) {
163       String stringOp = op.getAsString();
164       ProjectStatusResponse.Comparator comparator = measureOpToQualityGateComparator(stringOp);
165       conditionBuilder.setComparator(comparator);
166     }
167   }
168
169   private static void formatConditionMetric(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
170     JsonElement metric = jsonCondition.get("metric");
171     if (metric != null && !isNullOrEmpty(metric.getAsString())) {
172       conditionBuilder.setMetricKey(metric.getAsString());
173     }
174   }
175
176   private static void formatConditionLevel(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
177     JsonElement measureLevel = jsonCondition.get("level");
178     if (measureLevel != null && !isNullOrEmpty(measureLevel.getAsString())) {
179       conditionBuilder.setStatus(measureLevelToQualityGateStatus(measureLevel.getAsString()));
180     }
181   }
182
183   private static ProjectStatusResponse.Status measureLevelToQualityGateStatus(String measureLevel) {
184     for (ProjectStatusResponse.Status status : ProjectStatusResponse.Status.values()) {
185       if (status.name().equals(measureLevel)) {
186         return status;
187       }
188     }
189
190     throw new IllegalStateException(String.format("Unknown quality gate status '%s'", measureLevel));
191   }
192
193   private static ProjectStatusResponse.Comparator measureOpToQualityGateComparator(String measureOp) {
194     for (ProjectStatusResponse.Comparator comparator : ProjectStatusResponse.Comparator.values()) {
195       if (comparator.name().equals(measureOp)) {
196         return comparator;
197       }
198     }
199
200     throw new IllegalStateException(String.format("Unknown quality gate comparator '%s'", measureOp));
201   }
202
203   private static ProjectStatusResponse.ProjectStatus newResponseWithoutQualityGateDetails() {
204     return ProjectStatusResponse.ProjectStatus.newBuilder().setStatus(ProjectStatusResponse.Status.NONE).build();
205   }
206
207   private static Predicate<JsonObject> isConditionOnValidPeriod() {
208     return jsonCondition -> {
209       JsonElement periodIndex = jsonCondition.get("period");
210       if (periodIndex == null) {
211         return true;
212       }
213       int period = periodIndex.getAsInt();
214       // Ignore period that was set on non leak period (for retro compatibility with project that hasn't been analyzed since a while)
215       return period == 1;
216     };
217   }
218 }