|
|
|
|
|
|
|
|
import org.sonar.db.qualitygate.QualityGateConditionDto; |
|
|
import org.sonar.db.qualitygate.QualityGateConditionDto; |
|
|
import org.sonar.db.qualitygate.QualityGateDao; |
|
|
import org.sonar.db.qualitygate.QualityGateDao; |
|
|
import org.sonar.db.qualitygate.QualityGateDto; |
|
|
import org.sonar.db.qualitygate.QualityGateDto; |
|
|
|
|
|
import org.sonar.server.measure.Rating; |
|
|
|
|
|
|
|
|
import static com.google.common.collect.ImmutableList.toImmutableList; |
|
|
import static com.google.common.collect.ImmutableList.toImmutableList; |
|
|
import static java.util.Arrays.asList; |
|
|
import static java.util.Arrays.asList; |
|
|
import static java.util.stream.Collectors.toMap; |
|
|
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_COVERAGE_KEY; |
|
|
import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_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_HOTSPOTS_REVIEWED_KEY; |
|
|
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_KEY; |
|
|
|
|
|
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY; |
|
|
import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; |
|
|
import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; |
|
|
import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN; |
|
|
import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN; |
|
|
import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THAN; |
|
|
import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THAN; |
|
|
import static org.sonar.server.qualitygate.QualityGate.BUILTIN_QUALITY_GATE_NAME; |
|
|
import static org.sonar.server.qualitygate.QualityGate.BUILTIN_QUALITY_GATE_NAME; |
|
|
|
|
|
import static org.sonar.server.qualitygate.QualityGate.SONAR_WAY_LEGACY_QUALITY_GATE_NAME; |
|
|
|
|
|
|
|
|
public class RegisterQualityGates implements Startable { |
|
|
public class RegisterQualityGates implements Startable { |
|
|
|
|
|
|
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(RegisterQualityGates.class); |
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(RegisterQualityGates.class); |
|
|
private static final List<QualityGateCondition> QUALITY_GATE_CONDITIONS = asList( |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final String A_RATING = Integer.toString(Rating.A.getIndex()); |
|
|
|
|
|
private static final List<QualityGateCondition> BUILT_IN_QUALITY_GATE_CONDITIONS = asList( |
|
|
new QualityGateCondition().setMetricKey(NEW_VIOLATIONS_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold("0"), |
|
|
new QualityGateCondition().setMetricKey(NEW_VIOLATIONS_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold("0"), |
|
|
new QualityGateCondition().setMetricKey(NEW_COVERAGE_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("80"), |
|
|
new QualityGateCondition().setMetricKey(NEW_COVERAGE_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("80"), |
|
|
new QualityGateCondition().setMetricKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold("3"), |
|
|
new QualityGateCondition().setMetricKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold("3"), |
|
|
new QualityGateCondition().setMetricKey(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("100")); |
|
|
new QualityGateCondition().setMetricKey(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("100")); |
|
|
|
|
|
|
|
|
|
|
|
private static final List<QualityGateCondition> SONAR_WAY_LEGACY_QUALITY_GATE_CONDITIONS = asList( |
|
|
|
|
|
new QualityGateCondition().setMetricKey(NEW_SECURITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING), |
|
|
|
|
|
new QualityGateCondition().setMetricKey(NEW_RELIABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING), |
|
|
|
|
|
new QualityGateCondition().setMetricKey(NEW_MAINTAINABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING), |
|
|
|
|
|
new QualityGateCondition().setMetricKey(NEW_COVERAGE_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("80"), |
|
|
|
|
|
new QualityGateCondition().setMetricKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold("3"), |
|
|
|
|
|
new QualityGateCondition().setMetricKey(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("100")); |
|
|
|
|
|
|
|
|
private final DbClient dbClient; |
|
|
private final DbClient dbClient; |
|
|
private final QualityGateConditionsUpdater qualityGateConditionsUpdater; |
|
|
private final QualityGateConditionsUpdater qualityGateConditionsUpdater; |
|
|
private final QualityGateDao qualityGateDao; |
|
|
private final QualityGateDao qualityGateDao; |
|
|
|
|
|
|
|
|
// Create builtinQualityGate if not present |
|
|
// Create builtinQualityGate if not present |
|
|
if (builtinQualityGate == null) { |
|
|
if (builtinQualityGate == null) { |
|
|
LOGGER.info("Built-in quality gate [{}] has been created", BUILTIN_QUALITY_GATE_NAME); |
|
|
LOGGER.info("Built-in quality gate [{}] has been created", BUILTIN_QUALITY_GATE_NAME); |
|
|
builtinQualityGate = createQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME); |
|
|
|
|
|
|
|
|
builtinQualityGate = createQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME, true); |
|
|
|
|
|
} |
|
|
|
|
|
List<QualityGateCondition> builtInQualityGateConditions = getQualityGateConditions(dbSession, builtinQualityGate); |
|
|
|
|
|
|
|
|
|
|
|
// Create sonar way (legacy) only if it is not a new instance (a new instance has a Sonar way QG and no conditions) and if it is |
|
|
|
|
|
// not already present |
|
|
|
|
|
if (!builtInQualityGateConditions.isEmpty()) { |
|
|
|
|
|
createSonarWayLegacyQualityGateIfMissing(dbSession); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set builtinQualityGate if missing |
|
|
// Set builtinQualityGate if missing |
|
|
if (!builtinQualityGate.isBuiltIn()) { |
|
|
if (!builtinQualityGate.isBuiltIn()) { |
|
|
builtinQualityGate.setBuiltIn(true); |
|
|
builtinQualityGate.setBuiltIn(true); |
|
|
|
|
|
|
|
|
LOGGER.info("Quality gate [{}] has been set as built-in", BUILTIN_QUALITY_GATE_NAME); |
|
|
LOGGER.info("Quality gate [{}] has been set as built-in", BUILTIN_QUALITY_GATE_NAME); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
updateQualityConditionsIfRequired(dbSession, builtinQualityGate); |
|
|
|
|
|
|
|
|
updateQualityConditionsIfRequired(dbSession, builtinQualityGate, builtInQualityGateConditions); |
|
|
|
|
|
|
|
|
qualityGateDao.ensureOneBuiltInQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME); |
|
|
qualityGateDao.ensureOneBuiltInQualityGate(dbSession, BUILTIN_QUALITY_GATE_NAME); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void updateQualityConditionsIfRequired(DbSession dbSession, QualityGateDto builtinQualityGate) { |
|
|
|
|
|
List<QualityGateCondition> qualityGateConditions = getQualityGateConditions(dbSession, builtinQualityGate); |
|
|
|
|
|
|
|
|
private void createSonarWayLegacyQualityGateIfMissing(DbSession dbSession) { |
|
|
|
|
|
QualityGateDto sonarWayLegacyQualityGate = qualityGateDao.selectByName(dbSession, SONAR_WAY_LEGACY_QUALITY_GATE_NAME); |
|
|
|
|
|
LOGGER.info("Sonar way legacy Gate: {} ", sonarWayLegacyQualityGate); |
|
|
|
|
|
if (sonarWayLegacyQualityGate == null) { |
|
|
|
|
|
sonarWayLegacyQualityGate = createQualityGate(dbSession, SONAR_WAY_LEGACY_QUALITY_GATE_NAME, false); |
|
|
|
|
|
addConditionsToQualityGate(dbSession, sonarWayLegacyQualityGate, SONAR_WAY_LEGACY_QUALITY_GATE_CONDITIONS); |
|
|
|
|
|
LOGGER.info("Sonar way (legacy) quality gate has been created"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void updateQualityConditionsIfRequired(DbSession dbSession, QualityGateDto builtinQualityGate, |
|
|
|
|
|
List<QualityGateCondition> qualityGateConditions) { |
|
|
|
|
|
|
|
|
List<QualityGateCondition> qgConditionsDeleted = removeExtraConditions(dbSession, builtinQualityGate, qualityGateConditions); |
|
|
List<QualityGateCondition> qgConditionsDeleted = removeExtraConditions(dbSession, builtinQualityGate, qualityGateConditions); |
|
|
qgConditionsDeleted.addAll(removeDuplicatedConditions(dbSession, builtinQualityGate, qualityGateConditions)); |
|
|
qgConditionsDeleted.addAll(removeDuplicatedConditions(dbSession, builtinQualityGate, qualityGateConditions)); |
|
|
|
|
|
|
|
|
// Find all conditions that are not present in QUALITY_GATE_CONDITIONS |
|
|
// Find all conditions that are not present in QUALITY_GATE_CONDITIONS |
|
|
// Those conditions must be deleted |
|
|
// Those conditions must be deleted |
|
|
List<QualityGateCondition> qgConditionsToBeDeleted = new ArrayList<>(qualityGateConditions); |
|
|
List<QualityGateCondition> qgConditionsToBeDeleted = new ArrayList<>(qualityGateConditions); |
|
|
qgConditionsToBeDeleted.removeAll(QUALITY_GATE_CONDITIONS); |
|
|
|
|
|
|
|
|
qgConditionsToBeDeleted.removeAll(BUILT_IN_QUALITY_GATE_CONDITIONS); |
|
|
qgConditionsToBeDeleted |
|
|
qgConditionsToBeDeleted |
|
|
.forEach(qgc -> qualityGateConditionDao.delete(qgc.toQualityGateDto(builtinQualityGate.getUuid()), dbSession)); |
|
|
.forEach(qgc -> qualityGateConditionDao.delete(qgc.toQualityGateDto(builtinQualityGate.getUuid()), dbSession)); |
|
|
return qgConditionsToBeDeleted; |
|
|
return qgConditionsToBeDeleted; |
|
|
|
|
|
|
|
|
return qgConditionsDuplicated; |
|
|
return qgConditionsDuplicated; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private List<QualityGateCondition> addMissingConditions(DbSession dbSession, QualityGateDto builtinQualityGate, List<QualityGateCondition> qualityGateConditions) { |
|
|
|
|
|
|
|
|
private List<QualityGateCondition> addMissingConditions(DbSession dbSession, QualityGateDto builtinQualityGate, |
|
|
|
|
|
List<QualityGateCondition> qualityGateConditions) { |
|
|
// Find all conditions that are not present in qualityGateConditions |
|
|
// Find all conditions that are not present in qualityGateConditions |
|
|
// Those conditions must be added to the built-in quality gate |
|
|
// Those conditions must be added to the built-in quality gate |
|
|
List<QualityGateCondition> qgConditionsToBeAdded = new ArrayList<>(QUALITY_GATE_CONDITIONS); |
|
|
|
|
|
|
|
|
List<QualityGateCondition> qgConditionsToBeAdded = new ArrayList<>(BUILT_IN_QUALITY_GATE_CONDITIONS); |
|
|
qgConditionsToBeAdded.removeAll(qualityGateConditions); |
|
|
qgConditionsToBeAdded.removeAll(qualityGateConditions); |
|
|
qgConditionsToBeAdded |
|
|
|
|
|
.forEach(qgc -> qualityGateConditionsUpdater.createCondition(dbSession, builtinQualityGate, qgc.getMetricKey(), qgc.getOperator(), |
|
|
|
|
|
qgc.getErrorThreshold())); |
|
|
|
|
|
|
|
|
addConditionsToQualityGate(dbSession, builtinQualityGate, qgConditionsToBeAdded); |
|
|
return qgConditionsToBeAdded; |
|
|
return qgConditionsToBeAdded; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void addConditionsToQualityGate(DbSession dbSession, QualityGateDto qualityGate, List<QualityGateCondition> conditions) { |
|
|
|
|
|
conditions.forEach(condition -> qualityGateConditionsUpdater.createCondition(dbSession, qualityGate, condition.getMetricKey(), |
|
|
|
|
|
condition.getOperator(), |
|
|
|
|
|
condition.getErrorThreshold())); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public void stop() { |
|
|
public void stop() { |
|
|
// do nothing |
|
|
// do nothing |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private QualityGateDto createQualityGate(DbSession dbSession, String name) { |
|
|
|
|
|
|
|
|
private QualityGateDto createQualityGate(DbSession dbSession, String name, boolean isBuiltIn) { |
|
|
QualityGateDto qualityGate = new QualityGateDto() |
|
|
QualityGateDto qualityGate = new QualityGateDto() |
|
|
.setName(name) |
|
|
.setName(name) |
|
|
.setBuiltIn(true) |
|
|
|
|
|
|
|
|
.setBuiltIn(isBuiltIn) |
|
|
.setUuid(uuidFactory.create()) |
|
|
.setUuid(uuidFactory.create()) |
|
|
.setCreatedAt(new Date(system2.now())); |
|
|
.setCreatedAt(new Date(system2.now())); |
|
|
return dbClient.qualityGateDao().insert(dbSession, qualityGate); |
|
|
return dbClient.qualityGateDao().insert(dbSession, qualityGate); |