]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11707 Replace hardcoded QG with project's QG for SLB/PRs
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 6 Feb 2019 14:35:19 +0000 (08:35 -0600)
committerSonarTech <sonartech@sonarsource.com>
Mon, 11 Mar 2019 19:21:02 +0000 (20:21 +0100)
19 files changed:
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolder.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/QGToEvaluatedQG.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegator.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/NewLinesRepository.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadDuplicationsFromReportStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityGateEventsStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTask.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegatorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGate.java [deleted file]
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGateTest.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java
server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java

index 7c787c74207578dfb74076ff56139d67116a38b8..a850633376241f1dea2a671d684485c00cb7bdec 100644 (file)
@@ -77,6 +77,15 @@ public interface AnalysisMetadataHolder {
    */
   boolean isShortLivingBranch();
 
+  /**
+   * Convenience method equivalent to do the check using {@link #getBranch()}
+   *
+   * @throws IllegalStateException if branch has not been set
+   */
+  default boolean isSLBorPR() {
+    return isShortLivingBranch() || isPullRequest();
+  }
+
   /**
    * Convenience method equivalent to do the check using {@link #getBranch()}
    *
index 574695e1223973713973e2b25fcd6ea304c2bdd6..bf2346048744e942a40877f236628dd6f2fa1bbb 100644 (file)
@@ -167,7 +167,7 @@ public class PostProjectAnalysisTasksExecutor implements ComputationStepExecutor
   }
 
   @CheckForNull
-  private QualityGateImpl createQualityGate() {
+  private QualityGate createQualityGate() {
     Optional<org.sonar.ce.task.projectanalysis.qualitygate.QualityGate> qualityGateOptional = this.qualityGateHolder.getQualityGate();
     if (qualityGateOptional.isPresent()) {
       org.sonar.ce.task.projectanalysis.qualitygate.QualityGate qualityGate = qualityGateOptional.get();
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/QGToEvaluatedQG.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/QGToEvaluatedQG.java
new file mode 100644 (file)
index 0000000..77dc404
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.ce.task.projectanalysis.api.posttask;
+
+import java.util.Set;
+import java.util.function.Function;
+import org.sonar.api.ce.posttask.QualityGate;
+import org.sonar.api.measures.Metric;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.server.qualitygate.Condition;
+import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.server.qualitygate.EvaluatedQualityGate;
+
+public class QGToEvaluatedQG implements Function<QualityGate, EvaluatedQualityGate> {
+  public static final QGToEvaluatedQG INSTANCE = new QGToEvaluatedQG();
+
+  private QGToEvaluatedQG() {
+    // static only
+  }
+
+  @Override public EvaluatedQualityGate apply(QualityGate qg) {
+    EvaluatedQualityGate.Builder builder = EvaluatedQualityGate.newBuilder();
+    Set<org.sonar.server.qualitygate.Condition> conditions = qg.getConditions().stream()
+      .map(q -> {
+        org.sonar.server.qualitygate.Condition condition = new org.sonar.server.qualitygate.Condition(q.getMetricKey(), Condition.Operator.valueOf(q.getOperator().name()),
+          q.getErrorThreshold());
+        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(Metric.Level.valueOf(qg.getStatus().name()))
+      .build();
+  }
+}
index fcde1d5941b8c5266a84abda3d517da9139cf16b..b4220a5b7a22cbc82d4da523dad24be60ca9e392 100644 (file)
@@ -44,7 +44,7 @@ public class IssueTrackingDelegator {
   }
 
   public TrackingResult track(Component component) {
-    if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) {
+    if (analysisMetadataHolder.isSLBorPR()) {
       return standardResult(shortBranchOrPullRequestTracker.track(component));
     } else if (isFirstAnalysisSecondaryLongLivingBranch()) {
       Tracking<DefaultIssue, DefaultIssue> tracking = mergeBranchTracker.track(component);
index 96ef3e0bd09b672d64af81f2dcd5beb407f1d27b..7757851e8b23718e41b55bf89ea843efff17e19b 100644 (file)
@@ -22,13 +22,12 @@ package org.sonar.ce.task.projectanalysis.qualitygate;
 import java.util.Collection;
 import java.util.Objects;
 import java.util.Optional;
+import org.sonar.ce.task.projectanalysis.analysis.Organization;
 import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.qualitygate.QualityGateConditionDto;
 import org.sonar.db.qualitygate.QualityGateDto;
-import org.sonar.ce.task.projectanalysis.analysis.Organization;
-import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 
 import static org.sonar.core.util.stream.MoreCollectors.toList;
 
@@ -44,9 +43,6 @@ public class QualityGateServiceImpl implements QualityGateService {
 
   @Override
   public Optional<QualityGate> findById(long id) {
-    if (id == ShortLivingBranchQualityGate.ID) {
-      return Optional.of(buildShortLivingBranchHardcodedQualityGate());
-    }
     try (DbSession dbSession = dbClient.openSession(false)) {
       QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectById(dbSession, id);
       if (qualityGateDto == null) {
@@ -79,14 +75,4 @@ public class QualityGateServiceImpl implements QualityGateService {
 
     return new QualityGate(qualityGateDto.getId(), qualityGateDto.getName(), conditions);
   }
-
-  private QualityGate buildShortLivingBranchHardcodedQualityGate() {
-    return new QualityGate(
-      ShortLivingBranchQualityGate.ID,
-      ShortLivingBranchQualityGate.NAME,
-      ShortLivingBranchQualityGate.CONDITIONS.stream()
-        .map(c -> new Condition(metricRepository.getByKey(c.getMetricKey()), c.getOperator(), c.getErrorThreshold()))
-        .collect(toList(ShortLivingBranchQualityGate.CONDITIONS.size())));
-  }
-
 }
index c59b4ee12a259698a11d48c307d11ca6338d31d1..5a8854c8bc3dbe3025d64003261f6a65847b63bc 100644 (file)
@@ -49,7 +49,7 @@ public class NewLinesRepository {
   }
 
   public boolean newLinesAvailable() {
-    return isPullRequestOrShortLivedBranch() || periodHolder.hasPeriod();
+    return analysisMetadataHolder.isSLBorPR() || periodHolder.hasPeriod();
   }
 
   public Optional<Set<Integer>> getNewLines(Component file) {
@@ -96,17 +96,13 @@ public class NewLinesRepository {
   }
 
   private Optional<Set<Integer>> getChangedLinesFromReport(Component file) {
-    if (isPullRequestOrShortLivedBranch()) {
+    if (analysisMetadataHolder.isSLBorPR()) {
       return reportChangedLinesCache.computeIfAbsent(file, this::readFromReport);
     }
 
     return Optional.empty();
   }
 
-  private boolean isPullRequestOrShortLivedBranch() {
-    return analysisMetadataHolder.isPullRequest() || analysisMetadataHolder.isShortLivingBranch();
-  }
-
   private Optional<Set<Integer>> readFromReport(Component file) {
     return reportReader.readComponentChangedLines(file.getReportAttributes().getRef())
       .map(c -> new HashSet<>(c.getLineList()));
index 09925d5656e887263bb63a09a80b58e56601dd0a..807756a4233805c8ec35b3a880c9f1a006bcc6e2 100644 (file)
@@ -101,7 +101,7 @@ public class BuildComponentTreeStep implements ComputationStep {
 
       Component reportTreeRoot = builder.buildProject(reportProject, relativePathFromScmRoot);
 
-      if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) {
+      if (analysisMetadataHolder.isSLBorPR()) {
         Component changedComponentTreeRoot = builder.buildChangedComponentTreeRoot(reportTreeRoot);
         treeRootHolder.setRoots(changedComponentTreeRoot, reportTreeRoot);
       } else {
index 1da15fe6b55edab3a7e54bfcc18bdfebb8349e85..0af8338fcfcaffbff090bcb881e19408da17e03d 100644 (file)
@@ -85,7 +85,7 @@ public class LoadDuplicationsFromReportStep implements ComputationStep {
       if (input.getOtherFileRef() != 0) {
         checkArgument(input.getOtherFileRef() != file.getReportAttributes().getRef(), "file and otherFile references can not be the same");
         Component otherComponent = treeRootHolder.getReportTreeComponentByRef(input.getOtherFileRef());
-        if ((analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) && otherComponent.getStatus() == Component.Status.SAME) {
+        if (analysisMetadataHolder.isSLBorPR() && otherComponent.getStatus() == Component.Status.SAME) {
           return new InExtendedProjectDuplicate(otherComponent, convert(input.getRange()));
         } else {
           return new InProjectDuplicate(otherComponent, convert(input.getRange()));
index b9cadec700ebbb9fe6984d544720abe02fed0785..24432b9d2bc8322dc15a99b4e55fd057c9cbeb10 100644 (file)
 package org.sonar.ce.task.projectanalysis.step;
 
 import java.util.Optional;
+import java.util.stream.Collectors;
 import org.sonar.api.config.Configuration;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository;
+import org.sonar.ce.task.projectanalysis.qualitygate.Condition;
 import org.sonar.ce.task.projectanalysis.qualitygate.MutableQualityGateHolder;
 import org.sonar.ce.task.projectanalysis.qualitygate.QualityGate;
 import org.sonar.ce.task.projectanalysis.qualitygate.QualityGateService;
 import org.sonar.ce.task.step.ComputationStep;
-import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 
 import static org.apache.commons.lang.StringUtils.isBlank;
 
@@ -53,30 +54,22 @@ public class LoadQualityGateStep implements ComputationStep {
 
   @Override
   public void execute(ComputationStep.Context context) {
-    Optional<QualityGate> qualityGate = getShortLivingBranchQualityGate();
+    Optional<QualityGate> qualityGate = getProjectQualityGate();
     if (!qualityGate.isPresent()) {
-      // Not on a short living branch, let's retrieve the QG of the project
-      qualityGate = getProjectQualityGate();
-      if (!qualityGate.isPresent()) {
-        // No QG defined for the project, let's retrieve the QG on the organization
-        qualityGate = Optional.of(getOrganizationDefaultQualityGate());
-      }
+      // No QG defined for the project, let's retrieve the QG on the organization
+      qualityGate = Optional.of(getOrganizationDefaultQualityGate());
+    }
+
+    if (analysisMetadataHolder.isSLBorPR()) {
+      qualityGate = filterQGForSLB(qualityGate);
     }
 
     qualityGateHolder.setQualityGate(qualityGate.orElseThrow(() -> new IllegalStateException("Quality gate not present")));
   }
 
-  private Optional<QualityGate> getShortLivingBranchQualityGate() {
-    if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) {
-      Optional<QualityGate> qualityGate = qualityGateService.findById(ShortLivingBranchQualityGate.ID);
-      if (qualityGate.isPresent()) {
-        return qualityGate;
-      } else {
-        throw new IllegalStateException("Failed to retrieve hardcoded short living branch Quality Gate");
-      }
-    } else {
-      return Optional.empty();
-    }
+  private static Optional<QualityGate> filterQGForSLB(Optional<QualityGate> qualityGate) {
+    return qualityGate.map(qg -> new QualityGate(qg.getId(), qg.getName(),
+      qg.getConditions().stream().filter(Condition::useVariation).collect(Collectors.toList())));
   }
 
   private Optional<QualityGate> getProjectQualityGate() {
index e6c3555a3954a6b93b55ca93b0be81b941186940..b65e2ce6298b090bb2b99e87b28fae69dc9ca770 100644 (file)
@@ -70,7 +70,7 @@ public class QualityGateEventsStep implements ComputationStep {
   @Override
   public void execute(ComputationStep.Context context) {
     // no notification on short living branch and pull request as there is no real Quality Gate on those
-    if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) {
+    if (analysisMetadataHolder.isSLBorPR()) {
       return;
     }
     new DepthTraversalTypeAwareCrawler(
index 31f4a986985249cfec023bb432d6dbeb008925f5..fab944e408d0ab7f7741ea04bef763773ba406a5 100644 (file)
@@ -88,7 +88,7 @@ public class ValidateProjectStep implements ComputationStep {
   }
 
   private void validateTargetBranch(DbSession session) {
-    if (!analysisMetadataHolder.isShortLivingBranch() && !analysisMetadataHolder.isPullRequest()) {
+    if (!analysisMetadataHolder.isSLBorPR()) {
       return;
     }
     String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid().get();
index cea109218f169469204ca40b679a9d89411ee9a3..5976e7a1a6d8ca8fed34e6b2d866f34caf472d5c 100644 (file)
@@ -21,12 +21,8 @@ package org.sonar.ce.task.projectanalysis.webhook;
 
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 import org.sonar.api.ce.posttask.PostProjectAnalysisTask;
-import org.sonar.api.measures.Metric;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.server.qualitygate.Condition;
-import org.sonar.server.qualitygate.EvaluatedCondition;
+import org.sonar.ce.task.projectanalysis.api.posttask.QGToEvaluatedQG;
 import org.sonar.server.qualitygate.EvaluatedQualityGate;
 import org.sonar.server.webhook.Analysis;
 import org.sonar.server.webhook.Branch;
@@ -36,7 +32,6 @@ import org.sonar.server.webhook.WebHooks;
 import org.sonar.server.webhook.WebhookPayloadFactory;
 
 public class WebhookPostTask implements PostProjectAnalysisTask {
-
   private final WebhookPayloadFactory payloadFactory;
   private final WebHooks webHooks;
 
@@ -60,21 +55,7 @@ public class WebhookPostTask implements PostProjectAnalysisTask {
     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);
     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());
-            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(Metric.Level.valueOf(qg.getStatus().name()))
-          .build();
-      })
+      .map(QGToEvaluatedQG.INSTANCE)
       .orElse(null);
     Long date = projectAnalysis.getAnalysis().map(a -> a.getDate().getTime()).orElse(null);
     Map<String, String> properties = projectAnalysis.getScannerContext().getProperties();
index ac60f9964a95abdf635a7d2b26968f5727a27bcf..c5a7a14f05858b4c8fc14dac01fe2f40f1978742 100644 (file)
@@ -93,7 +93,7 @@ public class IssueTrackingDelegatorTest {
     Branch branch = mock(Branch.class);
     when(branch.getType()).thenReturn(BranchType.SHORT);
     when(analysisMetadataHolder.getBranch()).thenReturn(mock(Branch.class));
-    when(analysisMetadataHolder.isShortLivingBranch()).thenReturn(true);
+    when(analysisMetadataHolder.isSLBorPR()).thenReturn(true);
 
     underTest.track(component);
 
@@ -107,7 +107,7 @@ public class IssueTrackingDelegatorTest {
     Branch branch = mock(Branch.class);
     when(branch.getType()).thenReturn(BranchType.PULL_REQUEST);
     when(analysisMetadataHolder.getBranch()).thenReturn(mock(Branch.class));
-    when(analysisMetadataHolder.isShortLivingBranch()).thenReturn(true);
+    when(analysisMetadataHolder.isSLBorPR()).thenReturn(true);
 
     underTest.track(component);
 
index 934bf7f99bc62d588f5d4e340757c6b6d34671c6..adb3c09fd9001308afb05a629bf16d911491a994 100644 (file)
@@ -22,28 +22,21 @@ package org.sonar.ce.task.projectanalysis.qualitygate;
 import com.google.common.collect.ImmutableList;
 import java.util.Collections;
 import java.util.Optional;
-import java.util.Random;
-import org.apache.commons.lang.RandomStringUtils;
 import org.junit.Before;
 import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
 import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.metric.MetricImpl;
 import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
 import org.sonar.db.DbClient;
 import org.sonar.db.qualitygate.QualityGateConditionDao;
 import org.sonar.db.qualitygate.QualityGateConditionDto;
 import org.sonar.db.qualitygate.QualityGateDao;
 import org.sonar.db.qualitygate.QualityGateDto;
-import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.sonar.ce.task.projectanalysis.qualitygate.Condition.Operator.GREATER_THAN;
 
 public class QualityGateServiceImplTest {
   private static final long SOME_ID = 123;
@@ -124,32 +117,4 @@ public class QualityGateServiceImplTest {
     assertThat(res.get().getConditions()).containsOnly(
       new Condition(METRIC_2, CONDITION_2.getOperator(), CONDITION_2.getErrorThreshold()));
   }
-
-  @Test
-  public void findById_of_hardcoded_short_living_branch_returns_hardcoded_qg() {
-    MetricImpl bugsMetric = mockMetricInRepository(CoreMetrics.BUGS_KEY);
-    MetricImpl vulnerabilitiesMetric = mockMetricInRepository(CoreMetrics.VULNERABILITIES_KEY);
-    MetricImpl codeSmellsMetric = mockMetricInRepository(CoreMetrics.CODE_SMELLS_KEY);
-    MetricImpl openedIssueMetric = mockMetricInRepository(CoreMetrics.OPEN_ISSUES_KEY);
-    MetricImpl reOpenedIssueMetric = mockMetricInRepository(CoreMetrics.REOPENED_ISSUES_KEY);
-
-    Optional<QualityGate> res = underTest.findById(ShortLivingBranchQualityGate.ID);
-
-    assertThat(res).isPresent();
-    QualityGate qualityGate = res.get();
-    assertThat(qualityGate.getId()).isEqualTo(ShortLivingBranchQualityGate.ID);
-    assertThat(qualityGate.getName()).isEqualTo("Hardcoded short living branch quality gate");
-    assertThat(qualityGate.getConditions())
-      .extracting(Condition::getMetric, Condition::getOperator, Condition::getErrorThreshold)
-      .containsOnly(
-        tuple(openedIssueMetric, GREATER_THAN, "0"),
-        tuple(reOpenedIssueMetric, GREATER_THAN, "0"));
-  }
-
-  private MetricImpl mockMetricInRepository(String metricKey) {
-    MetricImpl metric = new MetricImpl(new Random().nextInt(999), metricKey, RandomStringUtils.randomAlphanumeric(20), Metric.MetricType.INT);
-    when(metricRepository.getByKey(metricKey))
-      .thenReturn(metric);
-    return metric;
-  }
 }
index f616279c85da3f694943c6e416c26e4fabbe7e2c..809c2505fd6038dd8f5287aa4efe9ecdae56b1c6 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.ce.task.projectanalysis.step;
 
+import java.util.Arrays;
 import java.util.Optional;
 import org.junit.Before;
 import org.junit.Rule;
@@ -27,11 +28,13 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository;
+import org.sonar.ce.task.projectanalysis.metric.Metric;
+import org.sonar.ce.task.projectanalysis.metric.MetricImpl;
+import org.sonar.ce.task.projectanalysis.qualitygate.Condition;
 import org.sonar.ce.task.projectanalysis.qualitygate.MutableQualityGateHolderRule;
 import org.sonar.ce.task.projectanalysis.qualitygate.QualityGate;
 import org.sonar.ce.task.projectanalysis.qualitygate.QualityGateService;
 import org.sonar.ce.task.step.TestComputationStepContext;
-import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 
 import static java.util.Collections.emptyList;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -58,25 +61,39 @@ public class LoadQualityGateStepTest {
   }
 
   @Test
-  public void add_hardcoded_QG_on_short_living_branch() {
-    when(analysisMetadataHolder.isShortLivingBranch()).thenReturn(true);
-    QualityGate qualityGate = mock(QualityGate.class);
-    when(qualityGateService.findById(ShortLivingBranchQualityGate.ID)).thenReturn(Optional.of(qualityGate));
+  public void filter_conditions_on_short_living_branch() {
+    when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig());
+
+    Metric newMetric = new MetricImpl(1, "new_key", "name", Metric.MetricType.INT);
+    Metric metric = new MetricImpl(2, "key", "name", Metric.MetricType.INT);
+    Condition variation = new Condition(newMetric, Condition.Operator.GREATER_THAN.getDbValue(), "1.0");
+    Condition condition = new Condition(metric, Condition.Operator.GREATER_THAN.getDbValue(), "1.0");
+
+    when(analysisMetadataHolder.isSLBorPR()).thenReturn(true);
+    QualityGate defaultGate = new QualityGate(1, "qg", Arrays.asList(variation, condition));
+    when(qualityGateService.findDefaultQualityGate(any())).thenReturn(defaultGate);
 
     underTest.execute(new TestComputationStepContext());
 
-    assertThat(mutableQualityGateHolder.getQualityGate().get()).isSameAs(qualityGate);
+    assertThat(mutableQualityGateHolder.getQualityGate().get().getConditions()).containsExactly(variation);
   }
 
   @Test
-  public void add_hardcoded_QG_on_pull_request() {
-    when(analysisMetadataHolder.isPullRequest()).thenReturn(true);
-    QualityGate qualityGate = mock(QualityGate.class);
-    when(qualityGateService.findById(ShortLivingBranchQualityGate.ID)).thenReturn(Optional.of(qualityGate));
+  public void filter_conditions_on_pull_request() {
+    when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig());
+
+    Metric newMetric = new MetricImpl(1, "new_key", "name", Metric.MetricType.INT);
+    Metric metric = new MetricImpl(2, "key", "name", Metric.MetricType.INT);
+    Condition variation = new Condition(newMetric, Condition.Operator.GREATER_THAN.getDbValue(), "1.0");
+    Condition condition = new Condition(metric, Condition.Operator.GREATER_THAN.getDbValue(), "1.0");
+
+    when(analysisMetadataHolder.isSLBorPR()).thenReturn(true);
+    QualityGate defaultGate = new QualityGate(1, "qg", Arrays.asList(variation, condition));
+    when(qualityGateService.findDefaultQualityGate(any())).thenReturn(defaultGate);
 
     underTest.execute(new TestComputationStepContext());
 
-    assertThat(mutableQualityGateHolder.getQualityGate().get()).isSameAs(qualityGate);
+    assertThat(mutableQualityGateHolder.getQualityGate().get().getConditions()).containsExactly(variation);
   }
 
   @Test
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGate.java b/server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGate.java
deleted file mode 100644 (file)
index 389e7f0..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.qualitygate;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import java.util.List;
-import org.sonar.api.measures.CoreMetrics;
-
-import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN;
-
-/**
- * Offers constants describing the Hardcoded Quality Gate for short living branches and pull requests.
- */
-public final class ShortLivingBranchQualityGate {
-  public static final long ID = -1_963_456_987L;
-  public static final String NAME = "Hardcoded short living branch quality gate";
-  public static final List<Condition> CONDITIONS = ImmutableList.of(
-    new Condition(CoreMetrics.OPEN_ISSUES_KEY, OPERATOR_GREATER_THAN, "0"),
-    new Condition(CoreMetrics.REOPENED_ISSUES_KEY, OPERATOR_GREATER_THAN, "0"));
-
-  public static final QualityGate GATE = new QualityGate(String.valueOf(ID), NAME, ImmutableSet.of(
-    new org.sonar.server.qualitygate.Condition(CoreMetrics.OPEN_ISSUES_KEY, org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN, "0"),
-    new org.sonar.server.qualitygate.Condition(CoreMetrics.REOPENED_ISSUES_KEY, org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN, "0")));
-
-  private ShortLivingBranchQualityGate() {
-    // prevents instantiation
-  }
-
-  public static final class Condition {
-    private final String metricKey;
-    private final String operator;
-    private final String errorThreshold;
-
-    public Condition(String metricKey, String operator, String errorThreshold) {
-      this.metricKey = metricKey;
-      this.operator = operator;
-      this.errorThreshold = errorThreshold;
-    }
-
-    public String getMetricKey() {
-      return metricKey;
-    }
-
-    public String getOperator() {
-      return operator;
-    }
-
-    public String getErrorThreshold() {
-      return errorThreshold;
-    }
-  }
-}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGateTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGateTest.java
deleted file mode 100644 (file)
index a1d9805..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.qualitygate;
-
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.server.qualitygate.ShortLivingBranchQualityGate.Condition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-
-public class ShortLivingBranchQualityGateTest {
-
-  @Test
-  public void defines_short_living_branches_hardcoded_quality_gate_conditions() {
-    assertThat(ShortLivingBranchQualityGate.CONDITIONS)
-      .extracting(Condition::getMetricKey, Condition::getOperator, Condition::getErrorThreshold)
-      .containsExactly(
-        tuple(CoreMetrics.OPEN_ISSUES_KEY, "GT", "0"),
-        tuple(CoreMetrics.REOPENED_ISSUES_KEY, "GT", "0"));
-  }
-
-}
index 2f6740305a247ca695da7a878590f0eda23364a1..95455db3e02a18284f31924f69e95c3c7e49df8d 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.OptionalDouble;
 import java.util.Set;
+import java.util.stream.Stream;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric;
 import org.sonar.db.DbClient;
@@ -43,7 +44,6 @@ import org.sonar.server.qualitygate.QualityGate;
 import org.sonar.server.qualitygate.QualityGateConverter;
 import org.sonar.server.qualitygate.QualityGateEvaluator;
 import org.sonar.server.qualitygate.QualityGateFinder;
-import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 
 import static java.lang.String.format;
 import static org.sonar.core.util.stream.MoreCollectors.toHashSet;
@@ -63,10 +63,6 @@ public class LiveQualityGateComputerImpl implements LiveQualityGateComputer {
 
   @Override
   public QualityGate loadQualityGate(DbSession dbSession, OrganizationDto organization, ComponentDto project, BranchDto branch) {
-    if (branch.getBranchType() == BranchType.SHORT || branch.getBranchType() == BranchType.PULL_REQUEST) {
-      return ShortLivingBranchQualityGate.GATE;
-    }
-
     ComponentDto mainProject = project.getMainBranchProjectUuid() == null ? project : dbClient.componentDao().selectOrFailByKey(dbSession, project.getKey());
     QualityGateDto gateDto = qGateFinder.getQualityGate(dbSession, organization, mainProject)
       .orElseThrow(() -> new IllegalStateException(format("Quality Gate not found for project %s", mainProject.getKey())))
@@ -77,13 +73,17 @@ public class LiveQualityGateComputerImpl implements LiveQualityGateComputer {
     Map<Integer, MetricDto> metricsById = dbClient.metricDao().selectByIds(dbSession, metricIds).stream()
       .collect(uniqueIndex(MetricDto::getId));
 
-    Set<Condition> conditions = conditionDtos.stream().map(conditionDto -> {
+    Stream<Condition> conditions = conditionDtos.stream().map(conditionDto -> {
       String metricKey = metricsById.get((int) conditionDto.getMetricId()).getKey();
       Condition.Operator operator = Condition.Operator.fromDbValue(conditionDto.getOperator());
       return new Condition(metricKey, operator, conditionDto.getErrorThreshold());
-    }).collect(toHashSet(conditionDtos.size()));
+    });
+
+    if (branch.getBranchType() == BranchType.PULL_REQUEST || branch.getBranchType() == BranchType.SHORT) {
+      conditions = conditions.filter(Condition::isOnLeakPeriod);
+    }
 
-    return new QualityGate(String.valueOf(gateDto.getId()), gateDto.getName(), conditions);
+    return new QualityGate(String.valueOf(gateDto.getId()), gateDto.getName(), conditions.collect(toHashSet(conditionDtos.size())));
   }
 
   @Override
index d4097977303c6021e2335379b076ff33d46ae901..8190195d8ce68c4abb6cb6cec9c08eef37c6b3f7 100644 (file)
@@ -44,7 +44,6 @@ import org.sonar.server.qualitygate.EvaluatedQualityGate;
 import org.sonar.server.qualitygate.QualityGate;
 import org.sonar.server.qualitygate.QualityGateEvaluator;
 import org.sonar.server.qualitygate.QualityGateFinder;
-import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Arrays.asList;
@@ -71,24 +70,40 @@ public class LiveQualityGateComputerImplTest {
   public void loadQualityGate_returns_hardcoded_gate_for_short_living_branches() {
     OrganizationDto organization = db.organizations().insert();
     ComponentDto project = db.components().insertPublicProject(organization);
+
     BranchDto branch = newBranchDto(project).setBranchType(BranchType.SHORT);
     db.components().insertProjectBranch(project, branch);
+    MetricDto metric1 = db.measures().insertMetric(m -> m.setKey("new_metric"));
+    MetricDto metric2 = db.measures().insertMetric(m -> m.setKey("metric"));
 
-    QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, branch);
+    QGateWithOrgDto gate = db.qualityGates().insertQualityGate(organization);
+    db.qualityGates().setDefaultQualityGate(organization, gate);
 
-    assertThat(result).isSameAs(ShortLivingBranchQualityGate.GATE);
+    db.qualityGates().addCondition(gate, metric1);
+    db.qualityGates().addCondition(gate, metric2);
+
+    QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, branch);
+    assertThat(result.getConditions()).extracting(Condition::getMetricKey).containsExactly("new_metric");
   }
 
   @Test
   public void loadQualityGate_returns_hardcoded_gate_for_pull_requests() {
     OrganizationDto organization = db.organizations().insert();
     ComponentDto project = db.components().insertPublicProject(organization);
-    BranchDto pullRequest = newBranchDto(project).setBranchType(BranchType.PULL_REQUEST);
-    db.components().insertProjectBranch(project, pullRequest);
 
-    QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, pullRequest);
+    BranchDto branch = newBranchDto(project).setBranchType(BranchType.SHORT);
+    db.components().insertProjectBranch(project, branch);
+    MetricDto metric1 = db.measures().insertMetric(m -> m.setKey("new_metric"));
+    MetricDto metric2 = db.measures().insertMetric(m -> m.setKey("metric"));
+
+    QGateWithOrgDto gate = db.qualityGates().insertQualityGate(organization);
+    db.qualityGates().setDefaultQualityGate(organization, gate);
+
+    db.qualityGates().addCondition(gate, metric1);
+    db.qualityGates().addCondition(gate, metric2);
 
-    assertThat(result).isSameAs(ShortLivingBranchQualityGate.GATE);
+    QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, branch);
+    assertThat(result.getConditions()).extracting(Condition::getMetricKey).containsExactly("new_metric");
   }
 
   @Test
@@ -164,7 +179,8 @@ public class LiveQualityGateComputerImplTest {
     LiveMeasureDto numericMeasure = new LiveMeasureDto().setMetricId(numericMetric.getId()).setValue(1.23).setVariation(4.56).setComponentUuid(project.uuid());
     LiveMeasureDto numericNewMeasure = new LiveMeasureDto().setMetricId(numericNewMetric.getId()).setValue(7.8).setVariation(8.9).setComponentUuid(project.uuid());
     LiveMeasureDto stringMeasure = new LiveMeasureDto().setMetricId(stringMetric.getId()).setData("bar").setComponentUuid(project.uuid());
-    MeasureMatrix matrix = new MeasureMatrix(singleton(project), asList(statusMetric, detailsMetric, numericMetric, numericNewMetric, stringMetric), asList(numericMeasure, numericNewMeasure, stringMeasure));
+    MeasureMatrix matrix = new MeasureMatrix(singleton(project), asList(statusMetric, detailsMetric, numericMetric, numericNewMetric, stringMetric),
+      asList(numericMeasure, numericNewMeasure, stringMeasure));
 
     underTest.refreshGateStatus(project, gate, matrix);