aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>2017-10-04 09:42:38 +0200
committerDaniel Schwarz <bartfastiel@users.noreply.github.com>2017-10-07 09:06:25 +0200
commit454f14e4688f677877ce61bb0c9c5256638375a9 (patch)
tree652622b3302461388c93511de46e2c2db9e67b34
parent6dbe83f15f431bc1f5a609040767ef7e0a4ba79c (diff)
downloadsonarqube-454f14e4688f677877ce61bb0c9c5256638375a9.tar.gz
sonarqube-454f14e4688f677877ce61bb0c9c5256638375a9.zip
SONAR-9352 add "ignoredConditions" to response example of api/qualitygates/project_status
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStep.java22
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCase.java28
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java10
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json1
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java18
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStepTest.java8
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java42
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java12
-rw-r--r--sonar-ws/src/main/protobuf/ws-qualitygates.proto1
-rw-r--r--tests/projects/qualitygate/small-changesets/v2-1020-lines/src/sample/Sample.xoo.scm2
-rw-r--r--tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateForSmallChangesetsTest.java81
13 files changed, 191 insertions, 46 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java
index 4c4af01b977..e157d5aa650 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java
@@ -32,13 +32,16 @@ import static java.util.Objects.requireNonNull;
@Immutable
public class QualityGateDetailsData {
private static final String FIELD_LEVEL = "level";
+ private static final String FIELD_IGNORED_CONDITIONS = "ignoredConditions";
private final Measure.Level level;
private final List<EvaluatedCondition> conditions;
+ private final boolean ignoredConditions;
- public QualityGateDetailsData(Measure.Level level, Iterable<EvaluatedCondition> conditions) {
+ public QualityGateDetailsData(Measure.Level level, Iterable<EvaluatedCondition> conditions, boolean ignoredConditions) {
this.level = requireNonNull(level);
this.conditions = from(conditions).toList();
+ this.ignoredConditions = ignoredConditions;
}
public String toJson() {
@@ -49,6 +52,7 @@ public class QualityGateDetailsData {
conditionResults.add(toJson(condition));
}
details.add("conditions", conditionResults);
+ details.addProperty(FIELD_IGNORED_CONDITIONS, ignoredConditions);
return details.toString();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStep.java
index 22a0b04aa2f..8bfffcac931 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStep.java
@@ -174,6 +174,7 @@ public class QualityGateMeasuresStep implements ComputationStep {
private void updateMeasures(Component project, Set<Condition> conditions, QualityGateDetailsDataBuilder builder) {
Multimap<Metric, Condition> conditionsPerMetric = conditions.stream().collect(MoreCollectors.index(Condition::getMetric, java.util.function.Function.identity()));
+ boolean ignoredConditions = false;
for (Map.Entry<Metric, Collection<Condition>> entry : conditionsPerMetric.asMap().entrySet()) {
Metric metric = entry.getKey();
Optional<Measure> measure = measureRepository.getRawMeasure(project, metric);
@@ -182,7 +183,13 @@ public class QualityGateMeasuresStep implements ComputationStep {
}
final MetricEvaluationResult metricEvaluationResult = evaluateQualityGate(measure.get(), entry.getValue());
- final MetricEvaluationResult finalMetricEvaluationResult = smallChangesetQualityGateSpecialCase.applyIfNeeded(project, metricEvaluationResult);
+ final MetricEvaluationResult finalMetricEvaluationResult;
+ if (smallChangesetQualityGateSpecialCase.appliesTo(project, metricEvaluationResult)) {
+ finalMetricEvaluationResult = smallChangesetQualityGateSpecialCase.apply(metricEvaluationResult);
+ ignoredConditions = true;
+ } else {
+ finalMetricEvaluationResult = metricEvaluationResult;
+ }
String text = evaluationResultTextConverter.asText(finalMetricEvaluationResult.condition, finalMetricEvaluationResult.evaluationResult);
builder.addLabel(text);
@@ -193,6 +200,7 @@ public class QualityGateMeasuresStep implements ComputationStep {
builder.addEvaluatedCondition(finalMetricEvaluationResult);
}
+ builder.setIgnoredConditions(ignoredConditions);
}
private static MetricEvaluationResult evaluateQualityGate(Measure measure, Collection<Condition> conditions) {
@@ -214,7 +222,7 @@ public class QualityGateMeasuresStep implements ComputationStep {
Metric metric = metricRepository.getByKey(CoreMetrics.ALERT_STATUS_KEY);
measureRepository.add(project, metric, globalMeasure);
- String detailMeasureValue = new QualityGateDetailsData(builder.getGlobalLevel(), builder.getEvaluatedConditions()).toJson();
+ String detailMeasureValue = new QualityGateDetailsData(builder.getGlobalLevel(), builder.getEvaluatedConditions(), builder.isIgnoredConditions()).toJson();
Measure detailsMeasure = Measure.newMeasureBuilder().create(detailMeasureValue);
Metric qgDetailsMetric = metricRepository.getByKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY);
measureRepository.add(project, qgDetailsMetric, detailsMeasure);
@@ -229,6 +237,7 @@ public class QualityGateMeasuresStep implements ComputationStep {
private Measure.Level globalLevel = Measure.Level.OK;
private List<String> labels = new ArrayList<>();
private List<EvaluatedCondition> evaluatedConditions = new ArrayList<>();
+ private boolean ignoredConditions;
public Measure.Level getGlobalLevel() {
return globalLevel;
@@ -259,6 +268,15 @@ public class QualityGateMeasuresStep implements ComputationStep {
public List<EvaluatedCondition> getEvaluatedConditions() {
return evaluatedConditions;
}
+
+ public boolean isIgnoredConditions() {
+ return ignoredConditions;
+ }
+
+ public QualityGateDetailsDataBuilder setIgnoredConditions(boolean ignoredConditions) {
+ this.ignoredConditions = ignoredConditions;
+ return this;
+ }
}
private enum EvaluatedConditionToCondition implements Function<EvaluatedCondition, Condition> {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCase.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCase.java
index 6f4a1224cd8..fc0a3af4851 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCase.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCase.java
@@ -27,15 +27,16 @@ import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository;
import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository;
import org.sonar.server.computation.task.projectanalysis.qualitygate.EvaluationResult;
+import org.sonar.server.computation.task.projectanalysis.step.QualityGateMeasuresStep.MetricEvaluationResult;
import static java.util.Arrays.asList;
public class SmallChangesetQualityGateSpecialCase {
/**
- * Some metrics will only produce warnings (never errors) on very small change sets.
+ * Some metrics will be ignored on very small change sets.
*/
- private static final Collection<String> METRICS_THAT_CAN_ONLY_PRODUCE_WARNINGS_ON_SMALL_CHANGESETS = asList(
+ private static final Collection<String> METRICS_TO_IGNORE_ON_SMALL_CHANGESETS = asList(
CoreMetrics.NEW_COVERAGE_KEY,
CoreMetrics.NEW_LINE_COVERAGE_KEY,
CoreMetrics.NEW_BRANCH_COVERAGE_KEY,
@@ -53,24 +54,15 @@ public class SmallChangesetQualityGateSpecialCase {
this.metricRepository = metricRepository;
}
- QualityGateMeasuresStep.MetricEvaluationResult applyIfNeeded(Component project, @Nullable QualityGateMeasuresStep.MetricEvaluationResult metricEvaluationResult) {
- if (metricEvaluationResult == null) {
- return metricEvaluationResult;
- }
- if (metricEvaluationResult.evaluationResult.getLevel() == Measure.Level.OK) {
- return metricEvaluationResult;
- }
- if (!METRICS_THAT_CAN_ONLY_PRODUCE_WARNINGS_ON_SMALL_CHANGESETS.contains(metricEvaluationResult.condition.getMetric().getKey())) {
- return metricEvaluationResult;
- }
- if (!isSmallChangeset(project)) {
- return metricEvaluationResult;
- }
- return calculateModifiedResult(metricEvaluationResult);
+ public boolean appliesTo(Component project, @Nullable MetricEvaluationResult metricEvaluationResult) {
+ return metricEvaluationResult != null
+ && metricEvaluationResult.evaluationResult.getLevel() != Measure.Level.OK
+ && METRICS_TO_IGNORE_ON_SMALL_CHANGESETS.contains(metricEvaluationResult.condition.getMetric().getKey())
+ && isSmallChangeset(project);
}
- private QualityGateMeasuresStep.MetricEvaluationResult calculateModifiedResult(@Nullable QualityGateMeasuresStep.MetricEvaluationResult metricEvaluationResult) {
- return new QualityGateMeasuresStep.MetricEvaluationResult(
+ MetricEvaluationResult apply(MetricEvaluationResult metricEvaluationResult) {
+ return new MetricEvaluationResult(
new EvaluationResult(Measure.Level.OK, metricEvaluationResult.evaluationResult.getValue()), metricEvaluationResult.condition);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
index d61184b3d9a..37b98e830a6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
@@ -87,7 +88,10 @@ public class ProjectStatusAction implements QualityGatesWsAction {
"</ul>", QG_STATUSES_ONE_LINE, ProjectStatusWsResponse.Status.NONE))
.setResponseExample(getClass().getResource("project_status-example.json"))
.setSince("5.3")
- .setHandler(this);
+ .setHandler(this)
+ .setChangelog(
+ new Change("6.4", "The field 'ignoredConditions' is added to the response")
+ );
action.createParam(PARAM_ANALYSIS_ID)
.setDescription("Analysis id")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
index b45804f50e7..6c6a9508142 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
@@ -55,12 +55,22 @@ public class QualityGateDetailsFormatter {
ProjectStatusWsResponse.Status qualityGateStatus = measureLevelToQualityGateStatus(json.get("level").getAsString());
projectStatusBuilder.setStatus(qualityGateStatus);
+ formatIgnoredConditions(json);
formatConditions(json.getAsJsonArray("conditions"));
formatPeriods();
return projectStatusBuilder.build();
}
+ private void formatIgnoredConditions(JsonObject json) {
+ JsonElement ignoredConditions = json.get("ignoredConditions");
+ if (ignoredConditions != null) {
+ projectStatusBuilder.setIgnoredConditions(ignoredConditions.getAsBoolean());
+ } else {
+ projectStatusBuilder.setIgnoredConditions(false);
+ }
+ }
+
private void formatPeriods() {
if (!optionalSnapshot.isPresent()) {
return;
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json
index 31308d8f45c..946f9c4fdb3 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json
@@ -1,6 +1,7 @@
{
"projectStatus": {
"status": "ERROR",
+ "ignoredConditions": false,
"conditions": [
{
"status": "ERROR",
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java
index 46a97eb845e..ac2730c9d48 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java
@@ -31,17 +31,17 @@ import org.sonar.test.JsonAssert;
public class QualityGateDetailsDataTest {
@Test(expected = NullPointerException.class)
public void constructor_throws_NPE_if_Level_arg_is_null() {
- new QualityGateDetailsData(null, Collections.<EvaluatedCondition>emptyList());
+ new QualityGateDetailsData(null, Collections.<EvaluatedCondition>emptyList(), false);
}
@Test(expected = NullPointerException.class)
public void constructor_throws_NPE_if_Iterable_arg_is_null() {
- new QualityGateDetailsData(Measure.Level.OK, null);
+ new QualityGateDetailsData(Measure.Level.OK, null, false);
}
@Test
public void verify_json_when_there_is_no_condition() {
- String actualJson = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList()).toJson();
+ String actualJson = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList(), false).toJson();
JsonAssert.assertJson(actualJson).isSimilarTo("{" +
"\"level\":\"OK\"," +
@@ -57,7 +57,7 @@ public class QualityGateDetailsDataTest {
new EvaluatedCondition(condition, Measure.Level.OK, value),
new EvaluatedCondition(condition, Measure.Level.WARN, value),
new EvaluatedCondition(condition, Measure.Level.ERROR, value));
- String actualJson = new QualityGateDetailsData(Measure.Level.OK, evaluatedConditions).toJson();
+ String actualJson = new QualityGateDetailsData(Measure.Level.OK, evaluatedConditions, false).toJson();
JsonAssert.assertJson(actualJson).isSimilarTo("{" +
"\"level\":\"OK\"," +
@@ -92,4 +92,14 @@ public class QualityGateDetailsDataTest {
"]" +
"}");
}
+
+ @Test
+ public void verify_json_for_small_leak() {
+ String actualJson = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList(), false).toJson();
+ JsonAssert.assertJson(actualJson).isSimilarTo("{\"ignoredConditions\": false}");
+
+ String actualJson2 = new QualityGateDetailsData(Measure.Level.OK, Collections.<EvaluatedCondition>emptyList(), true).toJson();
+ JsonAssert.assertJson(actualJson2).isSimilarTo("{\"ignoredConditions\": true}");
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStepTest.java
index 1b6860e5d1f..92fdda5700e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateMeasuresStepTest.java
@@ -161,7 +161,7 @@ public class QualityGateMeasuresStepTest {
.hasQualityGateLevel(OK)
.hasQualityGateText("");
assertThat(getQGDetailsMeasure())
- .hasValue(new QualityGateDetailsData(OK, Collections.<EvaluatedCondition>emptyList()).toJson());
+ .hasValue(new QualityGateDetailsData(OK, Collections.<EvaluatedCondition>emptyList(), false).toJson());
QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.OK)
@@ -189,7 +189,7 @@ public class QualityGateMeasuresStepTest {
.hasQualityGateLevel(OK)
.hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
assertThat(getQGDetailsMeasure().get())
- .hasValue(new QualityGateDetailsData(OK, of(new EvaluatedCondition(equals2Condition, OK, rawValue))).toJson());
+ .hasValue(new QualityGateDetailsData(OK, of(new EvaluatedCondition(equals2Condition, OK, rawValue)), false).toJson());
QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.OK)
@@ -226,7 +226,7 @@ public class QualityGateMeasuresStepTest {
assertThat(getQGDetailsMeasure())
.hasValue(new QualityGateDetailsData(ERROR, of(
new EvaluatedCondition(equals1ErrorCondition, ERROR, rawValue),
- new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());
+ new EvaluatedCondition(equals1WarningCondition, WARN, rawValue)), false).toJson());
QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.ERROR)
@@ -264,7 +264,7 @@ public class QualityGateMeasuresStepTest {
assertThat(getQGDetailsMeasure())
.hasValue(new QualityGateDetailsData(WARN, of(
new EvaluatedCondition(equals2Condition, OK, rawValue),
- new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());
+ new EvaluatedCondition(equals1WarningCondition, WARN, rawValue)), false).toJson());
QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
.hasStatus(QualityGateStatus.WARN)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java
index 0f41d0bf7cf..482ef242a6f 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java
@@ -61,9 +61,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));
- QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
+ boolean result = underTest.appliesTo(project, metricEvaluationResult);
- assertThat(result.evaluationResult.getLevel()).isSameAs(OK);
+ assertThat(result).isTrue();
}
@Test
@@ -72,9 +72,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));
- QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
+ boolean result = underTest.appliesTo(project, metricEvaluationResult);
- assertThat(result.evaluationResult.getLevel()).isSameAs(OK);
+ assertThat(result).isTrue();
}
@Test
@@ -83,9 +83,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(20).create(1000));
- QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
+ boolean result = underTest.appliesTo(project, metricEvaluationResult);
- assertThat(result.evaluationResult.getLevel()).isSameAs(ERROR);
+ assertThat(result).isFalse();
}
@Test
@@ -94,9 +94,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));
- QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
+ boolean result = underTest.appliesTo(project, metricEvaluationResult);
- assertThat(result.evaluationResult.getLevel()).isSameAs(ERROR);
+ assertThat(result).isFalse();
}
@Test
@@ -105,9 +105,9 @@ public class SmallChangesetQualityGateSpecialCaseTest {
Component project = generateNewRootProject();
measureRepository.addRawMeasure(PROJECT_REF, CoreMetrics.NEW_LINES_KEY, newMeasureBuilder().setVariation(19).create(1000));
- QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
+ boolean result = underTest.appliesTo(project, metricEvaluationResult);
- assertThat(result.evaluationResult.getLevel()).isSameAs(OK);
+ assertThat(result).isFalse();
}
@Test
@@ -115,17 +115,31 @@ public class SmallChangesetQualityGateSpecialCaseTest {
QualityGateMeasuresStep.MetricEvaluationResult metricEvaluationResult = generateEvaluationResult(NEW_COVERAGE_KEY, ERROR);
Component project = generateNewRootProject();
- QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(project, metricEvaluationResult);
+ boolean result = underTest.appliesTo(project, metricEvaluationResult);
- assertThat(result.evaluationResult.getLevel()).isSameAs(ERROR);
+ assertThat(result).isFalse();
}
@Test
public void should_silently_ignore_null_values() throws Exception {
- QualityGateMeasuresStep.MetricEvaluationResult result = underTest.applyIfNeeded(mock(Component.class), null);
+ boolean result = underTest.appliesTo(mock(Component.class), null);
- assertThat(result).isNull();
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void apply() throws Exception {
+ Comparable<?> value = mock(Comparable.class);
+ Condition condition = mock(Condition.class);
+ QualityGateMeasuresStep.MetricEvaluationResult original = new QualityGateMeasuresStep.MetricEvaluationResult(
+ new EvaluationResult(Measure.Level.ERROR, value), condition);
+
+ QualityGateMeasuresStep.MetricEvaluationResult modified = underTest.apply(original);
+
+ assertThat(modified.evaluationResult.getLevel()).isSameAs(OK);
+ assertThat(modified.evaluationResult.getValue()).isSameAs(value);
+ assertThat(modified.condition).isSameAs(condition);
}
private Component generateNewRootProject() {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
index 13305eb54db..8e96d3fd2d5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
@@ -26,6 +26,8 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.server.ws.Change;
+import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
@@ -47,6 +49,7 @@ import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse.Status;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.db.component.SnapshotTesting.newAnalysis;
import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
import static org.sonar.db.metric.MetricTesting.newMetricDto;
@@ -78,6 +81,15 @@ public class ProjectStatusActionTest {
}
@Test
+ public void definition() throws Exception {
+ WebService.Action def = ws.getDef();
+ assertThat(def.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("analysisId", "projectKey", "projectId");
+ assertThat(def.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactly(
+ tuple("6.4", "The field 'ignoredConditions' is added to the response")
+ );
+ }
+
+ @Test
public void json_example() throws IOException {
ComponentDto project = db.components().insertPrivateProject(db.organizations().insert());
userSession.addProjectPermission(UserRole.USER, project);
diff --git a/sonar-ws/src/main/protobuf/ws-qualitygates.proto b/sonar-ws/src/main/protobuf/ws-qualitygates.proto
index 92d2be56d33..8444dbac729 100644
--- a/sonar-ws/src/main/protobuf/ws-qualitygates.proto
+++ b/sonar-ws/src/main/protobuf/ws-qualitygates.proto
@@ -32,6 +32,7 @@ message ProjectStatusWsResponse {
optional Status status = 1;
repeated Condition conditions = 2;
repeated Period periods = 3;
+ optional bool ignoredConditions = 4;
}
message Condition {
diff --git a/tests/projects/qualitygate/small-changesets/v2-1020-lines/src/sample/Sample.xoo.scm b/tests/projects/qualitygate/small-changesets/v2-1020-lines/src/sample/Sample.xoo.scm
index 07c227857e1..98fd9a53dda 100644
--- a/tests/projects/qualitygate/small-changesets/v2-1020-lines/src/sample/Sample.xoo.scm
+++ b/tests/projects/qualitygate/small-changesets/v2-1020-lines/src/sample/Sample.xoo.scm
@@ -1017,4 +1017,4 @@
2,user2,2014-04-01
2,user2,2014-04-01
2,user2,2014-04-01
-3,user3,2014-04-02 \ No newline at end of file
+3,user3,2014-04-03 \ No newline at end of file
diff --git a/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateForSmallChangesetsTest.java b/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateForSmallChangesetsTest.java
index 715b80cab80..ca4c99e47dc 100644
--- a/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateForSmallChangesetsTest.java
+++ b/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateForSmallChangesetsTest.java
@@ -21,17 +21,29 @@ package org.sonarqube.tests.qualityGate;
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.SonarScanner;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+import org.apache.commons.io.FileUtils;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonarqube.tests.Category6Suite;
import org.sonarqube.tests.Tester;
+import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.Organizations;
+import org.sonarqube.ws.WsCe;
import org.sonarqube.ws.WsProjects.CreateWsResponse.Project;
import org.sonarqube.ws.WsQualityGates;
import org.sonarqube.ws.WsQualityGates.CreateWsResponse;
import org.sonarqube.ws.WsUsers;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsResponse;
import org.sonarqube.ws.client.qualitygate.CreateConditionRequest;
+import org.sonarqube.ws.client.qualitygate.ProjectStatusWsRequest;
+import org.sonarqube.ws.client.qualitygate.UpdateConditionRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.getMeasure;
@@ -64,6 +76,7 @@ public class QualityGateForSmallChangesetsTest {
String password = "password1";
WsUsers.CreateWsResponse.User user = tester.users().generateAdministrator(organization, u -> u.setPassword(password));
+ // no leak => use usual behaviour
SonarScanner analysis = SonarScanner
.create(projectDir("qualitygate/small-changesets/v1-1000-lines"))
.setProperty("sonar.projectKey", project.getKey())
@@ -76,7 +89,9 @@ public class QualityGateForSmallChangesetsTest {
.setDebugLogs(true);
orchestrator.executeBuild(analysis);
assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("OK");
+ assertIgnoredConditions(project, "qualitygate/small-changesets/v1-1000-lines", false);
+ // small leak => ignore coverage warning or error
SonarScanner analysis2 = SonarScanner
.create(projectDir("qualitygate/small-changesets/v2-1019-lines"))
.setProperty("sonar.projectKey", project.getKey())
@@ -89,7 +104,40 @@ public class QualityGateForSmallChangesetsTest {
.setDebugLogs(true);
orchestrator.executeBuild(analysis2);
assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("OK");
+ assertIgnoredConditions(project, "qualitygate/small-changesets/v2-1019-lines", true);
+ // small leak => if coverage is OK anyways, we do not have to ignore anything
+ tester.wsClient().qualityGates().updateCondition(UpdateConditionRequest.builder()
+ .setConditionId(condition.getId())
+ .setMetricKey("new_coverage")
+ .setOperator("LT")
+ .setWarning("10")
+ .setError("20")
+ .setPeriod(1)
+ .build());
+ SonarScanner analysis3 = SonarScanner
+ .create(projectDir("qualitygate/small-changesets/v2-1019-lines"))
+ .setProperty("sonar.projectKey", project.getKey())
+ .setProperty("sonar.organization", organization.getKey())
+ .setProperty("sonar.login", user.getLogin())
+ .setProperty("sonar.password", password)
+ .setProperty("sonar.scm.provider", "xoo")
+ .setProperty("sonar.scm.disabled", "false")
+ .setProperty("sonar.projectDate", "2014-04-02")
+ .setDebugLogs(true);
+ orchestrator.executeBuild(analysis3);
+ assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("OK");
+ assertIgnoredConditions(project, "qualitygate/small-changesets/v2-1019-lines", false);
+
+ // big leak => use usual behaviour
+ tester.wsClient().qualityGates().updateCondition(UpdateConditionRequest.builder()
+ .setConditionId(condition.getId())
+ .setMetricKey("new_coverage")
+ .setOperator("LT")
+ .setWarning(null)
+ .setError("70")
+ .setPeriod(1)
+ .build());
SonarScanner analysis4 = SonarScanner
.create(projectDir("qualitygate/small-changesets/v2-1020-lines"))
.setProperty("sonar.projectKey", project.getKey())
@@ -98,9 +146,40 @@ public class QualityGateForSmallChangesetsTest {
.setProperty("sonar.password", password)
.setProperty("sonar.scm.provider", "xoo")
.setProperty("sonar.scm.disabled", "false")
- .setProperty("sonar.projectDate", "2014-04-02")
+ .setProperty("sonar.projectDate", "2014-04-03")
.setDebugLogs(true);
orchestrator.executeBuild(analysis4);
assertThat(getMeasure(orchestrator, project.getKey(), "alert_status").getValue()).isEqualTo("ERROR");
+ assertIgnoredConditions(project, "qualitygate/small-changesets/v2-1020-lines", false);
+ }
+
+ private void assertIgnoredConditions(Project project, String projectDir, boolean expected) throws IOException {
+ String analysisId = getAnalysisId(getTaskIdInLocalReport(projectDir(projectDir)));
+ boolean ignoredConditions = tester.wsClient().qualityGates()
+ .projectStatus(new ProjectStatusWsRequest().setAnalysisId(analysisId))
+ .getProjectStatus()
+ .getIgnoredConditions();
+ assertThat(ignoredConditions).isEqualTo(expected);
+ }
+
+ private String getAnalysisId(String taskId) throws IOException {
+ WsResponse activity = tester.wsClient()
+ .wsConnector()
+ .call(new GetRequest("api/ce/task")
+ .setParam("id", taskId)
+ .setMediaType(MediaTypes.PROTOBUF));
+ WsCe.TaskResponse activityWsResponse = WsCe.TaskResponse.parseFrom(activity.contentStream());
+ return activityWsResponse.getTask().getAnalysisId();
+ }
+
+ private String getTaskIdInLocalReport(File projectDirectory) throws IOException {
+ File metadata = new File(projectDirectory, ".sonar/report-task.txt");
+ assertThat(metadata).exists().isFile();
+ // verify properties
+ Properties props = new Properties();
+ props.load(new StringReader(FileUtils.readFileToString(metadata, StandardCharsets.UTF_8)));
+ assertThat(props.getProperty("ceTaskId")).isNotEmpty();
+
+ return props.getProperty("ceTaskId");
}
}