]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8115 storing project quality gate in table (#1919)
authorJacek <52388493+jacek-poreda-sonarsource@users.noreply.github.com>
Wed, 31 Jul 2019 13:03:39 +0000 (15:03 +0200)
committerSonarTech <sonartech@sonarsource.com>
Wed, 31 Jul 2019 18:21:14 +0000 (20:21 +0200)
* migrate properties to project_qgate table

* use project_qgates table instead of property

* change usage of project quality gate in CE

27 files changed:
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateService.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationMapper.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationQuery.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/ProjectQgateAssociationMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTable.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest/schema.sql [new file with mode: 0644]
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/DeselectAction.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/DestroyAction.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DeselectActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DestroyActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SelectActionTest.java

index b93ff801079c61b6175ba5555a1f6168c48fd4f6..8513a5f061b963c888d92528b764d663dee1c40a 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.ce.task.projectanalysis.qualitygate;
 
 import java.util.Optional;
 import org.sonar.ce.task.projectanalysis.analysis.Organization;
+import org.sonar.server.project.Project;
 
 public interface QualityGateService {
 
@@ -30,9 +31,14 @@ public interface QualityGateService {
   Optional<QualityGate> findById(long id);
 
   /**
-   * Retrieve the {@link QualityGate} from the database with the specified uuid.
+   * Retrieve the {@link QualityGate} from the database using organization.
    * @throws IllegalStateException if database is corrupted and default gate can't be found.
    */
   QualityGate findDefaultQualityGate(Organization organizationDto);
 
+  /**
+   * Retrieve the {@link QualityGate} from the database associated with project.
+   */
+  Optional<QualityGate> findQualityGate(Project project);
+
 }
index 7757851e8b23718e41b55bf89ea843efff17e19b..5cba5cf75bc6822fe0e4be3c660a26b4b42ef460 100644 (file)
@@ -28,6 +28,7 @@ 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.server.project.Project;
 
 import static org.sonar.core.util.stream.MoreCollectors.toList;
 
@@ -63,6 +64,17 @@ public class QualityGateServiceImpl implements QualityGateService {
     }
   }
 
+  @Override
+  public Optional<QualityGate> findQualityGate(Project project) {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectByProjectUuid(dbSession, project.getUuid());
+      if (qualityGateDto == null) {
+        return Optional.empty();
+      }
+      return Optional.of(toQualityGate(dbSession, qualityGateDto));
+    }
+  }
+
   private QualityGate toQualityGate(DbSession dbSession, QualityGateDto qualityGateDto) {
     Collection<QualityGateConditionDto> dtos = dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGateDto.getId());
 
