Browse Source

SONAR-8115 storing project quality gate in table (#1919)

* migrate properties to project_qgate table

* use project_qgates table instead of property

* change usage of project quality gate in CE
tags/8.0
Jacek 4 years ago
parent
commit
eb9b158713
27 changed files with 441 additions and 155 deletions
  1. 7
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateService.java
  2. 12
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java
  3. 5
    23
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java
  4. 56
    0
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java
  5. 9
    23
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java
  6. 0
    10
      server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationDao.java
  7. 0
    3
      server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationMapper.java
  8. 4
    4
      server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationQuery.java
  9. 5
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateDao.java
  10. 2
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateMapper.java
  11. 5
    13
      server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/ProjectQgateAssociationMapper.xml
  12. 7
    0
      server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateMapper.xml
  13. 5
    19
      server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationDaoTest.java
  14. 22
    10
      server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDaoTest.java
  15. 2
    9
      server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java
  16. 2
    1
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80.java
  17. 80
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTable.java
  18. 1
    1
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80Test.java
  19. 131
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest.java
  20. 77
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest/schema.sql
  21. 2
    4
      server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java
  22. 0
    2
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/DeselectAction.java
  23. 0
    2
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/DestroyAction.java
  24. 5
    12
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java
  25. 0
    12
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DeselectActionTest.java
  26. 2
    4
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DestroyActionTest.java
  27. 0
    2
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SelectActionTest.java

+ 7
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateService.java View 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);

}

+ 12
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java View 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());


+ 5
- 23
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStep.java View 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() {

+ 56
- 0
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java View 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());
}
}

+ 9
- 23
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadQualityGateStepTest.java View 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());


+ 0
- 10
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationDao.java View 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)

+ 0
- 3
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationMapper.java View 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);


+ 4
- 4
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationQuery.java View 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() {

+ 5
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateDao.java View 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());

+ 2
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateMapper.java View File

@@ -57,5 +57,7 @@ public interface QualityGateMapper {

void ensureOneBuiltInQualityGate(String builtInQualityName);

QualityGateDto selectByUuid(String uuid);

QualityGateDto selectByProjectUuid(@Param("projectUuid") String projectUuid);
}

+ 5
- 13
server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/ProjectQgateAssociationMapper.xml View 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}
@@ -15,10 +16,10 @@
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">
@@ -27,15 +28,6 @@
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

+ 7
- 0
server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateMapper.xml View File

@@ -43,6 +43,13 @@
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"/>

+ 5
- 19
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationDaoTest.java View 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();

+ 22
- 10
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDaoTest.java View 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();

+ 2
- 9
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java View 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);
}
}

+ 2
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80.java View 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);
}
}

+ 80
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTable.java View File

@@ -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;
}
}

}

+ 1
- 1
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80Test.java View File

@@ -35,7 +35,7 @@ public class DbVersion80Test {

@Test
public void verify_migration_count() {
verifyMigrationCount(underTest, 3);
verifyMigrationCount(underTest, 4);
}

}

+ 131
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest.java View File

@@ -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;
}
}
}

+ 77
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v80/PopulateProjectQualityGatesTableTest/schema.sql View File

@@ -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");

+ 2
- 4
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java View 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;

+ 0
- 2
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/DeselectAction.java View 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();
}

+ 0
- 2
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/DestroyAction.java View 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();

+ 5
- 12
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SelectAction.java View 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();
}

+ 0
- 12
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DeselectActionTest.java View 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()));
}
}

+ 2
- 4
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DestroyActionTest.java View 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()))

+ 0
- 2
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SelectActionTest.java View 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()

Loading…
Cancel
Save