]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10085 webhook now use shared model of QualityGate
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 17 Nov 2017 10:17:31 +0000 (11:17 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 24 Nov 2017 08:23:58 +0000 (09:23 +0100)
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTask.java
server/sonar-server/src/main/java/org/sonar/server/issue/webhook/IssueChangeWebhookImpl.java
server/sonar-server/src/main/java/org/sonar/server/webhook/ProjectAnalysis.java
server/sonar-server/src/main/java/org/sonar/server/webhook/QualityGate.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/webhook/WebhookPayloadFactoryImpl.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTaskTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/webhook/IssueChangeWebhookImplTest.java
server/sonar-server/src/test/java/org/sonar/server/webhook/ProjectAnalysisTest.java
server/sonar-server/src/test/java/org/sonar/server/webhook/QualityGateTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/webhook/WebhookPayloadFactoryImplTest.java

index ab8eef8c46546ae350563ee533aa10be952f3f70..6f016550ace4ead9944bdf0e38b1b9bdf9f5506b 100644 (file)
@@ -24,7 +24,6 @@ import java.util.Date;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.ce.posttask.Analysis;
@@ -37,6 +36,7 @@ import org.sonar.api.ce.posttask.ScannerContext;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader;
 import org.sonar.server.computation.task.projectanalysis.qualitygate.Condition;
@@ -191,7 +191,8 @@ public class PostProjectAnalysisTasksExecutor implements ComputationStepExecutor
 
   private static Collection<QualityGate.Condition> convert(Set<Condition> conditions, Map<Condition, ConditionStatus> statusPerConditions) {
     return conditions.stream()
-      .map(new ConditionToCondition(statusPerConditions)::apply).collect(Collectors.toList());
+      .map(new ConditionToCondition(statusPerConditions)::apply)
+      .collect(MoreCollectors.toList(statusPerConditions.size()));
   }
 
   private static class ProjectAnalysisImpl implements PostProjectAnalysisTask.ProjectAnalysis {
index 5adcd21c40ebd58b8d912fd8e1299f7aeccd0a21..c67e7419cf701d68efb66a4a1144e7e2c2c770d3 100644 (file)
@@ -21,15 +21,18 @@ package org.sonar.server.computation.task.projectanalysis.webhook;
 
 import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
+import java.util.Set;
 import org.sonar.api.ce.posttask.PostProjectAnalysisTask;
 import org.sonar.api.config.Configuration;
+import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository;
+import org.sonar.server.qualitygate.Condition;
+import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
 import org.sonar.server.webhook.Analysis;
 import org.sonar.server.webhook.Branch;
 import org.sonar.server.webhook.CeTask;
 import org.sonar.server.webhook.Project;
-import org.sonar.server.webhook.QualityGate;
 import org.sonar.server.webhook.WebHooks;
 import org.sonar.server.webhook.WebhookPayloadFactory;
 
@@ -63,16 +66,23 @@ public class WebhookPostTask implements PostProjectAnalysisTask {
     Project project = new Project(projectAnalysis.getProject().getUuid(), projectAnalysis.getProject().getKey(), projectAnalysis.getProject().getName());
     Analysis analysis = projectAnalysis.getAnalysis().map(a -> new Analysis(a.getAnalysisUuid(), a.getDate().getTime())).orElse(null);
     Branch branch = projectAnalysis.getBranch().map(b -> new Branch(b.isMain(), b.getName().orElse(null), Branch.Type.valueOf(b.getType().name()))).orElse(null);
-    QualityGate qualityGate = Optional.ofNullable(projectAnalysis.getQualityGate())
-      .map(qg -> new QualityGate(
-        qg.getId(),
-        qg.getName(),
-        QualityGate.Status.valueOf(qg.getStatus().name()),
-        qg.getConditions().stream()
-          .map(c -> new QualityGate.Condition(QualityGate.EvaluationStatus.valueOf(c.getStatus().name()), c.getMetricKey(), QualityGate.Operator.valueOf(c.getOperator().name()),
-            c.getErrorThreshold(), c.getWarningThreshold(), c.isOnLeakPeriod(),
-            c.getStatus() == org.sonar.api.ce.posttask.QualityGate.EvaluationStatus.NO_VALUE ? null : c.getValue()))
-          .collect(Collectors.toSet())))
+    EvaluatedQualityGate qualityGate = Optional.ofNullable(projectAnalysis.getQualityGate())
+      .map(qg -> {
+        EvaluatedQualityGate.Builder builder = EvaluatedQualityGate.newBuilder();
+        Set<Condition> conditions = qg.getConditions().stream()
+          .map(q -> {
+            Condition condition = new Condition(q.getMetricKey(), Condition.Operator.valueOf(q.getOperator().name()),
+              q.getErrorThreshold(), q.getWarningThreshold(), q.isOnLeakPeriod());
+            builder.addCondition(condition,
+              EvaluatedCondition.EvaluationStatus.valueOf(q.getStatus().name()),
+              q.getStatus() == org.sonar.api.ce.posttask.QualityGate.EvaluationStatus.NO_VALUE ? null : q.getValue());
+            return condition;
+          })
+          .collect(MoreCollectors.toSet());
+        return builder.setQualityGate(new org.sonar.server.qualitygate.QualityGate(qg.getId(), qg.getName(), conditions))
+          .setStatus(EvaluatedQualityGate.Status.valueOf(qg.getStatus().name()))
+          .build();
+      })
       .orElse(null);
     Long date = projectAnalysis.getAnalysis().map(a -> a.getDate().getTime()).orElse(null);
     Map<String, String> properties = projectAnalysis.getScannerContext().getProperties();
index b379eb629a7b32208ed22101ebbc96f5313b2171..698dae3bf2a14064a720865ceb341e3bdc45d5ba 100644 (file)
@@ -46,6 +46,10 @@ import org.sonar.server.es.Facets;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.issue.IssueQuery;
 import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.qualitygate.Condition;
+import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
 import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.settings.ProjectConfigurationLoader;
@@ -53,7 +57,6 @@ import org.sonar.server.webhook.Analysis;
 import org.sonar.server.webhook.Branch;
 import org.sonar.server.webhook.Project;
 import org.sonar.server.webhook.ProjectAnalysis;
-import org.sonar.server.webhook.QualityGate;
 import org.sonar.server.webhook.WebHooks;
 import org.sonar.server.webhook.WebhookPayload;
 import org.sonar.server.webhook.WebhookPayloadFactory;
@@ -170,7 +173,7 @@ public class IssueChangeWebhookImpl implements IssueChangeWebhook {
     return webhookPayloadFactory.create(projectAnalysis);
   }
 
-  private QualityGate createQualityGate(ComponentDto branch, IssueIndex issueIndex) {
+  private EvaluatedQualityGate createQualityGate(ComponentDto branch, IssueIndex issueIndex) {
     SearchResponse searchResponse = issueIndex.search(IssueQuery.builder()
       .projectUuids(singletonList(branch.getMainBranchProjectUuid()))
       .branchUuid(branch.uuid())
@@ -182,43 +185,48 @@ public class IssueChangeWebhookImpl implements IssueChangeWebhook {
     LinkedHashMap<String, Long> typeFacet = new Facets(searchResponse, system2.getDefaultTimeZone())
       .get(RuleIndex.FACET_TYPES);
 
-    Set<QualityGate.Condition> conditions = ShortLivingBranchQualityGate.CONDITIONS.stream()
-      .map(c -> toCondition(typeFacet, c))
+    EvaluatedQualityGate.Builder builder = EvaluatedQualityGate.newBuilder();
+    Set<Condition> conditions = ShortLivingBranchQualityGate.CONDITIONS.stream()
+      .map(c -> {
+        long measure = getMeasure(typeFacet, c);
+        EvaluationStatus status = measure > 0 ? EvaluationStatus.ERROR : EvaluationStatus.OK;
+        Condition condition = new Condition(c.getMetricKey(), toOperator(c), c.getErrorThreshold(), c.getWarnThreshold(), c.isOnLeak());
+        builder.addCondition(condition, status, valueOf(measure));
+        return condition;
+      })
       .collect(toSet(ShortLivingBranchQualityGate.CONDITIONS.size()));
+    builder
+      .setQualityGate(
+        new org.sonar.server.qualitygate.QualityGate(
+          valueOf(ShortLivingBranchQualityGate.ID),
+          ShortLivingBranchQualityGate.NAME,
+          conditions))
+      .setStatus(qgStatusFrom(builder.getEvaluatedConditions()));
 
-    return new QualityGate(valueOf(ShortLivingBranchQualityGate.ID), ShortLivingBranchQualityGate.NAME, qgStatusFrom(conditions), conditions);
+    return builder.build();
   }
 
-  private static QualityGate.Condition toCondition(LinkedHashMap<String, Long> typeFacet, ShortLivingBranchQualityGate.Condition c) {
-    long measure = getMeasure(typeFacet, c);
-    QualityGate.EvaluationStatus status = measure > 0 ? QualityGate.EvaluationStatus.ERROR : QualityGate.EvaluationStatus.OK;
-    return new QualityGate.Condition(status, c.getMetricKey(),
-      toOperator(c),
-      c.getErrorThreshold(), c.getWarnThreshold(), c.isOnLeak(),
-      valueOf(measure));
-  }
-
-  private static QualityGate.Operator toOperator(ShortLivingBranchQualityGate.Condition c) {
+  private static Condition.Operator toOperator(ShortLivingBranchQualityGate.Condition c) {
     String operator = c.getOperator();
     switch (operator) {
       case QualityGateConditionDto.OPERATOR_GREATER_THAN:
-        return QualityGate.Operator.GREATER_THAN;
+        return Condition.Operator.GREATER_THAN;
       case QualityGateConditionDto.OPERATOR_LESS_THAN:
-        return QualityGate.Operator.LESS_THAN;
+        return Condition.Operator.LESS_THAN;
       case QualityGateConditionDto.OPERATOR_EQUALS:
-        return QualityGate.Operator.EQUALS;
+        return Condition.Operator.EQUALS;
       case QualityGateConditionDto.OPERATOR_NOT_EQUALS:
-        return QualityGate.Operator.NOT_EQUALS;
+        return Condition.Operator.NOT_EQUALS;
       default:
         throw new IllegalArgumentException(format("Unsupported Condition operator '%s'", operator));
     }
   }
 
-  private static QualityGate.Status qgStatusFrom(Set<QualityGate.Condition> conditions) {
-    if (conditions.stream().anyMatch(c -> c.getStatus() == QualityGate.EvaluationStatus.ERROR)) {
-      return QualityGate.Status.ERROR;
+  private static EvaluatedQualityGate.Status qgStatusFrom(Set<EvaluatedCondition> conditions) {
+    if (conditions.stream().anyMatch(c -> c.getStatus() == EvaluationStatus.ERROR)) {
+      return EvaluatedQualityGate.Status.ERROR;
     }
-    return QualityGate.Status.OK;
+    return EvaluatedQualityGate.Status.OK;
   }
 
   private static long getMeasure(LinkedHashMap<String, Long> typeFacet, ShortLivingBranchQualityGate.Condition c) {
index 6e94f505ce420797d66374d172db7c94262fb315..3f8616828616bd9d62e0aac88a08b78260dc29c1 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import javax.annotation.Nullable;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
 
 import static com.google.common.collect.ImmutableMap.copyOf;
 import static java.util.Objects.requireNonNull;
@@ -31,13 +32,13 @@ public class ProjectAnalysis {
   private final Project project;
   private final CeTask ceTask;
   private final Branch branch;
-  private final QualityGate qualityGate;
+  private final EvaluatedQualityGate qualityGate;
   private final Long updatedAt;
   private final Map<String, String> properties;
   private final Analysis analysis;
 
   public ProjectAnalysis(Project project, @Nullable CeTask ceTask, @Nullable Analysis analysis,
-    @Nullable Branch branch, @Nullable QualityGate qualityGate, @Nullable Long updatedAt,
+    @Nullable Branch branch, @Nullable EvaluatedQualityGate qualityGate, @Nullable Long updatedAt,
     Map<String, String> properties) {
     this.project = requireNonNull(project, "project can't be null");
     this.ceTask = ceTask;
@@ -60,7 +61,7 @@ public class ProjectAnalysis {
     return Optional.ofNullable(branch);
   }
 
-  public Optional<QualityGate> getQualityGate() {
+  public Optional<EvaluatedQualityGate> getQualityGate() {
     return Optional.ofNullable(qualityGate);
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/QualityGate.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/QualityGate.java
deleted file mode 100644 (file)
index 2133842..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.webhook;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.Nullable;
-
-import static java.util.Objects.requireNonNull;
-
-public final class QualityGate {
-  private final String id;
-  private final String name;
-  private final Status status;
-  private final Set<Condition> conditions;
-
-  public QualityGate(String id, String name, Status status, Set<Condition> conditions) {
-    this.id = requireNonNull(id, "id can't be null");
-    this.name = requireNonNull(name, "name can't be null");
-    this.status = requireNonNull(status, "status can't be null");
-    this.conditions = ImmutableSet.copyOf(requireNonNull(conditions, "conditions can't be null"));
-  }
-
-  public String getId() {
-    return id;
-  }
-
-  public String getName() {
-    return name;
-  }
-
-  public Status getStatus() {
-    return status;
-  }
-
-  public Collection<Condition> getConditions() {
-    return conditions;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    QualityGate that = (QualityGate) o;
-    return Objects.equals(id, that.id) &&
-      Objects.equals(name, that.name) &&
-      status == that.status &&
-      Objects.equals(conditions, that.conditions);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(id, name, status, conditions);
-  }
-
-  @Override
-  public String toString() {
-    return "QualityGate{" +
-      "id='" + id + '\'' +
-      ", name='" + name + '\'' +
-      ", status=" + status +
-      ", conditions=" + conditions +
-      '}';
-  }
-
-  public enum Status {
-    OK,
-    WARN,
-    ERROR
-  }
-
-  public static final class Condition {
-    private final EvaluationStatus status;
-    private final String metricKey;
-    private final Operator operator;
-    private final String errorThreshold;
-    private final String warnThreshold;
-    private final boolean onLeakPeriod;
-    private final String value;
-
-    public Condition(EvaluationStatus status, String metricKey, Operator operator,
-      @Nullable String errorThreshold, @Nullable String warnThreshold,
-      boolean onLeakPeriod, @Nullable String value) {
-      this.status = requireNonNull(status, "status can't be null");
-      this.metricKey = requireNonNull(metricKey, "metricKey can't be null");
-      this.operator = requireNonNull(operator, "operator can't be null");
-      this.errorThreshold = errorThreshold;
-      this.warnThreshold = warnThreshold;
-      this.onLeakPeriod = onLeakPeriod;
-      this.value = value;
-    }
-
-    public EvaluationStatus getStatus() {
-      return status;
-    }
-
-    public String getMetricKey() {
-      return metricKey;
-    }
-
-    public Operator getOperator() {
-      return operator;
-    }
-
-    public Optional<String> getErrorThreshold() {
-      return Optional.ofNullable(errorThreshold);
-    }
-
-    public Optional<String> getWarningThreshold() {
-      return Optional.ofNullable(warnThreshold);
-    }
-
-    public boolean isOnLeakPeriod() {
-      return onLeakPeriod;
-    }
-
-    public Optional<String> getValue() {
-      return Optional.ofNullable(value);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      Condition condition = (Condition) o;
-      return onLeakPeriod == condition.onLeakPeriod &&
-        status == condition.status &&
-        Objects.equals(metricKey, condition.metricKey) &&
-        operator == condition.operator &&
-        Objects.equals(errorThreshold, condition.errorThreshold) &&
-        Objects.equals(warnThreshold, condition.warnThreshold) &&
-        Objects.equals(value, condition.value);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(status, metricKey, operator, errorThreshold, warnThreshold, onLeakPeriod, value);
-    }
-
-    @Override
-    public String toString() {
-      return "Condition{" +
-        "status=" + status +
-        ", metricKey='" + metricKey + '\'' +
-        ", operator=" + operator +
-        ", errorThreshold='" + errorThreshold + '\'' +
-        ", warnThreshold='" + warnThreshold + '\'' +
-        ", onLeakPeriod=" + onLeakPeriod +
-        ", value='" + value + '\'' +
-        '}';
-    }
-  }
-
-  /**
-   * Quality Gate condition operator.
-   */
-  public enum Operator {
-    EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN
-  }
-
-  /**
-   * Quality gate condition evaluation status.
-   */
-  public enum EvaluationStatus {
-    /**
-     * No measure found or measure had no value. The condition has not been evaluated and therefor ignored in
-     * the computation of the Quality Gate status.
-     */
-    NO_VALUE,
-    /**
-     * Condition evaluated as OK, neither error nor warning thresholds have been reached.
-     */
-    OK,
-    /**
-     * Condition evaluated as WARN, only warning thresholds has been reached.
-     */
-    WARN,
-    /**
-     * Condition evaluated as ERROR, error thresholds has been reached (and most likely warning thresholds too).
-     */
-    ERROR
-  }
-}
index 9f4c0ca5015e92ea6868477773ccead4c3ea24cc..d57271074176be46fb0437875b2db25967feb618 100644 (file)
@@ -30,6 +30,9 @@ import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.platform.Server;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.server.qualitygate.Condition;
+import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
 
 import static java.lang.String.format;
 import static org.sonar.core.config.WebhookProperties.ANALYSIS_PROPERTY_PREFIX;
@@ -126,22 +129,23 @@ public class WebhookPayloadFactoryImpl implements WebhookPayloadFactory {
     }
   }
 
-  private static void writeQualityGate(JsonWriter writer, QualityGate gate) {
+  private static void writeQualityGate(JsonWriter writer, EvaluatedQualityGate gate) {
     writer
       .name("qualityGate")
       .beginObject()
-      .prop("name", gate.getName())
+      .prop("name", gate.getQualityGate().getName())
       .prop(PROPERTY_STATUS, gate.getStatus().toString())
       .name("conditions")
       .beginArray();
-    for (QualityGate.Condition condition : gate.getConditions()) {
+    for (EvaluatedCondition evaluatedCondition : gate.getEvaluatedConditions()) {
+      Condition condition = evaluatedCondition.getCondition();
       writer
         .beginObject()
         .prop("metric", condition.getMetricKey())
         .prop("operator", condition.getOperator().name());
-      condition.getValue().ifPresent(t -> writer.prop("value", t));
+      evaluatedCondition.getValue().ifPresent(t -> writer.prop("value", t));
       writer
-        .prop(PROPERTY_STATUS, condition.getStatus().name())
+        .prop(PROPERTY_STATUS, evaluatedCondition.getStatus().name())
         .prop("onLeakPeriod", condition.isOnLeakPeriod())
         .prop("errorThreshold", condition.getErrorThreshold().orElse(null))
         .prop("warningThreshold", condition.getWarningThreshold().orElse(null))
index c610f8e91e2623aee031d6c793685c141e7d23e3..e95b32c22d604a7f14967405ca7ec8a819618fe1 100644 (file)
@@ -36,6 +36,9 @@ import org.sonar.api.ce.posttask.Project;
 import org.sonar.api.ce.posttask.QualityGate;
 import org.sonar.api.config.Configuration;
 import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository;
+import org.sonar.server.qualitygate.Condition;
+import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
 import org.sonar.server.webhook.Analysis;
 import org.sonar.server.webhook.ProjectAnalysis;
 import org.sonar.server.webhook.WebHooks;
@@ -139,19 +142,20 @@ public class WebhookPostTaskTest {
 
     assertThat(supplierCaptor.getValue().get()).isSameAs(webhookPayload);
 
-    org.sonar.server.webhook.QualityGate webQualityGate = null;
+    EvaluatedQualityGate webQualityGate = null;
     if (qualityGate != null) {
       QualityGate.Condition condition = qualityGate.getConditions().iterator().next();
-      webQualityGate = new org.sonar.server.webhook.QualityGate(qualityGate.getId(), qualityGate.getName(),
-        org.sonar.server.webhook.QualityGate.Status.valueOf(qualityGate.getStatus().name()),
-        Collections.singleton(new org.sonar.server.webhook.QualityGate.Condition(
-          org.sonar.server.webhook.QualityGate.EvaluationStatus.valueOf(condition.getStatus().name()),
-          condition.getMetricKey(),
-          org.sonar.server.webhook.QualityGate.Operator.valueOf(condition.getOperator().name()),
-          condition.getErrorThreshold(),
-          condition.getWarningThreshold(),
-          condition.isOnLeakPeriod(),
-          condition.getValue())));
+      Condition qgCondition = new Condition(
+        condition.getMetricKey(),
+        Condition.Operator.valueOf(condition.getOperator().name()),
+        condition.getErrorThreshold(),
+        condition.getWarningThreshold(),
+        condition.isOnLeakPeriod());
+      webQualityGate = EvaluatedQualityGate.newBuilder()
+        .setQualityGate(new org.sonar.server.qualitygate.QualityGate(qualityGate.getId(), qualityGate.getName(), Collections.singleton(qgCondition)))
+        .setStatus(EvaluatedQualityGate.Status.valueOf(qualityGate.getStatus().name()))
+        .addCondition(qgCondition, EvaluatedCondition.EvaluationStatus.valueOf(condition.getStatus().name()), condition.getValue())
+        .build();
     }
 
     verify(payloadFactory).create(new ProjectAnalysis(
index 95b7232d1026abe2589178cf01288f04834be98c..94c25b67a3bb4b4915b2433c5155fabd0663b816 100644 (file)
@@ -49,7 +49,6 @@ import org.sonar.api.config.Configuration;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.issue.DefaultTransitions;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.rules.RuleType;
 import org.sonar.api.utils.System2;
 import org.sonar.core.issue.IssueChangeContext;
@@ -77,6 +76,11 @@ import org.sonar.server.issue.index.IssueIndexer;
 import org.sonar.server.issue.index.IssueIteratorFactory;
 import org.sonar.server.issue.webhook.IssueChangeWebhook.IssueChange;
 import org.sonar.server.permission.index.AuthorizationTypeSupport;
+import org.sonar.server.qualitygate.Condition;
+import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
+import org.sonar.server.qualitygate.QualityGate;
 import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 import org.sonar.server.settings.ProjectConfigurationLoader;
 import org.sonar.server.tester.UserSessionRule;
@@ -84,8 +88,6 @@ import org.sonar.server.webhook.Analysis;
 import org.sonar.server.webhook.Branch;
 import org.sonar.server.webhook.Project;
 import org.sonar.server.webhook.ProjectAnalysis;
-import org.sonar.server.webhook.QualityGate;
-import org.sonar.server.webhook.QualityGate.EvaluationStatus;
 import org.sonar.server.webhook.WebHooks;
 import org.sonar.server.webhook.WebhookPayload;
 import org.sonar.server.webhook.WebhookPayloadFactory;
@@ -115,7 +117,7 @@ import static org.sonar.api.measures.CoreMetrics.BUGS_KEY;
 import static org.sonar.api.measures.CoreMetrics.CODE_SMELLS_KEY;
 import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY;
 import static org.sonar.core.util.stream.MoreCollectors.toArrayList;
-import static org.sonar.server.webhook.QualityGate.Operator.GREATER_THAN;
+import static org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN;
 
 @RunWith(DataProviderRunner.class)
 public class IssueChangeWebhookImplTest {
@@ -148,7 +150,8 @@ public class IssueChangeWebhookImplTest {
   private IssueChangeWebhookImpl underTest = new IssueChangeWebhookImpl(spiedOnDbClient, webHooks, projectConfigurationLoader, webhookPayloadFactory, issueIndex, System2.INSTANCE);
   private DbClient mockedDbClient = mock(DbClient.class);
   private IssueIndex spiedOnIssueIndex = spy(issueIndex);
-  private IssueChangeWebhookImpl mockedUnderTest = new IssueChangeWebhookImpl(mockedDbClient, webHooks, projectConfigurationLoader, webhookPayloadFactory, spiedOnIssueIndex, System2.INSTANCE);
+  private IssueChangeWebhookImpl mockedUnderTest = new IssueChangeWebhookImpl(mockedDbClient, webHooks, projectConfigurationLoader, webhookPayloadFactory, spiedOnIssueIndex,
+    System2.INSTANCE);
 
   @Test
   public void on_type_change_has_no_effect_if_SearchResponseData_has_no_issue() {
@@ -267,20 +270,25 @@ public class IssueChangeWebhookImplTest {
     underTest.onChange(issueChangeData(newIssueDto(branch)), issueChange, userChangeContext);
 
     ProjectAnalysis projectAnalysis = verifyWebhookCalledAndExtractPayloadFactoryArgument(branch, configuration, analysis);
+    Condition condition1 = new Condition(BUGS_KEY, GREATER_THAN, "0", null, false);
+    Condition condition2 = new Condition(VULNERABILITIES_KEY, GREATER_THAN, "0", null, false);
+    Condition condition3 = new Condition(CODE_SMELLS_KEY, GREATER_THAN, "0", null, false);
     assertThat(projectAnalysis).isEqualTo(
       new ProjectAnalysis(
         new Project(project.uuid(), project.getKey(), project.name()),
         null,
         new Analysis(analysis.getUuid(), analysis.getCreatedAt()),
         new Branch(false, "foo", Branch.Type.SHORT),
-        new QualityGate(
-          valueOf(ShortLivingBranchQualityGate.ID),
-          ShortLivingBranchQualityGate.NAME,
-          QualityGate.Status.OK,
-          ImmutableSet.of(
-            new QualityGate.Condition(EvaluationStatus.OK, BUGS_KEY, GREATER_THAN, "0", null, false, "0"),
-            new QualityGate.Condition(EvaluationStatus.OK, CoreMetrics.VULNERABILITIES_KEY, GREATER_THAN, "0", null, false, "0"),
-            new QualityGate.Condition(EvaluationStatus.OK, CODE_SMELLS_KEY, GREATER_THAN, "0", null, false, "0"))),
+        EvaluatedQualityGate.newBuilder()
+          .setQualityGate(new QualityGate(
+            valueOf(ShortLivingBranchQualityGate.ID),
+            ShortLivingBranchQualityGate.NAME,
+            ImmutableSet.of(condition1, condition2, condition3)))
+          .setStatus(EvaluatedQualityGate.Status.OK)
+          .addCondition(condition1, EvaluationStatus.OK, "0")
+          .addCondition(condition2, EvaluationStatus.OK, "0")
+          .addCondition(condition3, EvaluationStatus.OK, "0")
+          .build(),
         null,
         properties));
   }
@@ -378,10 +386,10 @@ public class IssueChangeWebhookImplTest {
     underTest.onChange(issueChangeData(newIssueDto(branch)), new IssueChange(randomRuleType), userChangeContext);
 
     ProjectAnalysis projectAnalysis = verifyWebhookCalledAndExtractPayloadFactoryArgument(branch, configuration, analysis);
-    QualityGate qualityGate = projectAnalysis.getQualityGate().get();
-    assertThat(qualityGate.getStatus()).isEqualTo(QualityGate.Status.OK);
-    assertThat(qualityGate.getConditions())
-      .extracting(QualityGate.Condition::getStatus, QualityGate.Condition::getValue)
+    EvaluatedQualityGate qualityGate = projectAnalysis.getQualityGate().get();
+    assertThat(qualityGate.getStatus()).isEqualTo(EvaluatedQualityGate.Status.OK);
+    assertThat(qualityGate.getEvaluatedConditions())
+      .extracting(EvaluatedCondition::getStatus, EvaluatedCondition::getValue)
       .containsOnly(Tuple.tuple(EvaluationStatus.OK, Optional.of("0")));
   }
 
@@ -436,10 +444,10 @@ public class IssueChangeWebhookImplTest {
     underTest.onChange(issueChangeData(newIssueDto(branch)), new IssueChange(randomRuleType), userChangeContext);
 
     ProjectAnalysis projectAnalysis = verifyWebhookCalledAndExtractPayloadFactoryArgument(branch, configuration, analysis);
-    QualityGate qualityGate = projectAnalysis.getQualityGate().get();
-    assertThat(qualityGate.getStatus()).isEqualTo(QualityGate.Status.ERROR);
-    assertThat(qualityGate.getConditions())
-      .extracting(QualityGate.Condition::getMetricKey, QualityGate.Condition::getStatus, QualityGate.Condition::getValue)
+    EvaluatedQualityGate qualityGate = projectAnalysis.getQualityGate().get();
+    assertThat(qualityGate.getStatus()).isEqualTo(EvaluatedQualityGate.Status.ERROR);
+    assertThat(qualityGate.getEvaluatedConditions())
+      .extracting(s -> s.getCondition().getMetricKey(), EvaluatedCondition::getStatus, EvaluatedCondition::getValue)
       .containsOnly(expectedQGConditions);
   }
 
@@ -462,10 +470,10 @@ public class IssueChangeWebhookImplTest {
     underTest.onChange(issueChangeData(newIssueDto(branch)), new IssueChange(randomRuleType), userChangeContext);
 
     ProjectAnalysis projectAnalysis = verifyWebhookCalledAndExtractPayloadFactoryArgument(branch, configuration, analysis);
-    QualityGate qualityGate = projectAnalysis.getQualityGate().get();
-    assertThat(qualityGate.getStatus()).isEqualTo(QualityGate.Status.ERROR);
-    assertThat(qualityGate.getConditions())
-      .extracting(QualityGate.Condition::getMetricKey, QualityGate.Condition::getStatus, QualityGate.Condition::getValue)
+    EvaluatedQualityGate qualityGate = projectAnalysis.getQualityGate().get();
+    assertThat(qualityGate.getStatus()).isEqualTo(EvaluatedQualityGate.Status.ERROR);
+    assertThat(qualityGate.getEvaluatedConditions())
+      .extracting(s -> s.getCondition().getMetricKey(), EvaluatedCondition::getStatus, EvaluatedCondition::getValue)
       .containsOnly(
         Tuple.tuple(BUGS_KEY, EvaluationStatus.ERROR, Optional.of(valueOf(unresolvedBugs))),
         Tuple.tuple(VULNERABILITIES_KEY, EvaluationStatus.ERROR, Optional.of(valueOf(unresolvedVulnerabilities))),
@@ -564,18 +572,18 @@ public class IssueChangeWebhookImplTest {
     Configuration configuration2 = mock(Configuration.class);
     Configuration configuration3 = mock(Configuration.class);
     mockLoadProjectConfigurations(
-        branch1, configuration1,
-        branch2, configuration2,
-        branch3, configuration3);
+      branch1, configuration1,
+      branch2, configuration2,
+      branch3, configuration3);
     mockWebhookEnabled(configuration1, configuration2, configuration3);
     mockPayloadSupplierConsumedByWebhooks();
 
     ComponentDao componentDaoSpy = spy(dbClient.componentDao());
     when(spiedOnDbClient.componentDao()).thenReturn(componentDaoSpy);
     underTest.onChange(
-        issueChangeData(issueDtos, branch1, branch2, branch3),
-        new IssueChange(randomRuleType),
-        userChangeContext);
+      issueChangeData(issueDtos, branch1, branch2, branch3),
+      new IssueChange(randomRuleType),
+      userChangeContext);
 
     verifyWebhookCalled(branch1, configuration1, analysis1);
     verifyWebhookCalled(branch2, configuration2, analysis2);
index 45187a36b5607087eb65ae6c7f3c1459fb470053..ff88b24dc485d6f2520279fc7270693e46bc8e37 100644 (file)
@@ -24,6 +24,8 @@ import java.util.Map;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
+import org.sonar.server.qualitygate.QualityGate;
 
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.emptySet;
@@ -37,7 +39,10 @@ public class ProjectAnalysisTest {
   private final Project project = new Project("uuid", "key", "name");
   private final Analysis analysis = new Analysis("analysis_uuid", 1_500L);
   private final Branch branch = new Branch(true, "name", Branch.Type.SHORT);
-  private final QualityGate qualityGate = new QualityGate("id", "name", QualityGate.Status.WARN, emptySet());
+  private final EvaluatedQualityGate qualityGate = EvaluatedQualityGate.newBuilder()
+    .setQualityGate(new QualityGate("id", "name", emptySet()))
+    .setStatus(EvaluatedQualityGate.Status.WARN)
+    .build();
   private final Map<String, String> properties = ImmutableMap.of("a", "b");
   private ProjectAnalysis underTest = new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, 1L, properties);
 
@@ -101,7 +106,11 @@ public class ProjectAnalysisTest {
     assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, null, qualityGate, 1L, properties));
     assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, new Branch(false, "B", Branch.Type.SHORT), qualityGate, 1L, properties));
     assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, null, 1L, properties));
-    assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, new QualityGate("A", "B", QualityGate.Status.WARN, emptySet()), 1L, properties));
+    EvaluatedQualityGate otherQualityGate = EvaluatedQualityGate.newBuilder()
+      .setQualityGate(new QualityGate("A", "B", emptySet()))
+      .setStatus(EvaluatedQualityGate.Status.WARN)
+      .build();
+    assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, otherQualityGate, 1L, properties));
     assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, null, properties));
     assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, 2L, properties));
     assertThat(underTest).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, 1L, emptyMap()));
@@ -123,17 +132,21 @@ public class ProjectAnalysisTest {
     assertThat(underTest.hashCode())
       .isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, new Branch(false, "B", Branch.Type.SHORT), qualityGate, 1L, properties).hashCode());
     assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, null, 1L, properties).hashCode());
+    EvaluatedQualityGate otherQualityGate = EvaluatedQualityGate.newBuilder()
+      .setQualityGate(new QualityGate("A", "B", emptySet()))
+      .setStatus(EvaluatedQualityGate.Status.WARN)
+      .build();
     assertThat(underTest.hashCode())
-      .isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, new QualityGate("A", "B", QualityGate.Status.WARN, emptySet()), 1L, properties).hashCode());
-    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, null, properties).hashCode());
-    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, 2L, properties).hashCode());
-    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, 1L, emptyMap()).hashCode());
-    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, qualityGate, 1L, ImmutableMap.of("B", "C")).hashCode());
+      .isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, otherQualityGate, 1L, properties).hashCode());
+    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, this.qualityGate, null, properties).hashCode());
+    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, this.qualityGate, 2L, properties).hashCode());
+    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, this.qualityGate, 1L, emptyMap()).hashCode());
+    assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(project, ceTask, analysis, branch, this.qualityGate, 1L, ImmutableMap.of("B", "C")).hashCode());
   }
 
   @Test
   public void verify_toString() {
     assertThat(underTest.toString()).isEqualTo(
-      "ProjectAnalysis{project=Project{uuid='uuid', key='key', name='name'}, ceTask=CeTask{id='id', status=SUCCESS}, branch=Branch{main=true, name='name', type=SHORT}, qualityGate=QualityGate{id='id', name='name', status=WARN, conditions=[]}, updatedAt=1, properties={a=b}, analysis=Analysis{uuid='analysis_uuid', date=1500}}");
+      "ProjectAnalysis{project=Project{uuid='uuid', key='key', name='name'}, ceTask=CeTask{id='id', status=SUCCESS}, branch=Branch{main=true, name='name', type=SHORT}, qualityGate=EvaluatedQualityGate{qualityGate=QualityGate{id=id, name='name', conditions=[]}, status=WARN, evaluatedConditions=[]}, updatedAt=1, properties={a=b}, analysis=Analysis{uuid='analysis_uuid', date=1500}}");
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/webhook/QualityGateTest.java b/server/sonar-server/src/test/java/org/sonar/server/webhook/QualityGateTest.java
deleted file mode 100644 (file)
index b75c467..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.webhook;
-
-import java.util.Random;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import static java.util.Collections.singleton;
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class QualityGateTest {
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
-  private final Random random = new Random();
-  private boolean onLeak = random.nextBoolean();
-  private QualityGate.EvaluationStatus randomEvaluationStatus = QualityGate.EvaluationStatus.values()[random.nextInt(QualityGate.EvaluationStatus.values().length)];
-  private QualityGate.Condition condition = new QualityGate.Condition(
-    randomEvaluationStatus, "k", QualityGate.Operator.GREATER_THAN, "l", "m", onLeak, "val");
-  private QualityGate.Status randomStatus = QualityGate.Status.values()[random.nextInt(QualityGate.Status.values().length)];
-  private QualityGate underTest = new QualityGate("i", "j", randomStatus, singleton(condition));
-
-  @Test
-  public void constructor_throws_NPE_if_id_is_null() {
-    expectedException.expect(NullPointerException.class);
-    expectedException.expectMessage("id can't be null");
-
-    new QualityGate(null, "j", QualityGate.Status.WARN, singleton(condition));
-  }
-
-  @Test
-  public void constructor_throws_NPE_if_name_is_null() {
-    expectedException.expect(NullPointerException.class);
-    expectedException.expectMessage("name can't be null");
-
-    new QualityGate("i", null, QualityGate.Status.WARN, singleton(condition));
-  }
-
-  @Test
-  public void constructor_throws_NPE_if_status_is_null() {
-    expectedException.expect(NullPointerException.class);
-    expectedException.expectMessage("status can't be null");
-
-    new QualityGate("i", "j", null, singleton(condition));
-  }
-
-  @Test
-  public void constructor_throws_NPE_if_conditions_is_null() {
-    expectedException.expect(NullPointerException.class);
-    expectedException.expectMessage("conditions can't be null");
-
-    new QualityGate("i", "j", QualityGate.Status.WARN, null);
-  }
-
-  @Test
-  public void condition_constructor_throws_NPE_if_evaluation_status_is_null() {
-    expectedException.expect(NullPointerException.class);
-    expectedException.expectMessage("status can't be null");
-
-    new QualityGate.Condition(null, "k", QualityGate.Operator.GREATER_THAN, "l", "m", onLeak, "val");
-  }
-
-  @Test
-  public void condition_constructor_throws_NPE_if_metricKey_is_null() {
-    expectedException.expect(NullPointerException.class);
-    expectedException.expectMessage("metricKey can't be null");
-
-    new QualityGate.Condition(randomEvaluationStatus, null, QualityGate.Operator.GREATER_THAN, "l", "m", onLeak, "val");
-  }
-
-  @Test
-  public void condition_constructor_throws_NPE_if_operator_status_is_null() {
-    expectedException.expect(NullPointerException.class);
-    expectedException.expectMessage("operator can't be null");
-
-    new QualityGate.Condition(randomEvaluationStatus, "k", null, "l", "m", onLeak, "val");
-  }
-
-  @Test
-  public void verify_getters() {
-    assertThat(underTest.getId()).isEqualTo("i");
-    assertThat(underTest.getName()).isEqualTo("j");
-    assertThat(underTest.getStatus()).isEqualTo(randomStatus);
-    assertThat(underTest.getConditions()).isEqualTo(singleton(condition));
-  }
-
-  @Test
-  public void verify_condition_getters() {
-    assertThat(condition.getStatus()).isEqualTo(randomEvaluationStatus);
-    assertThat(condition.getMetricKey()).isEqualTo("k");
-    assertThat(condition.getErrorThreshold()).contains("l");
-    assertThat(condition.getWarningThreshold()).contains("m");
-    assertThat(condition.isOnLeakPeriod()).isEqualTo(onLeak);
-    assertThat(condition.getValue()).contains("val");
-
-    QualityGate.Condition conditionWithNulls = new QualityGate.Condition(
-        randomEvaluationStatus, "k", QualityGate.Operator.GREATER_THAN, null, null, onLeak, null);
-
-    assertThat(conditionWithNulls.getErrorThreshold()).isEmpty();
-    assertThat(conditionWithNulls.getWarningThreshold()).isEmpty();
-    assertThat(conditionWithNulls.getValue()).isEmpty();
-  }
-}
index 05501d9e366a28c682fd1fda792df1f6b18ac310..f81b5969094919a7925ad5d7754e65afec1c9abd 100644 (file)
@@ -26,6 +26,10 @@ import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.platform.Server;
 import org.sonar.api.utils.System2;