index 24432b9d2bc8322dc15a99b4e55fd057c9cbeb10..aa8060c75baaf409f37ef50a19d14178c14aaee7 100644 (file)
@@ -21,32 +21,26 @@ 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 static org.apache.commons.lang.StringUtils.isBlank;
+import org.sonar.server.project.Project;
 
 /**
  * This step retrieves the QualityGate and stores it in
  * {@link MutableQualityGateHolder}.
  */
 public class LoadQualityGateStep implements ComputationStep {
-  private static final String PROPERTY_PROJECT_QUALITY_GATE = "sonar.qualitygate";
 
-  private final ConfigurationRepository configRepository;
   private final QualityGateService qualityGateService;
   private final MutableQualityGateHolder qualityGateHolder;
   private final AnalysisMetadataHolder analysisMetadataHolder;
 
-  public LoadQualityGateStep(ConfigurationRepository settingsRepository, QualityGateService qualityGateService, MutableQualityGateHolder qualityGateHolder,
-    AnalysisMetadataHolder analysisMetadataHolder) {
-    this.configRepository = settingsRepository;
+  public LoadQualityGateStep(QualityGateService qualityGateService, MutableQualityGateHolder qualityGateHolder,
+                             AnalysisMetadataHolder analysisMetadataHolder) {
     this.qualityGateService = qualityGateService;
     this.qualityGateHolder = qualityGateHolder;
     this.analysisMetadataHolder = analysisMetadataHolder;
@@ -73,20 +67,8 @@ public class LoadQualityGateStep implements ComputationStep {
   }
 
   private Optional<QualityGate> getProjectQualityGate() {
-    Configuration config = configRepository.getConfiguration();
-    String qualityGateSetting = config.get(PROPERTY_PROJECT_QUALITY_GATE).orElse(null);
-
-    if (isBlank(qualityGateSetting)) {
-      return Optional.empty();
-    }
-
-    try {
-      long qualityGateId = Long.parseLong(qualityGateSetting);
-      return qualityGateService.findById(qualityGateId);
-    } catch (NumberFormatException e) {
-      throw new IllegalStateException(
-        String.format("Unsupported value (%s) in property %s", qualityGateSetting, PROPERTY_PROJECT_QUALITY_GATE), e);
-    }
+    Project project = analysisMetadataHolder.getProject();
+    return qualityGateService.findQualityGate(project);
   }
 
   private QualityGate getOrganizationDefaultQualityGate() {
index adb3c09fd9001308afb05a629bf16d911491a994..0dc856ed72b1323e301bcd0b656f615b97387e55 100644 (file)
@@ -24,13 +24,16 @@ import java.util.Collections;
 import java.util.Optional;
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.ce.task.projectanalysis.analysis.Organization;
 import org.sonar.ce.task.projectanalysis.metric.Metric;
 import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
 import org.sonar.db.DbClient;
+import org.sonar.db.qualitygate.QGateWithOrgDto;
 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.project.Project;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
@@ -117,4 +120,57 @@ public class QualityGateServiceImplTest {
     assertThat(res.get().getConditions()).containsOnly(
       new Condition(METRIC_2, CONDITION_2.getOperator(), CONDITION_2.getErrorThreshold()));
   }
+
+  @Test(expected = IllegalStateException.class)
+  public void findDefaultQualityGate_by_organization_not_found() {
+    when(qualityGateDao.selectByOrganizationAndUuid(any(), any(), any())).thenReturn(null);
+
+    underTest.findDefaultQualityGate(mock(Organization.class));
+  }
+
+  @Test
+  public void findDefaultQualityGate_by_organization_found() {
+    QGateWithOrgDto qGateWithOrgDto = new QGateWithOrgDto();
+    qGateWithOrgDto.setId(QUALITY_GATE_DTO.getId());
+    qGateWithOrgDto.setName(QUALITY_GATE_DTO.getName());
+    when(qualityGateDao.selectByOrganizationAndUuid(any(), any(), any())).thenReturn(qGateWithOrgDto);
+    when(qualityGateConditionDao.selectForQualityGate(any(), eq(SOME_ID))).thenReturn(ImmutableList.of(CONDITION_1, CONDITION_2));
+    when(metricRepository.getOptionalById(METRIC_ID_1)).thenReturn(Optional.empty());
+    when(metricRepository.getOptionalById(METRIC_ID_2)).thenReturn(Optional.of(METRIC_2));
+
+    QualityGate result = underTest.findDefaultQualityGate(mock(Organization.class));
+
+    assertThat(result).isNotNull();
+    assertThat(result.getId()).isEqualTo(QUALITY_GATE_DTO.getId());
+    assertThat(result.getName()).isNotBlank();
+    assertThat(result.getName()).isEqualTo(QUALITY_GATE_DTO.getName());
+  }
+
+  @Test
+  public void findQualityGate_by_project_not_found() {
+    when(qualityGateDao.selectByProjectUuid(any(), any())).thenReturn(null);
+    Optional<QualityGate> result = underTest.findQualityGate(mock(Project.class));
+    assertThat(result).isEmpty();
+  }
+
+  @Test
+  public void findQualityGate_by_project_found() {
+    QGateWithOrgDto qGateWithOrgDto = new QGateWithOrgDto();
+    qGateWithOrgDto.setId(QUALITY_GATE_DTO.getId());
+    qGateWithOrgDto.setName(QUALITY_GATE_DTO.getName());
+    when(qualityGateDao.selectByProjectUuid(any(), any())).thenReturn(qGateWithOrgDto);
+    when(qualityGateConditionDao.selectForQualityGate(any(), eq(SOME_ID))).thenReturn(ImmutableList.of(CONDITION_1, CONDITION_2));
+    when(metricRepository.getOptionalById(METRIC_ID_1)).thenReturn(Optional.empty());
+    when(metricRepository.getOptionalById(METRIC_ID_2)).thenReturn(Optional.of(METRIC_2));
+
+    Optional<QualityGate> result = underTest.findQualityGate(mock(Project.class));
+
+    assertThat(result).isNotNull();
+    assertThat(result).isNotEmpty();
+
+    QualityGate resultData = result.get();
+    assertThat(resultData.getId()).isEqualTo(QUALITY_GATE_DTO.getId());
+    assertThat(resultData.getName()).isNotBlank();
+    assertThat(resultData.getName()).isEqualTo(QUALITY_GATE_DTO.getName());
+  }
 }
index 809c2505fd6038dd8f5287aa4efe9ecdae56b1c6..8937d07b5c5c980a7855e7e5241d7fca1a02258d 100644 (file)
@@ -25,9 +25,8 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
-import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository;
+import org.sonar.ce.task.projectanalysis.analysis.Organization;
 import org.sonar.ce.task.projectanalysis.metric.Metric;
 import org.sonar.ce.task.projectanalysis.metric.MetricImpl;
 import org.sonar.ce.task.projectanalysis.qualitygate.Condition;
@@ -35,6 +34,7 @@ import org.sonar.ce.task.projectanalysis.qualitygate.MutableQualityGateHolderRul
 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.project.Project;
 
 import static java.util.Collections.emptyList;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -50,19 +50,18 @@ public class LoadQualityGateStepTest {
   public MutableQualityGateHolderRule mutableQualityGateHolder = new MutableQualityGateHolderRule();
 
   private AnalysisMetadataHolder analysisMetadataHolder = mock(AnalysisMetadataHolder.class);
-  private ConfigurationRepository settingsRepository = mock(ConfigurationRepository.class);
   private QualityGateService qualityGateService = mock(QualityGateService.class);
 
-  private LoadQualityGateStep underTest = new LoadQualityGateStep(settingsRepository, qualityGateService, mutableQualityGateHolder, analysisMetadataHolder);
+  private LoadQualityGateStep underTest = new LoadQualityGateStep(qualityGateService, mutableQualityGateHolder, analysisMetadataHolder);
 
   @Before
   public void setUp() {
     when(analysisMetadataHolder.isShortLivingBranch()).thenReturn(false);
+    when(analysisMetadataHolder.getOrganization()).thenReturn(mock(Organization.class));
   }
 
   @Test
   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);
@@ -71,7 +70,7 @@ public class LoadQualityGateStepTest {
 
     when(analysisMetadataHolder.isSLBorPR()).thenReturn(true);
     QualityGate defaultGate = new QualityGate(1, "qg", Arrays.asList(variation, condition));
-    when(qualityGateService.findDefaultQualityGate(any())).thenReturn(defaultGate);
+    when(qualityGateService.findDefaultQualityGate(any(Organization.class))).thenReturn(defaultGate);
 
     underTest.execute(new TestComputationStepContext());
 
@@ -80,8 +79,6 @@ public class LoadQualityGateStepTest {
 
   @Test
   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");
@@ -89,7 +86,7 @@ public class LoadQualityGateStepTest {
 
     when(analysisMetadataHolder.isSLBorPR()).thenReturn(true);
     QualityGate defaultGate = new QualityGate(1, "qg", Arrays.asList(variation, condition));
-    when(qualityGateService.findDefaultQualityGate(any())).thenReturn(defaultGate);
+    when(qualityGateService.findDefaultQualityGate(any(Organization.class))).thenReturn(defaultGate);
 
     underTest.execute(new TestComputationStepContext());
 
@@ -98,31 +95,20 @@ public class LoadQualityGateStepTest {
 
   @Test
   public void execute_sets_default_QualityGate_when_project_has_no_settings() {
-    when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig());
     QualityGate defaultGate = mock(QualityGate.class);
-    when(qualityGateService.findDefaultQualityGate(any())).thenReturn(defaultGate);
+    when(qualityGateService.findDefaultQualityGate(any(Organization.class))).thenReturn(defaultGate);
 
     underTest.execute(new TestComputationStepContext());
 
     assertThat(mutableQualityGateHolder.getQualityGate().get()).isSameAs(defaultGate);
   }
 
-  @Test
-  public void execute_sets_default_QualityGate_when_property_value_is_not_a_long() {
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage("Unsupported value (10 sds) in property sonar.qualitygate");
-
-    when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", "10 sds").asConfig());
-
-    underTest.execute(new TestComputationStepContext());
-  }
-
   @Test
   public void execute_sets_QualityGate_if_it_can_be_found_by_service() {
     QualityGate qualityGate = new QualityGate(10, "name", emptyList());
 
-    when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig());
-    when(qualityGateService.findById(10)).thenReturn(Optional.of(qualityGate));
+    when(analysisMetadataHolder.getProject()).thenReturn(mock(Project.class));
+    when(qualityGateService.findQualityGate(any(Project.class))).thenReturn(Optional.of(qualityGate));
 
     underTest.execute(new TestComputationStepContext());
 
index 9e9152935fee569c04567d08f804b8e1c8902d09..a960ebb86d93b6aee55a862ff78cc33f19a89f54 100644 (file)
@@ -30,16 +30,6 @@ public class ProjectQgateAssociationDao implements Dao {
     return mapper(dbSession).selectProjects(query);
   }
 
-  /**
-   * @return quality gate id if a specific Quality Gate has been defined for the given component id. <br>
-   * Returns <code>{@link Optional#empty()}</code> otherwise (ex: default quality gate applies)
-   */
-  public Optional<Long> selectQGateIdByComponentId(DbSession dbSession, long componentId) {
-    String id = mapper(dbSession).selectQGateIdByComponentId(componentId);
-
-    return id == null ? Optional.empty() : Optional.of(Long.valueOf(id));
-  }
-
   /**
    * @return quality gate uuid if a specific Quality Gate has been defined for the given component uuid. <br>
    * Returns <code>{@link Optional#empty()}</code> otherwise (ex: default quality gate applies)
index 4d282c6a0919b06dac2b8c927585a36ce4b40069..a1a9cf84ad82b8e9037178c0a076f502a76e2923 100644 (file)
@@ -27,9 +27,6 @@ public interface ProjectQgateAssociationMapper {
 
   List<ProjectQgateAssociationDto> selectProjects(@Param("query") ProjectQgateAssociationQuery query);
 
-  @CheckForNull
-  String selectQGateIdByComponentId(long componentId);
-
   @CheckForNull
   String selectQGateUuidByComponentUuid(String componentUuid);
 
index b8d7e05de10fb787c21719e1d7765d106f696b66..f65869806185c28d00ec014865bc2908ccbb8639 100644 (file)
@@ -39,7 +39,7 @@ public class ProjectQgateAssociationQuery {
   public static final String OUT = "deselected";
   public static final Set<String> AVAILABLE_MEMBERSHIP = ImmutableSet.of(ANY, IN, OUT);
 
-  private final String gateId;
+  private final String gateUuid;
   private final String organizationUuid;
   private final String membership;
 
@@ -55,7 +55,7 @@ public class ProjectQgateAssociationQuery {
   private final int pageIndex;
 
   private ProjectQgateAssociationQuery(Builder builder) {
-    this.gateId = Long.toString(builder.qualityGate.getId());
+    this.gateUuid = builder.qualityGate.getUuid();
     this.organizationUuid = builder.qualityGate.getOrganizationUuid();
     this.membership = builder.membership;
     this.projectSearch = builder.projectSearch;
@@ -69,8 +69,8 @@ public class ProjectQgateAssociationQuery {
     this.pageIndex = builder.pageIndex;
   }
 
-  public String gateId() {
-    return gateId;
+  public String gateUuid() {
+    return gateUuid;
   }
 
   public String organizationUuid() {
index cc9e7a2b415e271d551405c4d9e384ad9839d563..086fad10892bf0df71ab8f29cfb4032e995b9cde 100644 (file)
@@ -53,6 +53,11 @@ public class QualityGateDao implements Dao {
     return mapper(session).selectById(id);
   }
 
+  @CheckForNull
+  public QualityGateDto selectByUuid(DbSession session, String uuid) {
+    return mapper(session).selectByUuid(uuid);
+  }
+
   @CheckForNull
   public QGateWithOrgDto selectByOrganizationAndUuid(DbSession dbSession, OrganizationDto organization, String qualityGateUuid) {
     return mapper(dbSession).selectByUuidAndOrganization(qualityGateUuid, organization.getUuid());
index 490f3bbbadc0f81c367b3415ca3b07709924a515..bc5acb250845d5782327fa643ff387189fecfa0b 100644 (file)
@@ -57,5 +57,7 @@ public interface QualityGateMapper {
 
   void ensureOneBuiltInQualityGate(String builtInQualityName);
 
+  QualityGateDto selectByUuid(String uuid);
+
   QualityGateDto selectByProjectUuid(@Param("projectUuid") String projectUuid);
 }
index ac1a2960ac8ba23c56c68fc7630b94d3cea2fc7e..e0ce3f079ffac0d1ea30836c767c1ac97902f736 100644 (file)
@@ -4,9 +4,10 @@
 <mapper namespace="org.sonar.db.qualitygate.ProjectQgateAssociationMapper">
 
   <select id="selectProjects" parameterType="map" resultType="ProjectQgateAssociation">
-    SELECT proj.id as id, proj.kee as "key", proj.name as name, prop.text_value as gateId
+    SELECT proj.id as id, proj.kee as "key", proj.name as name, qg.id as gateId
     FROM projects proj
-    LEFT JOIN properties prop ON prop.resource_id=proj.id AND prop.prop_key='sonar.qualitygate' AND prop.text_value = #{query.gateId}
+    LEFT JOIN project_qgates prqg ON prqg.project_uuid=proj.uuid AND prqg.quality_gate_uuid = #{query.gateUuid, jdbcType=VARCHAR}
+    LEFT JOIN quality_gates qg ON qg.uuid = prqg.quality_gate_uuid
     where
     proj.qualifier = 'TRK'
     and proj.enabled = ${_true}
     and proj.organization_uuid=#{query.organizationUuid, jdbcType=VARCHAR}
     <choose>
       <when test="query.membership() == 'selected'">
-        and prop.text_value IS NOT NULL
+        and qg.id IS NOT NULL
       </when>
       <when test="query.membership() == 'deselected'">
-        and prop.text_value IS NULL
+        and qg.id IS NULL
       </when>
     </choose>
     <if test="query.projectSearch() != null">
     order by proj.name
   </select>
 
-  <select id="selectQGateIdByComponentId" parameterType="long" resultType="string">
-    SELECT text_value
-    FROM properties
-    <where>
-      AND resource_id=#{componentId}
-      AND prop_key='sonar.qualitygate'
-    </where>
-  </select>
-
   <select id="selectQGateUuidByComponentUuid" parameterType="String" resultType="string">
     SELECT quality_gate_uuid
     FROM project_qgates
index 4d46494c2ff3c23d65f72698117b028e20f28d33..9fbedf685277db2081058f67cebbf6d4be5efc00 100644 (file)
     where name=#{name, jdbcType=VARCHAR}
   </select>
 
+  <select id="selectByUuid" parameterType="String" resultType="QualityGate">
+    select
+    <include refid="gateColumns"/>
+    from quality_gates
+    where uuid=#{uuid, jdbcType=VARCHAR}
+  </select>
+
   <select id="selectByUuidAndOrganization" parameterType="Map" resultType="org.sonar.db.qualitygate.QGateWithOrgDto">
     SELECT
       <include refid="qateWithOrgColumns"/>
index 77dae8512840084912a6b2e3640ae0b1bce20cf7..b399eaf0fe0e16ff1d4289e9346198b4b30d8fab 100644 (file)
@@ -151,16 +151,16 @@ public class ProjectQgateAssociationDaoTest {
   }
 
   @Test
-  public void select_qgate_id_is_absent() {
+  public void select_qgate_uuid_is_absent() {
     ComponentDto project = db.components().insertPrivateProject();
 
-    Optional<Long> result = underTest.selectQGateIdByComponentId(dbSession, project.getId());
+    Optional<String> result = underTest.selectQGateUuidByComponentUuid(dbSession, project.uuid());
 
     assertThat(result.isPresent()).isFalse();
   }
 
   @Test
-  public void select_qgate_id() {
+  public void select_qgate_uuid() {
     OrganizationDto organization = db.organizations().insert();
     QGateWithOrgDto qualityGate1 = db.qualityGates().insertQualityGate(organization);
     QGateWithOrgDto qualityGate2 = db.qualityGates().insertQualityGate(organization);
@@ -169,25 +169,11 @@ public class ProjectQgateAssociationDaoTest {
     db.qualityGates().associateProjectToQualityGate(project1, qualityGate1);
     db.qualityGates().associateProjectToQualityGate(project2, qualityGate2);
 
-    Optional<Long> result = underTest.selectQGateIdByComponentId(dbSession, project1.getId());
+    Optional<String> result = underTest.selectQGateUuidByComponentUuid(dbSession, project1.uuid());
 
-    assertThat(result).contains(qualityGate1.getId());
+    assertThat(result).contains(qualityGate1.getUuid());
   }
 
-  @Test
-  public void select_qgate_uuid_by_component_uuid() {
-    OrganizationDto organization = db.organizations().insert();
-    QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
-    ComponentDto project = db.components().insertPrivateProject(organization);
-
-    db.qualityGates().associateProjectToQualityGate(project, qualityGate);
-
-    Optional<String> qGateUuid = underTest.selectQGateUuidByComponentUuid(dbSession, project.uuid());
-
-    assertThat(qGateUuid).contains(qualityGate.getUuid());
-  }
-
-
   @Test
   public void delete_by_project_uuid() {
     OrganizationDto organization = db.organizations().insert();
index 824390141e570f65bf171002d8e10a7a5fc6712e..2eb97f50cab16b04b7878fc1c1bd0a294c26aac8 100644 (file)
@@ -112,16 +112,10 @@ public class QualityGateDaoTest {
   }
 
   @Test
-  public void select_by_uuid() {
-    QGateWithOrgDto dto = qualityGateDbTester.insertQualityGate(db.getDefaultOrganization(), g -> g.setName("QG Name").setBuiltIn(false));
-    QualityGateDto qualityGateToAssociate = underTest.selectById(dbSession, dto.getId());
-    ComponentDto project = db.components().insertPrivateProject();
-
-    qualityGateDbTester.associateProjectToQualityGate(project, qualityGateToAssociate);
-
-    QualityGateDto qualityGateFromSelect = underTest.selectByProjectUuid(dbSession, project.uuid());
-
-    assertThat(qualityGateFromSelect.getUuid()).isEqualTo(qualityGateToAssociate.getUuid());
+  public void testSelectByUuid() {
+    insertQualityGates();
+    assertThat(underTest.selectByUuid(dbSession, underTest.selectByName(dbSession, "Very strict").getUuid()).getName()).isEqualTo("Very strict");
+    assertThat(underTest.selectByUuid(dbSession, "not-existing-uuid")).isNull();
   }
 
   @Test
@@ -175,6 +169,24 @@ public class QualityGateDaoTest {
     assertThat(underTest.selectDefault(dbSession, otherOrganization).getUuid()).isEqualTo(otherQualityGate.getUuid());
   }
 
+  @Test
+  public void select_by_project_uuid() {
+    OrganizationDto organization = db.organizations().insert();
+
+    ComponentDto project = db.components().insertPrivateProject(organization);
+
+    QGateWithOrgDto qualityGate1 = db.qualityGates().insertQualityGate(organization);
+    QGateWithOrgDto qualityGate2 = db.qualityGates().insertQualityGate(organization);
+
+    OrganizationDto otherOrganization = db.organizations().insert();
+    QGateWithOrgDto qualityGate3 = db.qualityGates().insertQualityGate(otherOrganization);
+
+    db.qualityGates().associateProjectToQualityGate(project, qualityGate1);
+
+    assertThat(underTest.selectByProjectUuid(dbSession, project.uuid()).getUuid()).isEqualTo(qualityGate1.getUuid());
+    assertThat(underTest.selectByProjectUuid(dbSession, "not-existing-uuid")).isNull();
+  }
+
   @Test
   public void delete() {
     OrganizationDto organization = db.organizations().insert();
index 01727b4c215c489064d9f20d42e9686dc7943907..6b72f94b4a259177430a1da69b387249aa68fe6b 100644 (file)
@@ -30,7 +30,6 @@ import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.metric.MetricDto;
 import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.property.PropertyDto;
 
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
 import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
@@ -71,13 +70,7 @@ public class QualityGateDbTester {
   }
 
   public void associateProjectToQualityGate(ComponentDto component, QualityGateDto qualityGate) {
-    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
-      .setKey("sonar.qualitygate")
-      .setResourceId(component.getId())
-      .setValue(String.valueOf(qualityGate.getId())));
-
     dbClient.projectQgateAssociationDao().insertProjectQGateAssociation(dbSession, component.uuid(), qualityGate.getUuid());
-
     db.commit();
   }
 
@@ -110,7 +103,7 @@ public class QualityGateDbTester {
     return condition;
   }
 
-  public Optional<String> selectQGateUuidByComponentUuid(String uuid) {
-    return dbClient.projectQgateAssociationDao().selectQGateUuidByComponentUuid(dbSession, uuid);
+  public Optional<String> selectQGateUuidByComponentUuid(String componentUuid) {
+    return dbClient.projectQgateAssociationDao().selectQGateUuidByComponentUuid(dbSession, componentUuid);
   }
 }
index a11fd4e4156016a820f3f865974c7fc8b284cd26..f3f4721ef6d655bd221e5f740d9b0af3497aa607 100644 (file)
@@ -28,6 +28,7 @@ public class DbVersion80 implements DbVersion {
     registry
       .add(3000, "Set Organizations#guarded column nullable", MakeOrganizationsGuardedNullable.class)
       .add(3001, "Create ProjectQualityGates table", CreateProjectQualityGatesTable.class)
-      .add(3002, "Make index on DEPRECATED_RULE_KEYS.RULE_ID non unique", MakeDeprecatedRuleKeysRuleIdIndexNonUnique.class);
+      .add(3002, "Make index on DEPRECATED_RULE_KEYS.RULE_ID non unique", MakeDeprecatedRuleKeysRuleIdIndexNonUnique.class)
+      .add(3003, "Populate ProjectQualityGate table from Properties table", PopulateProjectQualityGatesTable.class);
   }
 }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTable.java
new file mode 100644 (file)
index 0000000..ba0ed09
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.platform.db.migration.version.v80;
+
+import java.sql.SQLException;
+import java.util.List;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.Upsert;
+
+public class PopulateProjectQualityGatesTable extends DataChange {
+
+  public PopulateProjectQualityGatesTable(Database db) {
+    super(db);
+  }
+
+  @Override
+  protected void execute(Context context) throws SQLException {
+    List<ProjectQualityGate> projectQualityGates = context.prepareSelect(
+      "select prj.uuid, qg.uuid from properties p \n" +
+        "join projects prj on p.resource_id = prj.id\n" +
+        "join quality_gates qg on qg.id = CAST(p.text_value AS int)\n" +
+        "where p.prop_key = 'sonar.qualitygate'\n" +
+        "and not exists(select pqg.project_uuid from project_qgates pqg where pqg.project_uuid = prj.uuid)")
+      .list(row -> {
+        String projectUuid = row.getString(1);
+        String qualityGateUuid = row.getString(2);
+        return new ProjectQualityGate(projectUuid, qualityGateUuid);
+      });
+
+    if (!projectQualityGates.isEmpty()) {
+      populateProjectQualityGates(context, projectQualityGates);
+    }
+  }
+
+  private static void populateProjectQualityGates(Context context, List<ProjectQualityGate> projectQualityGates) throws SQLException {
+    Upsert insertQuery = prepareInsertProjectQualityGateQuery(context);
+    for (ProjectQualityGate projectQualityGate : projectQualityGates) {
+      insertQuery
+        .setString(1, projectQualityGate.projectUuid)
+        .setString(2, projectQualityGate.qualityGateUuid)
+        .addBatch();
+    }
+    insertQuery
+      .execute()
+      .commit();
+  }
+
+  private static Upsert prepareInsertProjectQualityGateQuery(Context context) throws SQLException {
+    return context.prepareUpsert("insert into project_qgates(project_uuid, quality_gate_uuid) VALUES (?, ?)");
+  }
+
+  private static class ProjectQualityGate {
+    private final String projectUuid;
+    private final String qualityGateUuid;
+
+    ProjectQualityGate(String projectUuid, String qualityGateUuid) {
+      this.projectUuid = projectUuid;
+      this.qualityGateUuid = qualityGateUuid;
+    }
+  }
+
+}
index cefa4368acf0df029c74841d310f18c05ab16796..f69a48b5e7cc7de111b0d09fd9d3b8efc44a9692 100644 (file)
@@ -35,7 +35,7 @@ public class DbVersion80Test {
 
   @Test
   public void verify_migration_count() {
-    verifyMigrationCount(underTest, 3);
+    verifyMigrationCount(underTest, 4);
   }
 
 }
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest.java
new file mode 100644 (file)
index 0000000..4b7af24
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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.platform.db.migration.version.v80;
+
+import java.sql.SQLException;
+import java.time.Instant;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+import static java.lang.String.valueOf;
+
+
+public class PopulateProjectQualityGatesTableTest {
+  private static final String PROJECTS_TABLE_NAME = "projects";
+  private static final String QUALITY_GATES_TABLE_NAME = "quality_gates";
+  private static final String PROPERTIES_TABLE_NAME = "properties";
+  private static final int NUMBER_OF_PROJECTS_TO_INSERT = 5;
+
+  private final Random random = new Random();
+
+  @Rule
+  public CoreDbTester dbTester = CoreDbTester.createForSchema(PopulateProjectQualityGatesTableTest.class, "schema.sql");
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private PopulateProjectQualityGatesTable underTest = new PopulateProjectQualityGatesTable(dbTester.database());
+
+  @Test
+  public void copy_quality_gates_properties_to_project_qgate_table() throws SQLException {
+    long firstQualityGateId = insertQualityGate("qg1");
+    long secondQualityGateId = insertQualityGate("qg2");
+
+    for (long i = 1; i <= NUMBER_OF_PROJECTS_TO_INSERT; i++) {
+      long projectId = insertComponent("p" + i);
+      long qualityGateId = random.nextBoolean() ? firstQualityGateId : secondQualityGateId;
+      insertQualityGateProperty(projectId, qualityGateId);
+    }
+
+    underTest.execute();
+
+    List<ProjectQualityGate> qualityGates = getQualityGates();
+    Assert.assertEquals(NUMBER_OF_PROJECTS_TO_INSERT, qualityGates.size());
+
+    //must not delete properties
+    int propertiesCount = dbTester.countRowsOfTable(PROPERTIES_TABLE_NAME);
+    Assert.assertEquals(5, propertiesCount);
+
+    //should not fail if executed twice
+    underTest.execute();
+  }
+
+  private long insertQualityGate(String qualityGateUuid) {
+    dbTester.executeInsert(
+      QUALITY_GATES_TABLE_NAME,
+      "UUID", qualityGateUuid,
+      "NAME", "name_" + qualityGateUuid,
+      "IS_BUILT_IN", valueOf(true)
+    );
+    return (long) dbTester.selectFirst("select id as \"ID\" from quality_gates where uuid='" + qualityGateUuid + "'").get("ID");
+  }
+
+  private long insertComponent(String uuid) {
+    dbTester.executeInsert(
+      PROJECTS_TABLE_NAME,
+      "ORGANIZATION_UUID", "org_" + uuid,
+      "SCOPE", "PRJ",
+      "QUALIFIER", "TRK",
+      "UUID", uuid,
+      "UUID_PATH", "path_" + uuid,
+      "ROOT_UUID", "root_" + uuid,
+      "PROJECT_UUID", uuid,
+      "PRIVATE", valueOf(false));
+    return (long) dbTester.selectFirst("select id as \"ID\" from projects where uuid='" + uuid + "'").get("ID");
+  }
+
+  private void insertQualityGateProperty(Long projectId, Long qualityGateId) {
+    dbTester.executeInsert(PROPERTIES_TABLE_NAME,
+      "prop_key", "sonar.qualitygate",
+      "resource_id", projectId,
+      "is_empty", false,
+      "text_value", Long.toString(qualityGateId),
+      "created_at", Instant.now().toEpochMilli());
+  }
+
+  private List<ProjectQualityGate> getQualityGates() {
+    return dbTester.select("select pqg.project_uuid, pqg.quality_gate_uuid from project_qgates pqg " +
+      "join projects p on pqg.project_uuid = p.uuid " +
+      "join quality_gates qg on pqg.quality_gate_uuid = qg.uuid")
+      .stream()
+      .map(row -> {
+        String projectUuid = String.valueOf(row.get("PROJECT_UUID"));
+        String qualityGateUuid = String.valueOf(row.get("QUALITY_GATE_UUID"));
+        return new ProjectQualityGate(projectUuid, qualityGateUuid);
+      })
+      .collect(Collectors.toList());
+  }
+
+  private static class ProjectQualityGate {
+    final String projectUuid;
+    final String qualityGateUuid;
+
+    private ProjectQualityGate(String projectUuid, String qualityGateUuid) {
+      this.projectUuid = projectUuid;
+      this.qualityGateUuid = qualityGateUuid;
+    }
+  }
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest/schema.sql
new file mode 100644 (file)
index 0000000..d4dceda
--- /dev/null
@@ -0,0 +1,77 @@
+CREATE TABLE "PROJECTS" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+  "KEE" VARCHAR(400),
+  "UUID" VARCHAR(50) NOT NULL,
+  "UUID_PATH" VARCHAR(1500) NOT NULL,
+  "ROOT_UUID" VARCHAR(50) NOT NULL,
+  "PROJECT_UUID" VARCHAR(50) NOT NULL,
+  "MODULE_UUID" VARCHAR(50),
+  "MODULE_UUID_PATH" VARCHAR(1500),
+  "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50),
+  "NAME" VARCHAR(2000),
+  "DESCRIPTION" VARCHAR(2000),
+  "PRIVATE" BOOLEAN NOT NULL,
+  "TAGS" VARCHAR(500),
+  "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+  "SCOPE" VARCHAR(3),
+  "QUALIFIER" VARCHAR(10),
+  "DEPRECATED_KEE" VARCHAR(400),
+  "PATH" VARCHAR(2000),
+  "LANGUAGE" VARCHAR(20),
+  "COPY_COMPONENT_UUID" VARCHAR(50),
+  "LONG_NAME" VARCHAR(2000),
+  "DEVELOPER_UUID" VARCHAR(50),
+  "CREATED_AT" TIMESTAMP,
+  "AUTHORIZATION_UPDATED_AT" BIGINT,
+  "B_CHANGED" BOOLEAN,
+  "B_COPY_COMPONENT_UUID" VARCHAR(50),
+  "B_DESCRIPTION" VARCHAR(2000),
+  "B_ENABLED" BOOLEAN,
+  "B_UUID_PATH" VARCHAR(1500),
+  "B_LANGUAGE" VARCHAR(20),
+  "B_LONG_NAME" VARCHAR(500),
+  "B_MODULE_UUID" VARCHAR(50),
+  "B_MODULE_UUID_PATH" VARCHAR(1500),
+  "B_NAME" VARCHAR(500),
+  "B_PATH" VARCHAR(2000),
+  "B_QUALIFIER" VARCHAR(10)
+);
+CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID");
+CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE");
+CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID");
+CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID");
+CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID");
+CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID");
+CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER");
+
+CREATE TABLE "QUALITY_GATES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "UUID" VARCHAR(40) NOT NULL,
+  "NAME" VARCHAR(100) NOT NULL,
+  "IS_BUILT_IN" BOOLEAN NOT NULL,
+  "CREATED_AT" TIMESTAMP,
+  "UPDATED_AT" TIMESTAMP,
+);
+CREATE UNIQUE INDEX "UNIQ_QUALITY_GATES_UUID" ON "QUALITY_GATES" ("UUID");
+
+
+CREATE TABLE "PROPERTIES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "PROP_KEY" VARCHAR(512) NOT NULL,
+  "RESOURCE_ID" INTEGER,
+  "USER_ID" INTEGER,
+  "IS_EMPTY" BOOLEAN NOT NULL,
+  "TEXT_VALUE" VARCHAR(4000),
+  "CLOB_VALUE" CLOB,
+  "CREATED_AT" BIGINT
+);
+CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY");
+
+CREATE TABLE "PROJECT_QGATES" (
+"PROJECT_UUID" VARCHAR(40) NOT NULL,
+"QUALITY_GATE_UUID" VARCHAR(40) NOT NULL,
+
+CONSTRAINT "PK_PROJECT_QGATES" PRIMARY KEY ("PROJECT_UUID")
+);
+CREATE UNIQUE INDEX "UNIQ_PROJECT_QGATES" ON "PROJECT_QGATES" ("PROJECT_UUID", "QUALITY_GATE_UUID");
index a60ec55516b898f2954898fd52a67ea0535e2e56..f6f424fe983257c1a24e69f4a8a4dc0f831402ff 100644 (file)
@@ -32,8 +32,6 @@ import static java.util.Optional.ofNullable;
 
 public class QualityGateFinder {
 
-  public static final String SONAR_QUALITYGATE_PROPERTY = "sonar.qualitygate";
-
   private final DbClient dbClient;
 
   public QualityGateFinder(DbClient dbClient) {
@@ -46,8 +44,8 @@ public class QualityGateFinder {
    * It will first try to get the quality gate explicitly defined on a project, if none it will try to return default quality gate of the organization
    */
   public Optional<QualityGateData> getQualityGate(DbSession dbSession, OrganizationDto organization, ComponentDto component) {
-    Optional<QualityGateData> res = dbClient.projectQgateAssociationDao().selectQGateIdByComponentId(dbSession, component.getId())
-      .map(qualityGateId -> dbClient.qualityGateDao().selectById(dbSession, qualityGateId))
+    Optional<QualityGateData> res = dbClient.projectQgateAssociationDao().selectQGateUuidByComponentUuid(dbSession, component.uuid())
+      .map(qualityGateUuid -> dbClient.qualityGateDao().selectByUuid(dbSession, qualityGateUuid))
       .map(qualityGateDto -> new QualityGateData(qualityGateDto, false));
     if (res.isPresent()) {
       return res;
index 8bcf5a39e78592e53c90ae272c3975f7743e42e0..9ded531b6b2b49b4b40c25ee212fbd1c6c388081 100644 (file)
@@ -32,7 +32,6 @@ import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.server.component.ComponentFinder;
 
-import static org.sonar.server.qualitygate.QualityGateFinder.SONAR_QUALITYGATE_PROPERTY;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_ID;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_KEY;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
@@ -88,7 +87,6 @@ public class DeselectAction implements QualityGatesWsAction {
 
   private void dissociateProject(DbSession dbSession, OrganizationDto organization, ComponentDto project) {
     wsSupport.checkCanAdminProject(organization, project);
-    dbClient.propertiesDao().deleteProjectProperty(SONAR_QUALITYGATE_PROPERTY, project.getId(), dbSession);
     dbClient.projectQgateAssociationDao().deleteByProjectUuid(dbSession, project.uuid());
     dbSession.commit();
   }
index ce098eaa65f86981e0474a9f60535b29e21612c8..9b50241c2270f137d70d94f4989dac1d24d9be0e 100644 (file)
@@ -30,7 +30,6 @@ import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.qualitygate.QualityGateFinder;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static org.sonar.server.qualitygate.QualityGateFinder.SONAR_QUALITYGATE_PROPERTY;
 
 public class DestroyAction implements QualityGatesWsAction {
 
@@ -71,7 +70,6 @@ public class DestroyAction implements QualityGatesWsAction {
       checkArgument(!defaultQualityGate.getId().equals(qualityGate.getId()), "The default quality gate cannot be removed");
       wsSupport.checkCanEdit(qualityGate);
 
-      dbClient.propertiesDao().deleteByKeyAndValue(dbSession, SONAR_QUALITYGATE_PROPERTY, String.valueOf(qualityGate.getId()));
       dbClient.projectQgateAssociationDao().deleteByQGateUuid(dbSession, qualityGate.getUuid());
       dbClient.qualityGateDao().delete(qualityGate, dbSession);
       dbSession.commit();
index e8fc3e5eb641d7bed7d0b881728190aa5b849c10..9dd6a1f5ab0a69da508f03dc16101fed530f0058 100644 (file)
@@ -29,13 +29,11 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.property.PropertyDto;
 import org.sonar.db.qualitygate.QGateWithOrgDto;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.ComponentFinder.ParamNames;
 
-import static org.sonar.server.qualitygate.QualityGateFinder.SONAR_QUALITYGATE_PROPERTY;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_SELECT;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_ID;
@@ -57,9 +55,9 @@ public class SelectAction implements QualityGatesWsAction {
   public void define(WebService.NewController controller) {
     WebService.NewAction action = controller.createAction(ACTION_SELECT)
       .setDescription("Associate a project to a quality gate.<br>" +
-        "The '%s' or '%s' must be provided.<br>" +
-        "Project id as a numeric value is deprecated since 6.1. Please use the id similar to '%s'.<br>" +
-        "Requires the 'Administer Quality Gates' permission.",
+          "The '%s' or '%s' must be provided.<br>" +
+          "Project id as a numeric value is deprecated since 6.1. Please use the id similar to '%s'.<br>" +
+          "Requires the 'Administer Quality Gates' permission.",
         PARAM_PROJECT_ID, PARAM_PROJECT_KEY,
         Uuids.UUID_EXAMPLE_02)
       .setPost(true)
@@ -95,22 +93,17 @@ public class SelectAction implements QualityGatesWsAction {
       ComponentDto project = getProject(dbSession, organization, projectId, projectKey);
       wsSupport.checkCanAdminProject(organization, project);
 
-      dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
-        .setKey(SONAR_QUALITYGATE_PROPERTY)
-        .setResourceId(project.getId())
-        .setValue(String.valueOf(qualityGate.getId())));
-
       QualityGateDto currentQualityGate = dbClient.qualityGateDao().selectByProjectUuid(dbSession, project.uuid());
       if (currentQualityGate == null) {
         // project uses the default profile
         dbClient.projectQgateAssociationDao()
           .insertProjectQGateAssociation(dbSession, project.uuid(), qualityGate.getUuid());
+        dbSession.commit();
       } else if (!qualityGate.getUuid().equals(currentQualityGate.getUuid())) {
         dbClient.projectQgateAssociationDao()
           .updateProjectQGateAssociation(dbSession, project.uuid(), qualityGate.getUuid());
+        dbSession.commit();
       }
-
-      dbSession.commit();
     }
     response.noContent();
   }
index 8ef3fedbd48e84100cffa09cfcf08a10787cb3af..c3c7ad871774ad6f107e31f958918df5d42718e7 100644 (file)
@@ -27,11 +27,9 @@ import org.sonar.api.server.ws.Change;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.property.PropertyDto;
 import org.sonar.db.qualitygate.QGateWithOrgDto;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.component.TestComponentFinder;
@@ -47,7 +45,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
-import static org.sonar.server.qualitygate.QualityGateFinder.SONAR_QUALITYGATE_PROPERTY;
 
 public class DeselectActionTest {
 
@@ -59,7 +56,6 @@ public class DeselectActionTest {
   public DbTester db = DbTester.create();
 
   private DbClient dbClient = db.getDbClient();
-  private DbSession dbSession = db.getSession();
   private TestDefaultOrganizationProvider organizationProvider = TestDefaultOrganizationProvider.from(db);
   private DeselectAction underTest = new DeselectAction(dbClient, TestComponentFinder.from(db),
     new QualityGatesWsSupport(db.getDbClient(), userSession, organizationProvider));
@@ -300,10 +296,6 @@ public class DeselectActionTest {
   }
 
   private void associateProjectToQualityGate(ComponentDto project, QualityGateDto qualityGate) {
-    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
-      .setResourceId(project.getId())
-      .setValue(qualityGate.getId().toString())
-      .setKey(SONAR_QUALITYGATE_PROPERTY));
     db.qualityGates().associateProjectToQualityGate(project, qualityGate);
     db.commit();
   }
@@ -313,8 +305,6 @@ public class DeselectActionTest {
     assertThat(qGateUuid)
       .isNotNull()
       .isEmpty();
-
-    assertThat(dbClient.propertiesDao().selectProjectProperty(project.getId(), SONAR_QUALITYGATE_PROPERTY)).isNull();
   }
 
   private void assertSelected(QGateWithOrgDto qualityGate, ComponentDto project) {
@@ -323,7 +313,5 @@ public class DeselectActionTest {
       .isNotNull()
       .isNotEmpty()
       .hasValue(qualityGate.getUuid());
-    String qGateId = dbClient.propertiesDao().selectProjectProperty(project.getId(), SONAR_QUALITYGATE_PROPERTY).getValue();
-    assertThat(qGateId).isEqualTo(String.valueOf(qualityGate.getId()));
   }
 }
index 9fe569ccaf2b65f062c4e64726e21b1444851d3a..f72cfde473991c352471e6e57de984a010c3eeb4 100644 (file)
@@ -113,11 +113,9 @@ public class DestroyActionTest {
       .setParam(PARAM_ORGANIZATION, organization.getKey())
       .execute();
 
-    assertThat(db.getDbClient().qualityGateDao().selectByOrganizationAndId(dbSession, organization, qualityGate.getId()))
-      .isNull();
-    assertThat(db.getDbClient().propertiesDao().selectProjectProperties(prj1.getDbKey()))
+    assertThat(db.getDbClient().projectQgateAssociationDao().selectQGateUuidByComponentUuid(dbSession, prj1.uuid()))
       .isEmpty();
-    assertThat(db.getDbClient().propertiesDao().selectProjectProperties(prj2.getDbKey()))
+    assertThat(db.getDbClient().projectQgateAssociationDao().selectQGateUuidByComponentUuid(dbSession, prj2.uuid()))
       .isEmpty();
 
     assertThat(db.getDbClient().projectQgateAssociationDao().selectQGateUuidByComponentUuid(dbSession, prj1.uuid()))
index d38f148f5c8704069fa0dd1175477123eaf8fd9c..18ac6127aa47d8805daa9ce895e6a9348606e0fb 100644 (file)
@@ -42,7 +42,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.web.UserRole.ADMIN;
 import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
-import static org.sonar.server.qualitygate.QualityGateFinder.SONAR_QUALITYGATE_PROPERTY;
 
 public class SelectActionTest {
 
@@ -341,7 +340,6 @@ public class SelectActionTest {
   }
 
   private void assertSelected(QualityGateDto qualityGate, ComponentDto project) {
-    assertThat(dbClient.propertiesDao().selectProjectProperty(project.getId(), SONAR_QUALITYGATE_PROPERTY).getValue()).isEqualTo(qualityGate.getId().toString());
     Optional<String> qGateUuid = db.qualityGates().selectQGateUuidByComponentUuid(project.uuid());
     assertThat(qGateUuid)
       .isNotNull()