public final class LoadedTemplateDto {
- public static final String QUALITY_GATE_TYPE = "QUALITY_GATE";
public static final String ONE_SHOT_TASK_TYPE = "ONE_SHOT_TASK";
private Long id;
return metricKey;
}
- public QualityGateConditionDto setMetricKey(String metricKey) {
+ public QualityGateConditionDto setMetricKey(@Nullable String metricKey) {
this.metricKey = metricKey;
return this;
}
mapper(session).update(qGate.setUpdatedAt(new Date()));
}
+ public void ensureOneBuiltInQualityGate(DbSession dbSession, String builtInName) {
+ mapper(dbSession).ensureOneBuiltInQualityGate(builtInName);
+ }
+
private static QualityGateMapper mapper(DbSession session) {
return session.getMapper(QualityGateMapper.class);
}
void delete(long id);
void update(QualityGateDto qGate);
+
+ void ensureOneBuiltInQualityGate(String builtInQualityName);
}
<update id="update" parameterType="QualityGate">
update quality_gates set
name=#{name},
+ is_built_in=#{isBuiltIn},
updated_at=#{updatedAt}
where id=#{id}
</update>
+ <update id="ensureOneBuiltInQualityGate" parameterType="string">
+ UPDATE quality_gates
+ SET
+ is_built_in=${_false}
+ WHERE
+ is_built_in=${_true} AND name <> #{builtInQualityName}
+ </update>
+
</mapper>
package org.sonar.server.qualitygate;
import java.util.Optional;
-import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.qualitygate.QualityGateDto;
-import static org.apache.commons.lang.StringUtils.isBlank;
import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
import static org.sonar.server.ws.WsUtils.checkFound;
if (qualityGateId.isPresent()) {
return Optional.of(new QualityGateData(getById(dbSession, qualityGateId.get()), false));
} else {
- QualityGateDto defaultQualityGate = getDefault(dbSession);
- if (defaultQualityGate == null) {
+ Optional<QualityGateDto> defaultQualityGate = getDefault(dbSession);
+ if (!defaultQualityGate.isPresent()) {
return Optional.empty();
}
- return Optional.of(new QualityGateData(defaultQualityGate, true));
+ return Optional.of(new QualityGateData(defaultQualityGate.get(), true));
}
}
throw new IllegalArgumentException("No parameter has been set to identify a quality gate");
}
- @CheckForNull
- private QualityGateDto getDefault(DbSession dbSession) {
- Long defaultId = getDefaultId(dbSession);
- if (defaultId == null) {
- return null;
+ public Optional<QualityGateDto> getDefault(DbSession dbSession) {
+ Optional<Long> defaultQualityGateId = getDefaultId(dbSession);
+
+ if (!defaultQualityGateId.isPresent()) {
+ // For the moment, it's possible to have no default quality gate, but it will change with SONAR-8507
+ return Optional.empty();
+ } else {
+ return Optional.ofNullable(
+ dbClient.qualityGateDao().selectById(dbSession, defaultQualityGateId.get()));
}
- return getById(dbSession, defaultId);
}
- @CheckForNull
- private Long getDefaultId(DbSession dbSession) {
- PropertyDto defaultQgate = dbClient.propertiesDao().selectGlobalProperty(dbSession, SONAR_QUALITYGATE_PROPERTY);
- if (defaultQgate == null || isBlank(defaultQgate.getValue())) {
+ private Optional<Long> getDefaultId(DbSession dbSession) {
+ PropertyDto defaultQualityGateId = dbClient.propertiesDao().selectGlobalProperty(dbSession, SONAR_QUALITYGATE_PROPERTY);
+
+ if (defaultQualityGateId == null || StringUtils.isBlank(defaultQualityGateId.getValue())) {
// For the moment, it's possible to have no default quality gate, but it will change with SONAR-8507
- return null;
+ return Optional.empty();
}
- return Long.valueOf(defaultQgate.getValue());
+
+ return Optional.of(Long.valueOf(defaultQualityGateId.getValue()));
}
public static class QualityGateData {
import javax.annotation.Nullable;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.property.PropertyDto;
import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.util.Validation;
import static com.google.common.base.Strings.isNullOrEmpty;
public class QualityGateUpdater {
+ public static final String SONAR_QUALITYGATE_PROPERTY = "sonar.qualitygate";
+
private final DbClient dbClient;
public QualityGateUpdater(DbClient dbClient) {
return newQualityGate;
}
+ public void setDefault(DbSession dbSession, @Nullable QualityGateDto qualityGateDto) {
+ if (qualityGateDto == null) {
+ dbClient.propertiesDao().deleteGlobalProperty(SONAR_QUALITYGATE_PROPERTY, dbSession);
+ } else {
+ checkQualityGateExistence(dbSession, qualityGateDto.getId());
+ dbClient.propertiesDao().saveProperty(dbSession,
+ new PropertyDto().setKey(SONAR_QUALITYGATE_PROPERTY).setValue(qualityGateDto.getId().toString()));
+ }
+ }
+
+ private void checkQualityGateExistence(DbSession dbSession, @Nullable Long qualityGateId) {
+ if (qualityGateId == null ||
+ dbClient.qualityGateDao().selectById(dbSession, qualityGateId) == null) {
+ throw new NotFoundException("There is no quality gate with id=" + qualityGateId);
+ }
+ }
+
private void validateQualityGate(DbSession dbSession, @Nullable Long qGateId, @Nullable String name) {
List<String> errors = new ArrayList<>();
if (isNullOrEmpty(name)) {
}
}
+ /**
+ * Use {@link QualityGateUpdater#setDefault(DbSession, QualityGateDto)}
+ * @deprecated
+ */
+ @Deprecated
public void setDefault(DbSession dbSession, @Nullable Long idToUseAsDefault) {
checkIsQualityGateAdministrator();
if (idToUseAsDefault == null) {
}
}
+ /**
+ * Use {@link QualityGateUpdater#setDefault(DbSession, QualityGateDto)}
+ * @deprecated
+ */
+ @Deprecated
public void setDefault(@Nullable Long idToUseAsDefault) {
try (DbSession dbSession = dbClient.openSession(false)) {
setDefault(dbSession, idToUseAsDefault);
*/
package org.sonar.server.qualitygate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.picocontainer.Startable;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.db.loadedtemplate.LoadedTemplateDao;
-import org.sonar.db.loadedtemplate.LoadedTemplateDto;
+import org.sonar.db.metric.MetricDto;
+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.computation.task.projectanalysis.qualitymodel.RatingGrid;
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toMap;
import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
public class RegisterQualityGates implements Startable {
- private static final String BUILTIN_QUALITY_GATE = "SonarQube way";
+ private static final Logger LOGGER = Loggers.get(RegisterQualityGates.class);
+
+ private static final String BUILTIN_QUALITY_GATE_NAME = "Sonar way";
private static final int LEAK_PERIOD = 1;
+ private static final String A_RATING = Integer.toString(RatingGrid.Rating.A.getIndex());
+
+ private static final List<QualityGateCondition> QUALITY_GATE_CONDITIONS = asList(
+ new QualityGateCondition().setMetricKey(NEW_SECURITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold(A_RATING),
+ new QualityGateCondition().setMetricKey(NEW_RELIABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold(A_RATING),
+ new QualityGateCondition().setMetricKey(NEW_MAINTAINABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold(A_RATING),
+ new QualityGateCondition().setMetricKey(NEW_COVERAGE_KEY).setOperator(OPERATOR_LESS_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold("80"),
+ new QualityGateCondition().setMetricKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold("3")
+ );
private final DbClient dbClient;
private final QualityGateConditionsUpdater qualityGateConditionsUpdater;
- private final LoadedTemplateDao loadedTemplateDao;
- private final QualityGates qualityGates;
+ private final QualityGateFinder qualityGateFinder;
+ private final QualityGateUpdater qualityGateUpdater;
+ private final QualityGateDao qualityGateDao;
+ private final QualityGateConditionDao qualityGateConditionDao;
+ private final System2 system2;
- public RegisterQualityGates(DbClient dbClient, QualityGateConditionsUpdater qualityGateConditionsUpdater,
- LoadedTemplateDao loadedTemplateDao, QualityGates qualityGates) {
+ public RegisterQualityGates(DbClient dbClient, QualityGateUpdater qualityGateUpdater,
+ QualityGateConditionsUpdater qualityGateConditionsUpdater, QualityGateFinder qualityGateFinder, System2 system2) {
this.dbClient = dbClient;
this.qualityGateConditionsUpdater = qualityGateConditionsUpdater;
- this.loadedTemplateDao = loadedTemplateDao;
- this.qualityGates = qualityGates;
+ this.qualityGateUpdater = qualityGateUpdater;
+ this.qualityGateFinder = qualityGateFinder;
+ this.qualityGateDao = dbClient.qualityGateDao();
+ this.qualityGateConditionDao = dbClient.gateConditionDao();
+ this.system2 = system2;
}
@Override
public void start() {
try (DbSession dbSession = dbClient.openSession(false)) {
- if (shouldRegisterBuiltinQualityGate(dbSession)) {
- createBuiltinQualityGate(dbSession);
- registerBuiltinQualityGate(dbSession);
- dbSession.commit();
+ QualityGateDto builtin = qualityGateDao.selectByName(dbSession, BUILTIN_QUALITY_GATE_NAME);
+
+ // Create builtin if not present
+ if (builtin == null) {
+ LOGGER.info("Built-in quality gate [{}] has been created", BUILTIN_QUALITY_GATE_NAME);
+ builtin = createQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME);
+ }
+
+ // Set builtin as default if there is no default
+ if (!qualityGateFinder.getDefault(dbSession).isPresent()) {
+ LOGGER.info("Built-in quality gate [{}] has been set as default", BUILTIN_QUALITY_GATE_NAME);
+ qualityGateUpdater.setDefault(dbSession, builtin);
+ }
+
+ // Set builtin if missing
+ if (!builtin.isBuiltIn()) {
+ builtin.setBuiltIn(true);
+ dbClient.qualityGateDao().update(builtin, dbSession);
+ LOGGER.info("Quality gate [{}] has been set as built-in", BUILTIN_QUALITY_GATE_NAME);
}
+
+ updateQualityConditionsIfRequired(dbSession, builtin);
+
+ qualityGateDao.ensureOneBuiltInQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME);
+
+ dbSession.commit();
}
}
- @Override
- public void stop() {
- // do nothing
- }
+ private void updateQualityConditionsIfRequired(DbSession dbSession, QualityGateDto builtin) {
+ Map<Long, String> idToKeyMetric = dbClient.metricDao().selectAll(dbSession).stream()
+ .collect(toMap(metricDto -> metricDto.getId().longValue(), MetricDto::getKey));
- private boolean shouldRegisterBuiltinQualityGate(DbSession dbSession) {
- return loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.QUALITY_GATE_TYPE, BUILTIN_QUALITY_GATE, dbSession) == 0;
+ List<QualityGateCondition> qualityGateConditions = qualityGateConditionDao.selectForQualityGate(dbSession, builtin.getId())
+ .stream()
+ .map(dto -> QualityGateCondition.from(dto, idToKeyMetric))
+ .collect(MoreCollectors.toList());
+
+ // Find all conditions that are not present in QUALITY_GATE_CONDITIONS
+ // Those conditions must be deleted
+ List<QualityGateCondition> qgConditionsToBeDeleted = new ArrayList<>(qualityGateConditions);
+ qgConditionsToBeDeleted.removeAll(QUALITY_GATE_CONDITIONS);
+ qgConditionsToBeDeleted.stream()
+ .forEach(qgc -> qualityGateConditionDao.delete(qgc.toQualityGateDto(builtin.getId()), dbSession));
+
+ // Find all conditions that are not present in qualityGateConditions
+ // Those conditions must be created
+ List<QualityGateCondition> qgConditionsToBeCreated = new ArrayList<>(QUALITY_GATE_CONDITIONS);
+ qgConditionsToBeCreated.removeAll(qualityGateConditions);
+ qgConditionsToBeCreated.stream()
+ .forEach(qgc ->
+ qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(), qgc.getMetricKey(), qgc.getOperator(), qgc.getWarningThreshold(),
+ qgc.getErrorThreshold(), qgc.getPeriod())
+ );
+
+ if (!qgConditionsToBeCreated.isEmpty() || !qgConditionsToBeDeleted.isEmpty()) {
+ LOGGER.info("Built-in quality gate's conditions of [{}] has been updated", BUILTIN_QUALITY_GATE_NAME);
+ }
}
- private void createBuiltinQualityGate(DbSession dbSession) {
- String ratingAValue = Integer.toString(RatingGrid.Rating.A.getIndex());
- QualityGateDto builtin = createQualityGate(dbSession, BUILTIN_QUALITY_GATE);
- qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
- NEW_SECURITY_RATING_KEY, OPERATOR_GREATER_THAN, null, ratingAValue, LEAK_PERIOD);
- qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
- NEW_RELIABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, ratingAValue, LEAK_PERIOD);
- qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
- NEW_MAINTAINABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, ratingAValue, LEAK_PERIOD);
- qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
- NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, null, "80", LEAK_PERIOD);
- qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
- NEW_DUPLICATED_LINES_DENSITY_KEY, OPERATOR_GREATER_THAN, null, "3", LEAK_PERIOD);
- qualityGates.setDefault(dbSession, builtin.getId());
+ @Override
+ public void stop() {
+ // do nothing
}
- private QualityGateDto createQualityGate(DbSession dbSession, String name){
+ private QualityGateDto createQualityGate(DbSession dbSession, String name) {
QualityGateDto qualityGate = new QualityGateDto()
.setName(name)
- .setBuiltIn(true);
- dbClient.qualityGateDao().insert(dbSession, qualityGate);
- return qualityGate;
+ .setBuiltIn(true)
+ .setCreatedAt(new Date(system2.now()));
+ return dbClient.qualityGateDao().insert(dbSession, qualityGate);
}
- private void registerBuiltinQualityGate(DbSession dbSession) {
- loadedTemplateDao.insert(new LoadedTemplateDto(BUILTIN_QUALITY_GATE, LoadedTemplateDto.QUALITY_GATE_TYPE), dbSession);
+ private static class QualityGateCondition {
+ private Long id;
+ private String metricKey;
+ private Integer period;
+ private String operator;
+ private String warningThreshold;
+ private String errorThreshold;
+
+ public static QualityGateCondition from(QualityGateConditionDto qualityGateConditionDto, Map<Long, String> mapping) {
+ return new QualityGateCondition()
+ .setId(qualityGateConditionDto.getId())
+ .setMetricKey(mapping.get(qualityGateConditionDto.getMetricId()))
+ .setOperator(qualityGateConditionDto.getOperator())
+ .setPeriod(qualityGateConditionDto.getPeriod())
+ .setErrorThreshold(qualityGateConditionDto.getErrorThreshold())
+ .setWarningThreshold(qualityGateConditionDto.getWarningThreshold());
+ }
+
+ @CheckForNull
+ public Long getId() {
+ return id;
+ }
+
+ public QualityGateCondition setId(Long id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getMetricKey() {
+ return metricKey;
+ }
+
+ public QualityGateCondition setMetricKey(String metricKey) {
+ this.metricKey = metricKey;
+ return this;
+ }
+
+ public Integer getPeriod() {
+ return period;
+ }
+
+ public QualityGateCondition setPeriod(Integer period) {
+ this.period = period;
+ return this;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public QualityGateCondition setOperator(String operator) {
+ this.operator = operator;
+ return this;
+ }
+
+ @CheckForNull
+ public String getWarningThreshold() {
+ return warningThreshold;
+ }
+
+ public QualityGateCondition setWarningThreshold(@Nullable String warningThreshold) {
+ this.warningThreshold = warningThreshold;
+ return this;
+ }
+
+ @CheckForNull
+ public String getErrorThreshold() {
+ return errorThreshold;
+ }
+
+ public QualityGateCondition setErrorThreshold(@Nullable String errorThreshold) {
+ this.errorThreshold = errorThreshold;
+ return this;
+ }
+
+ public QualityGateConditionDto toQualityGateDto(long qualityGateId) {
+ return new QualityGateConditionDto()
+ .setId(id)
+ .setMetricKey(metricKey)
+ .setOperator(operator)
+ .setPeriod(period)
+ .setErrorThreshold(errorThreshold)
+ .setWarningThreshold(warningThreshold)
+ .setQualityGateId(qualityGateId);
+ }
+
+ // id does not belongs to equals to be able to be compared with builtin
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ QualityGateCondition that = (QualityGateCondition) o;
+ return Objects.equals(metricKey, that.metricKey) &&
+ Objects.equals(period, that.period) &&
+ Objects.equals(operator, that.operator) &&
+ Objects.equals(warningThreshold, that.warningThreshold) &&
+ Objects.equals(errorThreshold, that.errorThreshold);
+ }
+
+ // id does not belongs to hashcode to be able to be compared with builtin
+ @Override
+ public int hashCode() {
+ return Objects.hash(metricKey, period, operator, warningThreshold, errorThreshold);
+ }
}
}
}
@Test
- public void fail_when_default_qgate_defined_in_properties_does_not_exists() throws Exception {
+ public void fail_when_default_qgate_defined_in_properties_does_not_exists() {
ComponentDto project = db.components().insertPrivateProject();
QualityGateDto dbQualityGate = db.qualityGates().createDefaultQualityGate("Sonar way");
db.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
- expectedException.expect(NotFoundException.class);
- underTest.getQualityGate(dbSession, project.getId());
+ assertThat(underTest.getQualityGate(dbSession, project.getId())).isEmpty();
}
@Test
- public void fail_when_project_qgate_defined_in_properties_does_not_exists() throws Exception {
+ public void fail_when_project_qgate_defined_in_properties_does_not_exists() {
ComponentDto project = db.components().insertPrivateProject();
QualityGateDto dbQualityGate = db.qualityGates().insertQualityGate("My team QG");
db.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
*/
package org.sonar.server.qualitygate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
-import org.sonar.db.loadedtemplate.LoadedTemplateDto;
+import org.sonar.db.metric.MetricDao;
import org.sonar.db.metric.MetricDto;
+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 static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT_KEY;
import static org.sonar.api.measures.Metric.ValueType.INT;
import static org.sonar.api.measures.Metric.ValueType.PERCENT;
import static org.sonar.db.metric.MetricTesting.newMetricDto;
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ private static final int LEAK_PERIOD = 1;
+ private static final String BUILT_IN_NAME = "Sonar way";
+
+ private DbClient dbClient = db.getDbClient();
+ private DbSession dbSession = db.getSession();
+
+ private QualityGateDao qualityGateDao = dbClient.qualityGateDao();
+ private QualityGateConditionDao gateConditionDao = dbClient.gateConditionDao();
+ private MetricDao metricDao = dbClient.metricDao();
+ private QualityGateConditionsUpdater qualityGateConditionsUpdater = new QualityGateConditionsUpdater(dbClient);
+ private QualityGateUpdater qualityGateUpdater = new QualityGateUpdater(dbClient);
+ private QualityGateFinder qualityGateFinder = new QualityGateFinder(dbClient);
+
+ private RegisterQualityGates underTest = new RegisterQualityGates(dbClient, qualityGateUpdater, qualityGateConditionsUpdater, qualityGateFinder, System2.INSTANCE);
- DbClient dbClient = db.getDbClient();
- DbSession dbSession = db.getSession();
+ @Before
+ public void setup() {
+ insertMetrics();
+ }
- QualityGates qualityGates = mock(QualityGates.class);
- RegisterQualityGates task = new RegisterQualityGates(dbClient,
- new QualityGateConditionsUpdater(dbClient),
- dbClient.loadedTemplateDao(),
- qualityGates);
+ @After
+ public void after() {
+ underTest.stop();
+ }
@Test
public void register_default_gate() {
- MetricDto newReliability = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_RELIABILITY_RATING_KEY).setValueType(INT.name()).setHidden(false));
- MetricDto newSecurity = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_RATING_KEY).setValueType(INT.name()).setHidden(false));
- MetricDto newMaintainability = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_MAINTAINABILITY_RATING_KEY).setValueType(PERCENT.name()).setHidden(false));
- MetricDto newCoverage = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_COVERAGE_KEY).setValueType(PERCENT.name()).setHidden(false));
- MetricDto newDuplication = dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setValueType(PERCENT.name()).setHidden(false));
+ underTest.start();
+
+ verifyCorrectBuiltInQualityGate();
+
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")
+ ).isTrue();
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")
+ ).isTrue();
+ }
+
+ @Test
+ public void upgrade_empty_quality_gate() {
+ QualityGateDto builtin = new QualityGateDto().setName(BUILT_IN_NAME).setBuiltIn(true);
+ qualityGateDao.insert(dbSession, builtin);
+ dbSession.commit();
+
+ underTest.start();
+ assertThat(qualityGateDao.selectAll(dbSession)).hasSize(1);
+ verifyCorrectBuiltInQualityGate();
+
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")
+ ).isTrue();
+ }
+
+ @Test
+ public void upgrade_should_remove_deleted_condition() {
+ QualityGateDto builtin = new QualityGateDto().setName(BUILT_IN_NAME).setBuiltIn(true);
+ qualityGateDao.insert(dbSession, builtin);
+
+ createBuiltInConditions(builtin);
+
+ // Add another condition
+ qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
+ NEW_SECURITY_REMEDIATION_EFFORT_KEY, OPERATOR_GREATER_THAN, null, "5", LEAK_PERIOD);
+
+ dbSession.commit();
+
+ underTest.start();
+ assertThat(qualityGateDao.selectAll(dbSession)).hasSize(1);
+ verifyCorrectBuiltInQualityGate();
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")
+ ).isTrue();
+ }
+
+ @Test
+ public void upgrade_should_add_missing_condition() {
+ QualityGateDto builtin = new QualityGateDto().setName(BUILT_IN_NAME).setBuiltIn(true);
+ qualityGateDao.insert(dbSession, builtin);
+
+ List<QualityGateConditionDto> builtInConditions = createBuiltInConditions(builtin);
+
+ // Remove a condition
+ QualityGateConditionDto conditionToBeDeleted = builtInConditions.get(new Random().nextInt(builtInConditions.size()));
+ gateConditionDao.delete(conditionToBeDeleted, dbSession);
+
+ dbSession.commit();
+
+ underTest.start();
+ assertThat(qualityGateDao.selectAll(dbSession)).hasSize(1);
+ verifyCorrectBuiltInQualityGate();
+
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")
+ ).isTrue();
+ }
+
+ @Test
+ public void should_set_SonarWay_as_builtin_when_not_set() {
+ QualityGateDto builtin = new QualityGateDto().setName(BUILT_IN_NAME).setBuiltIn(false);
+ qualityGateDao.insert(dbSession, builtin);
+
+ createBuiltInConditions(builtin);
+ dbSession.commit();
+
+ underTest.start();
+ assertThat(qualityGateDao.selectAll(dbSession)).hasSize(1);
+ verifyCorrectBuiltInQualityGate();
+
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Quality gate [Sonar way] has been set as built-in")
+ ).isTrue();
+ }
+
+ @Test
+ public void should_not_update_builtin_quality_gate_if_already_uptodate() {
+ QualityGateDto builtin = new QualityGateDto().setName(BUILT_IN_NAME).setBuiltIn(true);
+ qualityGateDao.insert(dbSession, builtin);
+
+ createBuiltInConditions(builtin);
dbSession.commit();
- task.start();
+ underTest.start();
+ assertThat(qualityGateDao.selectAll(dbSession)).hasSize(1);
+ verifyCorrectBuiltInQualityGate();
+
+ // Log must not be present
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Quality gate [Sonar way] has been set as built-in")
+ ).isFalse();
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")
+ ).isFalse();
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")
+ ).isFalse();
+ }
+
+ @Test
+ public void ensure_only_one_built_in_quality_gate() {
+ String qualityGateName = "IncorrectQualityGate";
+ QualityGateDto builtin = new QualityGateDto().setName(qualityGateName).setBuiltIn(true);
+ qualityGateDao.insert(dbSession, builtin);
+ dbSession.commit();
+
+ underTest.start();
+
+ QualityGateDto oldQualityGate = qualityGateDao.selectByName(dbSession, qualityGateName);
+ assertThat(oldQualityGate).isNotNull();
+ assertThat(oldQualityGate.isBuiltIn()).isFalse();
+
+ List<QualityGateDto> allBuiltInQualityProfiles = qualityGateDao.selectAll(dbSession)
+ .stream()
+ .filter(QualityGateDto::isBuiltIn)
+ .collect(MoreCollectors.toList());
+ assertThat(allBuiltInQualityProfiles)
+ .extracting("name")
+ .containsExactly(BUILT_IN_NAME);
+
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")
+ ).isTrue();
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")
+ ).isTrue();
+ }
+
+ @Test
+ public void ensure_only_that_builtin_is_set_as_default_when_no_default_quality_gate() {
+ QualityGateDto builtin = new QualityGateDto().setName(BUILT_IN_NAME).setBuiltIn(true);
+ qualityGateDao.insert(dbSession, builtin);
+ dbSession.commit();
- assertThat(dbClient.loadedTemplateDao().countByTypeAndKey("QUALITY_GATE", "SonarQube way", dbSession)).isEqualTo(1);
- QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectByName(dbSession, "SonarQube way");
+ underTest.start();
+
+ assertThat(qualityGateFinder.getDefault(dbSession)).isPresent();
+ assertThat(qualityGateFinder.getDefault(dbSession).get().getId()).isEqualTo(builtin.getId());
+
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been set as default")
+ ).isTrue();
+ }
+
+ @Test
+ public void builtin_quality_gate_with_incorrect_metricId_should_not_throw_an_exception() {
+ QualityGateDto builtin = new QualityGateDto().setName(BUILT_IN_NAME).setBuiltIn(true);
+ qualityGateDao.insert(dbSession, builtin);
+ QualityGateConditionDto conditionDto = new QualityGateConditionDto()
+ .setMetricId(-1) // This Id does not exist
+ .setOperator(OPERATOR_GREATER_THAN)
+ .setErrorThreshold("1")
+ .setWarningThreshold("1");
+ gateConditionDao.insert(conditionDto,dbSession);
+ dbSession.commit();
+
+ underTest.start();
+
+ // No exception thrown
+ verifyCorrectBuiltInQualityGate();
+
+ assertThat(
+ logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")
+ ).isTrue();
+ }
+
+ private void insertMetrics() {
+ dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_RELIABILITY_RATING_KEY).setValueType(INT.name()).setHidden(false));
+ dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_RATING_KEY).setValueType(INT.name()).setHidden(false));
+ dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_REMEDIATION_EFFORT_KEY).setValueType(INT.name()).setHidden(false));
+ dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_MAINTAINABILITY_RATING_KEY).setValueType(PERCENT.name()).setHidden(false));
+ dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_COVERAGE_KEY).setValueType(PERCENT.name()).setHidden(false));
+ dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setValueType(PERCENT.name()).setHidden(false));
+ dbSession.commit();
+ }
+
+ private void verifyCorrectBuiltInQualityGate() {
+ MetricDto newReliability = metricDao.selectByKey(dbSession, NEW_RELIABILITY_RATING_KEY);
+ MetricDto newSecurity = metricDao.selectByKey(dbSession, NEW_SECURITY_RATING_KEY);
+ MetricDto newMaintainability = metricDao.selectByKey(dbSession, NEW_MAINTAINABILITY_RATING_KEY);
+ MetricDto newCoverage = metricDao.selectByKey(dbSession, NEW_COVERAGE_KEY);
+ MetricDto newDuplication = metricDao.selectByKey(dbSession, NEW_DUPLICATED_LINES_DENSITY_KEY);
+
+ QualityGateDto qualityGateDto = qualityGateDao.selectByName(dbSession, BUILT_IN_NAME);
assertThat(qualityGateDto).isNotNull();
+ assertThat(qualityGateDto.getCreatedAt()).isNotNull();
assertThat(qualityGateDto.isBuiltIn()).isTrue();
- assertThat(dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGateDto.getId()))
+ assertThat(gateConditionDao.selectForQualityGate(dbSession, qualityGateDto.getId()))
.extracting(QualityGateConditionDto::getMetricId, QualityGateConditionDto::getOperator, QualityGateConditionDto::getWarningThreshold,
QualityGateConditionDto::getErrorThreshold, QualityGateConditionDto::getPeriod)
.containsOnly(
tuple(newMaintainability.getId().longValue(), OPERATOR_GREATER_THAN, null, "1", 1),
tuple(newCoverage.getId().longValue(), OPERATOR_LESS_THAN, null, "80", 1),
tuple(newDuplication.getId().longValue(), OPERATOR_GREATER_THAN, null, "3", 1));
- verify(qualityGates).setDefault(any(DbSession.class), anyLong());
-
- task.stop();
}
- @Test
- public void does_not_register_default_gate_if_already_executed() {
- String templateType = "QUALITY_GATE";
- String templateName = "SonarQube way";
- dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(templateName, templateType), dbSession);
- dbSession.commit();
+ private List<QualityGateConditionDto> createBuiltInConditions(QualityGateDto builtin) {
+ List<QualityGateConditionDto> conditions = new ArrayList<>();
- task.start();
+ conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
+ NEW_SECURITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1", LEAK_PERIOD));
+ conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
+ NEW_RELIABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1", LEAK_PERIOD));
+ conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
+ NEW_MAINTAINABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1", LEAK_PERIOD));
+ conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
+ NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, null, "80", LEAK_PERIOD));
+ conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, builtin.getId(),
+ NEW_DUPLICATED_LINES_DENSITY_KEY, OPERATOR_GREATER_THAN, null, "3", LEAK_PERIOD));
- assertThat(dbClient.qualityGateDao().selectAll(dbSession)).isEmpty();
- verifyZeroInteractions(qualityGates);
+ return conditions;
}
}
ProjectDashboardPage page = tester.openBrowser()
.logIn().submitCredentials(user.getLogin())
.openProjectDashboard(project);
- page.hasQualityGateLink("SonarQube way", link);
+ page.hasQualityGateLink("Sonar way", link);
}
@Test
QualityGatePage page = tester.openBrowser()
.logIn().submitCredentials(user.getLogin())
.openQualityGates(organization.getKey());
- page.countQualityGates(1).displayQualityGateDetail("SonarQube way");
+ page.countQualityGates(1).displayQualityGateDetail("Sonar way");
}
}
.logIn().submitCredentials(login)
.openQualityGates()
.canNotCreateQG()
- .displayQualityGateDetail("SonarQube way");
+ .displayQualityGateDetail("Sonar way");
tester.openBrowser()
.logIn().submitCredentials(admin)
.openQualityGates()
assertThat(project.get("name")).isEqualTo(PROJECT_NAME);
assertThat(project.get("url")).isEqualTo(orchestrator.getServer().getUrl() + "/dashboard?id=" + PROJECT_KEY);
Map<String, Object> gate = (Map<String, Object>) payload.get("qualityGate");
- assertThat(gate.get("name")).isEqualTo("SonarQube way");
+ assertThat(gate.get("name")).isEqualTo("Sonar way");
assertThat(gate.get("status")).isEqualTo("OK");
assertThat(gate.get("conditions")).isNotNull();
<tr>
<td>waitForText</td>
<td>id=content</td>
- <td>*Quality Gate*SonarQube way*</td>
+ <td>*Quality Gate*Sonar way*</td>
</tr>
<tr>
<td>waitForText</td>