+import org.sonar.server.qualitygate.Condition;
+import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
+import org.sonar.server.qualitygate.QualityGate;
 
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.emptySet;
@@ -52,9 +56,12 @@ public class WebhookPayloadFactoryImplTest {
   @Test
   public void create_payload_for_successful_analysis() {
     CeTask task = new CeTask("#1", CeTask.Status.SUCCESS);
-    QualityGate gate = new QualityGate("G1", "Gate One", QualityGate.Status.WARN, singleton(new QualityGate.Condition(
-      QualityGate.EvaluationStatus.WARN,
-      "coverage", QualityGate.Operator.GREATER_THAN, "70.0", "75.0", true, "74.0")));
+    Condition condition = new Condition("coverage", Condition.Operator.GREATER_THAN, "70.0", "75.0", true);
+    EvaluatedQualityGate gate = EvaluatedQualityGate.newBuilder()
+      .setQualityGate(new QualityGate("G1", "Gate One", singleton(condition)))
+      .setStatus(EvaluatedQualityGate.Status.WARN)
+      .addCondition(condition, EvaluatedCondition.EvaluationStatus.WARN, "74.0")
+      .build();
     ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, emptyMap());
 
     WebhookPayload payload = underTest.create(analysis);
@@ -94,8 +101,13 @@ public class WebhookPayloadFactoryImplTest {
   @Test
   public void create_payload_with_gate_conditions_without_value() {
     CeTask task = new CeTask("#1", CeTask.Status.SUCCESS);
-    QualityGate gate = new QualityGate("G1", "Gate One", QualityGate.Status.WARN, singleton(
-      new QualityGate.Condition(QualityGate.EvaluationStatus.NO_VALUE, "coverage", QualityGate.Operator.GREATER_THAN, "70.0", "75.0", false, null)));
+
+    Condition condition = new Condition("coverage", Condition.Operator.GREATER_THAN, "70.0", "75.0", false);
+    EvaluatedQualityGate gate = EvaluatedQualityGate.newBuilder()
+      .setQualityGate(new QualityGate("G1", "Gate One", singleton(condition)))
+      .setStatus(EvaluatedQualityGate.Status.WARN)
+      .addCondition(condition, EvaluatedCondition.EvaluationStatus.NO_VALUE, null)
+      .build();
     ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, emptyMap());
 
     WebhookPayload payload = underTest.create(analysis);
@@ -132,7 +144,10 @@ public class WebhookPayloadFactoryImplTest {
   @Test
   public void create_payload_with_analysis_properties() {
     CeTask task = new CeTask("#1", CeTask.Status.SUCCESS);
-    QualityGate gate = new QualityGate("G1", "Gate One", QualityGate.Status.WARN, emptySet());
+    EvaluatedQualityGate gate = EvaluatedQualityGate.newBuilder()
+      .setQualityGate(new QualityGate("G1", "Gate One", emptySet()))
+      .setStatus(EvaluatedQualityGate.Status.WARN)
+      .build();
     Map<String, String> scannerProperties = ImmutableMap.of(
       "sonar.analysis.revision", "ab45d24",
       "sonar.analysis.buildNumber", "B123",
@@ -287,7 +302,7 @@ public class WebhookPayloadFactoryImplTest {
         "}");
   }
 
-  private static ProjectAnalysis newAnalysis(@Nullable CeTask task, @Nullable QualityGate gate,
+  private static ProjectAnalysis newAnalysis(@Nullable CeTask task, @Nullable EvaluatedQualityGate gate,
     @Nullable Branch branch, @Nullable Long analysisDate, Map<String, String> scannerProperties) {
     return new ProjectAnalysis(new Project("P1_UUID", PROJECT_KEY, "Project One"), task, analysisDate == null ? null : new Analysis("A_UUID1", analysisDate), branch,
       gate, analysisDate, scannerProperties);