Browse Source

SONAR-17816 Add isCaycCompliant flag to /api/qualitygates/project_status

tags/9.9.0.65466
Jeremy Davis 1 year ago
parent
commit
b9ccb2eb4f

+ 35
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java View File

@@ -23,19 +23,34 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.Nullable;
import org.sonar.api.measures.Metric;
import org.sonar.db.component.SnapshotDto;
import org.sonarqube.ws.Qualitygates.ProjectStatusResponse;
import org.sonarqube.ws.Qualitygates.ProjectStatusResponse.NewCodePeriod;
import org.sonarqube.ws.Qualitygates.ProjectStatusResponse.Period;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.stream.Collectors.toUnmodifiableMap;
import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING;
import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING;
import static org.sonar.api.utils.DateUtils.formatDateTime;

public class QualityGateDetailsFormatter {
public static final String METRIC_KEY = "metric";
private static final Map<String, Double> CAYC_REQUIREMENTS = Stream.of(
NEW_MAINTAINABILITY_RATING,
NEW_RELIABILITY_RATING,
NEW_SECURITY_HOTSPOTS_REVIEWED,
NEW_SECURITY_RATING
).collect(toUnmodifiableMap(Metric::getKey, Metric::getBestValue));
private final Optional<String> optionalMeasureData;
private final Optional<SnapshotDto> optionalSnapshot;
private final ProjectStatusResponse.ProjectStatus.Builder projectStatusBuilder;
@@ -58,11 +73,30 @@ public class QualityGateDetailsFormatter {

formatIgnoredConditions(json);
formatConditions(json.getAsJsonArray("conditions"));
formatCleanAsYouCodeCompliant(json.getAsJsonArray("conditions"));
formatPeriods();

return projectStatusBuilder.build();
}

private void formatCleanAsYouCodeCompliant(@Nullable JsonArray jsonConditions) {
if (jsonConditions == null) {
return;
}

long matchCount = jsonConditions.asList().stream()
.map(JsonElement::getAsJsonObject)
.filter(jsonObject -> CAYC_REQUIREMENTS.containsKey(jsonObject.get(METRIC_KEY).getAsString()))
.filter(jsonObject -> {
String metricKey = jsonObject.get(METRIC_KEY).getAsString();
Double value = jsonObject.get("error").getAsDouble();
return CAYC_REQUIREMENTS.get(metricKey).compareTo(value) == 0;
})
.count();

projectStatusBuilder.setIsCaycCompliant(matchCount == CAYC_REQUIREMENTS.size());
}

private void formatIgnoredConditions(JsonObject json) {
JsonElement ignoredConditions = json.get("ignoredConditions");
if (ignoredConditions != null) {
@@ -167,7 +201,7 @@ public class QualityGateDetailsFormatter {
}

private static void formatConditionMetric(ProjectStatusResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
JsonElement metric = jsonCondition.get("metric");
JsonElement metric = jsonCondition.get(METRIC_KEY);
if (metric != null && !isNullOrEmpty(metric.getAsString())) {
conditionBuilder.setMetricKey(metric.getAsString());
}

+ 26
- 0
server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest.java View File

@@ -21,9 +21,11 @@ package org.sonar.server.qualitygate.ws;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.text.StrSubstitutor;
import org.junit.Test;
import org.sonar.db.component.SnapshotDto;
import org.sonarqube.ws.Qualitygates.ProjectStatusResponse;
@@ -143,6 +145,30 @@ public class QualityGateDetailsFormatterTest {
.hasMessageContaining("Unknown quality gate comparator 'UNKNOWN'");
}

@Test
public void verify_cayc_quality_gate_checked() throws IOException {
String measureDataRaw = IOUtils.toString(getClass().getResource("QualityGateDetailsFormatterTest/cayc_compliant_qg.json"));

String measureDataCompliant = StrSubstitutor.replace(measureDataRaw, Map.of("nmr_error", "1.0"));
underTest = newQualityGateDetailsFormatter(measureDataCompliant, null);
ProjectStatus result = underTest.format();
assertThat(result.getIsCaycCompliant()).isTrue();

String measureDataNonCompliant = StrSubstitutor.replace(measureDataRaw, Map.of("nmr_error", "2.0"));
underTest = newQualityGateDetailsFormatter(measureDataNonCompliant, null);
result = underTest.format();
assertThat(result.getIsCaycCompliant()).isFalse();
}

@Test
public void verify_cayc_quality_gate_with_missing_metric() throws IOException {
String measureData = IOUtils.toString(getClass().getResource("QualityGateDetailsFormatterTest/cayc_missing_metric.json"));

underTest = newQualityGateDetailsFormatter(measureData, null);
ProjectStatus result = underTest.format();
assertThat(result.getIsCaycCompliant()).isFalse();
}

private static QualityGateDetailsFormatter newQualityGateDetailsFormatter(@Nullable String measureData, @Nullable SnapshotDto snapshotDto) {
return new QualityGateDetailsFormatter(Optional.ofNullable(measureData), Optional.ofNullable(snapshotDto));
}

+ 41
- 0
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest/cayc_compliant_qg.json View File

@@ -0,0 +1,41 @@
{
"level": "ERROR",
"conditions": [
{
"metric": "new_maintainability_rating",
"op": "LT",
"period": 1,
"warning": "",
"error": "${nmr_error}",
"actual": "2",
"level": "ERROR"
},
{
"metric": "new_reliability_rating",
"op": "LT",
"period": 1,
"warning": "",
"error": "1.0",
"actual": "1",
"level": "OK"
},
{
"metric": "new_security_hotspots_reviewed",
"op": "GT",
"period": 1,
"warning": "",
"error": "100.0",
"actual": "100.0",
"level": "OK"
},
{
"metric": "new_security_rating",
"op": "LT",
"period": 1,
"warning": "",
"error": "1.0",
"actual": "2",
"level": "ERROR"
}
]
}

+ 32
- 0
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest/cayc_missing_metric.json View File

@@ -0,0 +1,32 @@
{
"level": "ERROR",
"conditions": [
{
"metric": "new_reliability_rating",
"op": "LT",
"period": 1,
"warning": "",
"error": "1.0",
"actual": "1",
"level": "OK"
},
{
"metric": "new_security_hotspots_reviewed",
"op": "GT",
"period": 1,
"warning": "",
"error": "100.0",
"actual": "100.0",
"level": "OK"
},
{
"metric": "new_security_rating",
"op": "LT",
"period": 1,
"warning": "",
"error": "1.0",
"actual": "2",
"level": "ERROR"
}
]
}

+ 1
- 0
sonar-ws/src/main/protobuf/ws-qualitygates.proto View File

@@ -36,6 +36,7 @@ message ProjectStatusResponse {
repeated Period periods = 3;
optional bool ignoredConditions = 4;
optional NewCodePeriod period = 5;
optional bool isCaycCompliant = 6;
}

message Condition {

Loading…
Cancel
Save