]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20991 Copy old 'Sonar way' quality gate to 'Sonar way (legacy)'
authorNolwenn Cadic <nolwenn.cadic@sonarsource.com>
Thu, 9 Nov 2023 15:47:04 +0000 (16:47 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 15 Nov 2023 09:11:03 +0000 (09:11 +0000)
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGate.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/RegisterQualityGatesIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java

index d4082e0288c49a582181d33d71959bce0829cf9b..2f15f0e2cfb57b9fd212dd2b8dd45cc592866ee7 100644 (file)
@@ -30,6 +30,9 @@ import static java.util.Objects.requireNonNull;
 public class QualityGate {
 
   public static final String BUILTIN_QUALITY_GATE_NAME = "Sonar way";
+
+  public static final String SONAR_WAY_LEGACY_QUALITY_GATE_NAME = "Sonar way (legacy)";
+
   private final String id;
   private final String name;
   private final Set<Condition> conditions;
index 1dad0d2b0a15d7392ec4377fa8dc95f6cb4463db..7edbfb9e15576d0bea4eacd79ff934545ef947f8 100644 (file)
  */
 package org.sonar.server.qualitygate;
 
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Random;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.slf4j.event.Level;
 import org.sonar.api.testfixtures.log.LogTester;
 import org.sonar.api.utils.System2;
@@ -54,16 +58,16 @@ import static org.sonar.api.measures.Metric.ValueType.PERCENT;
 import static org.sonar.db.metric.MetricTesting.newMetricDto;
 import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_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.SONAR_WAY_LEGACY_QUALITY_GATE_NAME;
 
+@RunWith(DataProviderRunner.class)
 public class RegisterQualityGatesIT {
 
   @Rule
   public DbTester db = DbTester.create();
   @Rule
   public LogTester logTester = new LogTester();
-
-  private static final String BUILT_IN_NAME = "Sonar way";
-
   private final DbClient dbClient = db.getDbClient();
   private final DbSession dbSession = db.getSession();
 
@@ -114,7 +118,6 @@ public class RegisterQualityGatesIT {
 
     underTest.start();
 
-    assertThat(db.countRowsOfTable("quality_gates")).isOne();
     verifyCorrectBuiltInQualityGate();
     assertThat(
       logTester.logs(Level.INFO)).contains("Built-in quality gate's conditions of [Sonar way] has been updated");
@@ -131,7 +134,6 @@ public class RegisterQualityGatesIT {
 
     underTest.start();
 
-    assertThat(db.countRowsOfTable("quality_gates")).isOne();
     verifyCorrectBuiltInQualityGate();
     assertThat(
       logTester.logs(Level.INFO)).contains("Built-in quality gate's conditions of [Sonar way] has been updated");
@@ -149,7 +151,6 @@ public class RegisterQualityGatesIT {
 
     underTest.start();
 
-    assertThat(db.countRowsOfTable("quality_gates")).isOne();
     verifyCorrectBuiltInQualityGate();
     assertThat(
       logTester.logs(Level.INFO)).contains("Built-in quality gate's conditions of [Sonar way] has been updated");
@@ -169,7 +170,6 @@ public class RegisterQualityGatesIT {
 
     underTest.start();
 
-    assertThat(db.countRowsOfTable("quality_gates")).isOne();
     verifyCorrectBuiltInQualityGate();
     assertThat(
       logTester.logs(Level.INFO)).contains("Quality gate [Sonar way] has been set as built-in");
@@ -184,7 +184,6 @@ public class RegisterQualityGatesIT {
 
     underTest.start();
 
-    assertThat(db.countRowsOfTable("quality_gates")).isOne();
     verifyCorrectBuiltInQualityGate();
     // Log must not be present
     assertThat(
@@ -208,9 +207,8 @@ public class RegisterQualityGatesIT {
     QualityGateDto oldQualityGate = qualityGateDao.selectByName(dbSession, qualityGateName);
     assertThat(oldQualityGate).isNotNull();
     assertThat(oldQualityGate.isBuiltIn()).isFalse();
-    assertThat(db.select("select name as \"name\" from quality_gates where is_built_in is true"))
-      .extracting(column -> column.get("name"))
-      .containsExactly(BUILT_IN_NAME);
+    var qualityGateDto = qualityGateDao.selectByName(dbSession, BUILTIN_QUALITY_GATE_NAME);
+    assertThat(qualityGateDto).isNotNull();
     assertThat(
       logTester.logs(Level.INFO)).contains("Built-in quality gate [Sonar way] has been created");
     assertThat(
@@ -237,6 +235,62 @@ public class RegisterQualityGatesIT {
       logTester.logs(Level.INFO)).contains("Built-in quality gate's conditions of [Sonar way] has been updated");
   }
 
+  @Test
+  public void register_sonar_way_legacy_qg_if_not_exists_and_existing_instance() {
+    insertMetrics();
+    QualityGateDto builtin = new QualityGateDto().setName(BUILTIN_QUALITY_GATE_NAME).setBuiltIn(true).setUuid(Uuids.createFast());
+    qualityGateDao.insert(dbSession, builtin);
+    createBuiltInConditions(builtin);
+    dbSession.commit();
+
+    underTest.start();
+
+    var qualityGateDto = qualityGateDao.selectByName(dbSession, SONAR_WAY_LEGACY_QUALITY_GATE_NAME);
+    assertThat(qualityGateDto).isNotNull();
+
+    verifyCorrectSonarWayLegacyQualityGate();
+    assertThat(
+      logTester.logs(Level.INFO)).contains("Sonar way (legacy) quality gate has been created");
+
+  }
+
+  @Test
+  @UseDataProvider("data")
+  public void do_not_register_sonar_way_legacy_qg(boolean isNewInstance, boolean hasSonarWayLegacyQG) {
+    insertMetrics();
+    QualityGateDto builtin = new QualityGateDto().setName(BUILTIN_QUALITY_GATE_NAME).setBuiltIn(true).setUuid(Uuids.createFast());
+    qualityGateDao.insert(dbSession, builtin);
+    if(!isNewInstance) {
+      createBuiltInConditions(builtin);
+    }
+    if(hasSonarWayLegacyQG) {
+      QualityGateDto sonarWayLegacy = new QualityGateDto().setName(SONAR_WAY_LEGACY_QUALITY_GATE_NAME).setBuiltIn(true).setUuid(Uuids.createFast());
+      qualityGateDao.insert(dbSession, sonarWayLegacy);
+    }
+    dbSession.commit();
+
+    underTest.start();
+
+    var qualityGateDto = qualityGateDao.selectByName(dbSession, SONAR_WAY_LEGACY_QUALITY_GATE_NAME);
+    if(hasSonarWayLegacyQG) {
+     assertThat(qualityGateDto).isNotNull();
+    } else {
+      assertThat(qualityGateDto).isNull();
+    }
+
+    assertThat(
+      logTester.logs(Level.INFO)).doesNotContain("Sonar way (legacy) quality gate has been created");
+  }
+
+  @DataProvider
+  public static Object[][] data() {
+    return new Object[][] {
+      {false, true},
+      {true, true},
+      {true, false}
+    };
+  }
+
   private void insertMetrics() {
     dbClient.metricDao().insert(dbSession,
       newMetricDto().setKey(NEW_RELIABILITY_RATING_KEY).setValueType(INT.name()).setHidden(false).setDirection(0));
@@ -261,7 +315,7 @@ public class RegisterQualityGatesIT {
     MetricDto newDuplication = metricDao.selectByKey(dbSession, NEW_DUPLICATED_LINES_DENSITY_KEY);
     MetricDto newSecurityHotspots = metricDao.selectByKey(dbSession, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY);
 
-    QualityGateDto qualityGateDto = qualityGateDao.selectByName(dbSession, BUILT_IN_NAME);
+    QualityGateDto qualityGateDto = qualityGateDao.selectByName(dbSession, BUILTIN_QUALITY_GATE_NAME);
     assertThat(qualityGateDto).isNotNull();
     assertThat(qualityGateDto.getCreatedAt()).isNotNull();
     assertThat(qualityGateDto.isBuiltIn()).isTrue();
@@ -275,6 +329,29 @@ public class RegisterQualityGatesIT {
         tuple(newSecurityHotspots.getUuid(), OPERATOR_LESS_THAN, "100"));
   }
 
+  private void verifyCorrectSonarWayLegacyQualityGate() {
+    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);
+    MetricDto newSecurityHotspots = metricDao.selectByKey(dbSession, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY);
+    QualityGateDto qualityGateDto = qualityGateDao.selectByName(dbSession, SONAR_WAY_LEGACY_QUALITY_GATE_NAME);
+    assertThat(qualityGateDto).isNotNull();
+    assertThat(qualityGateDto.getCreatedAt()).isNotNull();
+    assertThat(qualityGateDto.isBuiltIn()).isFalse();
+    assertThat(gateConditionDao.selectForQualityGate(dbSession, qualityGateDto.getUuid()))
+      .extracting(QualityGateConditionDto::getMetricUuid, QualityGateConditionDto::getOperator,
+        QualityGateConditionDto::getErrorThreshold)
+      .containsExactlyInAnyOrder(
+        tuple(newReliability.getUuid(), OPERATOR_GREATER_THAN, "1"),
+        tuple(newSecurity.getUuid(), OPERATOR_GREATER_THAN, "1"),
+        tuple(newMaintainability.getUuid(), OPERATOR_GREATER_THAN, "1"),
+        tuple(newCoverage.getUuid(), OPERATOR_LESS_THAN, "80"),
+        tuple(newDuplication.getUuid(), OPERATOR_GREATER_THAN, "3"),
+        tuple(newSecurityHotspots.getUuid(), OPERATOR_LESS_THAN, "100"));
+  }
+
   private List<QualityGateConditionDto> createBuiltInConditions(QualityGateDto qg) {
     List<QualityGateConditionDto> conditions = new ArrayList<>();
 
index 2184186b80988977b31913d43a60ba6018b23bf6..2194664651902f1a008b98c5a75d0dcc473b169f 100644 (file)
@@ -41,27 +41,42 @@ 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.measure.Rating;
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 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;
+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_RATING_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_LESS_THAN;
 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 {
 
   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_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 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 QualityGateConditionsUpdater qualityGateConditionsUpdater;
   private final QualityGateDao qualityGateDao;
@@ -86,9 +101,17 @@ public class RegisterQualityGates implements Startable {
       // Create builtinQualityGate if not present
       if (builtinQualityGate == null) {
         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
       if (!builtinQualityGate.isBuiltIn()) {
         builtinQualityGate.setBuiltIn(true);
@@ -96,7 +119,7 @@ public class RegisterQualityGates implements Startable {
         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);
 
@@ -104,8 +127,18 @@ public class RegisterQualityGates implements Startable {
     }
   }
 
-  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);
     qgConditionsDeleted.addAll(removeDuplicatedConditions(dbSession, builtinQualityGate, qualityGateConditions));
@@ -131,7 +164,7 @@ public class RegisterQualityGates implements Startable {
     // 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.removeAll(BUILT_IN_QUALITY_GATE_CONDITIONS);
     qgConditionsToBeDeleted
       .forEach(qgc -> qualityGateConditionDao.delete(qgc.toQualityGateDto(builtinQualityGate.getUuid()), dbSession));
     return qgConditionsToBeDeleted;
@@ -149,26 +182,31 @@ public class RegisterQualityGates implements Startable {
     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
     // 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
-      .forEach(qgc -> qualityGateConditionsUpdater.createCondition(dbSession, builtinQualityGate, qgc.getMetricKey(), qgc.getOperator(),
-        qgc.getErrorThreshold()));
+    addConditionsToQualityGate(dbSession, builtinQualityGate, 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
   public void stop() {
     // do nothing
   }
 
-  private QualityGateDto createQualityGate(DbSession dbSession, String name) {
+  private QualityGateDto createQualityGate(DbSession dbSession, String name, boolean isBuiltIn) {
     QualityGateDto qualityGate = new QualityGateDto()
       .setName(name)
-      .setBuiltIn(true)
+      .setBuiltIn(isBuiltIn)
       .setUuid(uuidFactory.create())
       .setCreatedAt(new Date(system2.now()));
     return dbClient.qualityGateDao().insert(dbSession, qualityGate);