From 1634f0473b650f9949a632797e04b99d67aa598c Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Wed, 6 Feb 2019 08:35:19 -0600 Subject: [PATCH] SONAR-11707 Replace hardcoded QG with project's QG for SLB/PRs --- .../analysis/AnalysisMetadataHolder.java | 9 +++ .../PostProjectAnalysisTasksExecutor.java | 2 +- .../api/posttask/QGToEvaluatedQG.java | 54 ++++++++++++++ .../issue/IssueTrackingDelegator.java | 2 +- .../qualitygate/QualityGateServiceImpl.java | 16 +---- .../source/NewLinesRepository.java | 8 +-- .../step/BuildComponentTreeStep.java | 2 +- .../step/LoadDuplicationsFromReportStep.java | 2 +- .../step/LoadQualityGateStep.java | 31 ++++---- .../step/QualityGateEventsStep.java | 2 +- .../step/ValidateProjectStep.java | 2 +- .../webhook/WebhookPostTask.java | 23 +----- .../issue/IssueTrackingDelegatorTest.java | 4 +- .../QualityGateServiceImplTest.java | 35 ---------- .../step/LoadQualityGateStepTest.java | 39 ++++++++--- .../ShortLivingBranchQualityGate.java | 70 ------------------- .../ShortLivingBranchQualityGateTest.java | 40 ----------- .../live/LiveQualityGateComputerImpl.java | 16 ++--- .../live/LiveQualityGateComputerImplTest.java | 32 ++++++--- 19 files changed, 148 insertions(+), 241 deletions(-) create mode 100644 server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/QGToEvaluatedQG.java delete mode 100644 server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGate.java delete mode 100644 server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGateTest.java diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolder.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolder.java index 7c787c74207..a8506333762 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolder.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolder.java @@ -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()} * diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java index 574695e1223..bf234604874 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java @@ -167,7 +167,7 @@ public class PostProjectAnalysisTasksExecutor implements ComputationStepExecutor } @CheckForNull - private QualityGateImpl createQualityGate() { + private QualityGate createQualityGate() { Optional 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 index 00000000000..77dc404406f --- /dev/null +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/QGToEvaluatedQG.java @@ -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 { + public static final QGToEvaluatedQG INSTANCE = new QGToEvaluatedQG(); + + private QGToEvaluatedQG() { + // static only + } + + @Override public EvaluatedQualityGate apply(QualityGate qg) { + EvaluatedQualityGate.Builder builder = EvaluatedQualityGate.newBuilder(); + Set 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(); + } +} diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegator.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegator.java index fcde1d5941b..b4220a5b7a2 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegator.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegator.java @@ -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 tracking = mergeBranchTracker.track(component); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java index 96ef3e0bd09..7757851e8b2 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java @@ -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 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()))); - } - } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/NewLinesRepository.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/NewLinesRepository.java index c59b4ee12a2..5a8854c8bc3 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/NewLinesRepository.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/NewLinesRepository.java @@ -49,7 +49,7 @@ public class NewLinesRepository { } public boolean newLinesAvailable() { - return isPullRequestOrShortLivedBranch() || periodHolder.hasPeriod(); + return analysisMetadataHolder.isSLBorPR() || periodHolder.hasPeriod(); } public Optional> getNewLines(Component file) { @@ -96,17 +96,13 @@ public class NewLinesRepository { } private Optional> 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> readFromReport(Component file) { return reportReader.readComponentChangedLines(file.getReportAttributes().getRef()) .map(c -> new HashSet<>(c.getLineList())); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java index 09925d5656e..807756a4233 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java @@ -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 { diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadDuplicationsFromReportStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadDuplicationsFromReportStep.java index 1da15fe6b55..0af8338fcfc 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadDuplicationsFromReportStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadDuplicationsFromReportStep.java @@ -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())); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java index b9cadec700e..24432b9d2bc 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java @@ -20,14 +20,15 @@ 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 = getShortLivingBranchQualityGate(); + Optional 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 getShortLivingBranchQualityGate() { - if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) { - Optional 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 filterQGForSLB(Optional qualityGate) { + return qualityGate.map(qg -> new QualityGate(qg.getId(), qg.getName(), + qg.getConditions().stream().filter(Condition::useVariation).collect(Collectors.toList()))); } private Optional getProjectQualityGate() { diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityGateEventsStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityGateEventsStep.java index e6c3555a395..b65e2ce6298 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityGateEventsStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityGateEventsStep.java @@ -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( diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java index 31f4a986985..fab944e408d 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java @@ -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(); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTask.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTask.java index cea109218f1..5976e7a1a6d 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTask.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTask.java @@ -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 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 properties = projectAnalysis.getScannerContext().getProperties(); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegatorTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegatorTest.java index ac60f9964a9..c5a7a14f058 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegatorTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueTrackingDelegatorTest.java @@ -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); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java index 934bf7f99bc..adb3c09fd90 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java @@ -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 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; - } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java index f616279c85d..809c2505fd6 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java @@ -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 index 389e7f008d4..00000000000 --- a/server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGate.java +++ /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 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 index a1d9805f440..00000000000 --- a/server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGateTest.java +++ /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")); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java index 2f6740305a2..95455db3e02 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java @@ -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 metricsById = dbClient.metricDao().selectByIds(dbSession, metricIds).stream() .collect(uniqueIndex(MetricDto::getId)); - Set conditions = conditionDtos.stream().map(conditionDto -> { + Stream 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 diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java index d4097977303..8190195d8ce 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java @@ -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); -- 2.39.5