*/
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()}
*
}
@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();
--- /dev/null
+/*
+ * 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();
+ }
+}
}
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);
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;
@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) {
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())));
- }
-
}
}
public boolean newLinesAvailable() {
- return isPullRequestOrShortLivedBranch() || periodHolder.hasPeriod();
+ return analysisMetadataHolder.isSLBorPR() || periodHolder.hasPeriod();
}
public Optional<Set<Integer>> getNewLines(Component file) {
}
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()));
Component reportTreeRoot = builder.buildProject(reportProject, relativePathFromScmRoot);
- if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) {
+ if (analysisMetadataHolder.isSLBorPR()) {
Component changedComponentTreeRoot = builder.buildChangedComponentTreeRoot(reportTreeRoot);
treeRootHolder.setRoots(changedComponentTreeRoot, reportTreeRoot);
} else {
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()));
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;
@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() {
@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(
}
private void validateTargetBranch(DbSession session) {
- if (!analysisMetadataHolder.isShortLivingBranch() && !analysisMetadataHolder.isPullRequest()) {
+ if (!analysisMetadataHolder.isSLBorPR()) {
return;
}
String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid().get();
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;
import org.sonar.server.webhook.WebhookPayloadFactory;
public class WebhookPostTask implements PostProjectAnalysisTask {
-
private final WebhookPayloadFactory payloadFactory;
private final WebHooks webHooks;
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();
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);
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);
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;
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;
- }
}
*/
package org.sonar.ce.task.projectanalysis.step;
+import java.util.Arrays;
import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
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;
}
@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
+++ /dev/null
-/*
- * 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;
- }
- }
-}
+++ /dev/null
-/*
- * 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"));
- }
-
-}
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;
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;
@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())))
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
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;
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
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);