return selectAssociatedToProjectUuidAndLanguages(dbSession, project.getUuid(), languages);
}
+ public List<String> selectQProfileUuidsByProjectUuid(DbSession dbSession, String projectUuid) {
+ return mapper(dbSession).selectQProfileUuidsByProjectUuid(projectUuid);
+ }
+
public List<QProfileDto> selectByLanguage(DbSession dbSession, String language) {
return mapper(dbSession).selectByLanguage(language);
}
@Param("projectUuid") String projectUuid,
@Param("languages") Collection<String> languages);
+ List<String> selectQProfileUuidsByProjectUuid(@Param("projectUuid") String projectUuid);
+
void insertProjectProfileAssociation(
@Param("uuid") String uuid,
@Param("projectUuid") String projectUuid,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.db.report;
+
+import javax.annotation.CheckForNull;
+
+public class QualityGateFindingDto {
+ public static final String NEW_CODE_METRIC_PREFIX = "new_";
+
+ private String description = null;
+ private String operator = null;
+ private String kee = null;
+ private Boolean isEnabled = null;
+ private String valueType = null;
+ private Double bestValue = null;
+ private Double worstValue = null;
+ private Boolean optimizedBestValue = null;
+ private String errorThreshold = null;
+ private Integer decimalScale = null;
+
+ private String getOperator() {
+ return operator;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getOperatorDescription() {
+ return OperatorDescription.valueOf(getOperator()).getDescription();
+ }
+
+ public Boolean isNewCodeMetric() {
+ return kee.startsWith(NEW_CODE_METRIC_PREFIX);
+ }
+
+ public boolean isEnabled() {
+ return isEnabled;
+ }
+
+ public String getValueType() {
+ return valueType;
+ }
+
+ @CheckForNull
+ public Double getBestValue() {
+ return bestValue;
+ }
+
+ @CheckForNull
+ public Double getWorstValue() {
+ return worstValue;
+ }
+
+ public String getErrorThreshold() {
+ return errorThreshold;
+ }
+
+ public boolean isOptimizedBestValue() {
+ return optimizedBestValue;
+ }
+
+ @CheckForNull
+ public Integer getDecimalScale() {
+ return decimalScale;
+ }
+
+ public enum OperatorDescription {
+ LT("Is Less Than"),
+ GT("Is Greater Than"),
+ EQ("Is Equal To"),
+ NE("Is Not Equal To");
+
+ private final String desc;
+
+ OperatorDescription(String desc) {
+ this.desc = desc;
+ }
+
+ public String getDescription() {
+ return desc;
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.db.report;
+
+import javax.annotation.CheckForNull;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.RuleType;
+import org.sonar.db.rule.SeverityUtil;
+
+public class QualityProfileFindingDto {
+ private String language = null;
+ private String title = null;
+ private String repository = null;
+ private String ruleKey = null;
+ private String status = null;
+ private Integer type = null;
+ private Integer severity = null;
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public RuleKey getReferenceKey() {
+ return RuleKey.of(repository, ruleKey);
+ }
+
+ public RuleStatus getStatus() {
+ return RuleStatus.valueOf(status);
+ }
+
+ public RuleType getType() {
+ return RuleType.valueOf(type);
+ }
+
+ @CheckForNull
+ public String getSeverity() {
+ return SeverityUtil.getSeverityFromOrdinal(severity);
+ }
+}
mapper(dbSession).scrollIssues(branchUuid, handler);
}
+ public void getQualityGateFindings(DbSession dbSession, String qualityGateUuid, ResultHandler<QualityGateFindingDto> handler) {
+ mapper(dbSession).getQualityGateFindings(qualityGateUuid, handler);
+ }
+
+ public void getQualityProfileFindings(DbSession dbSession, String qualityProfileUuid, ResultHandler<QualityProfileFindingDto> handler) {
+ mapper(dbSession).getQualityProfileFindings(qualityProfileUuid, handler);
+ }
+
private static RegulatoryReportMapper mapper(DbSession dbSession) {
return dbSession.getMapper(RegulatoryReportMapper.class);
}
public interface RegulatoryReportMapper {
void scrollIssues(String branchUuid, ResultHandler<IssueFindingDto> handler);
+
+ void getQualityGateFindings(String qualityGateUuid, ResultHandler<QualityGateFindingDto> handler);
+
+ void getQualityProfileFindings(String qualityProfileUuid, ResultHandler<QualityProfileFindingDto> handler);
}
and pqp.project_uuid = #{projectUuid, jdbcType=VARCHAR}
</select>
+ <select id="selectQProfileUuidsByProjectUuid" parameterType="String" resultType="String">
+ SELECT profile_key
+ FROM project_qprofiles
+ <where>
+ AND project_uuid=#{projectUuid}
+ </where>
+ </select>
+
<insert id="insertProjectProfileAssociation" useGeneratedKeys="false">
insert into project_qprofiles (
uuid,
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
<mapper namespace="org.sonar.db.report.RegulatoryReportMapper">
+ <sql id="qualityGateFindingColumns">
+ m.description as description,
+ qgc.operator as operator,
+ m.name as kee,
+ m.enabled as isEnabled,
+ m.val_type as valueType,
+ m.best_value as bestValue,
+ m.worst_value as worstValue,
+ m.optimized_best_value as optimizedBestValue,
+ qgc.value_error as errorThreshold,
+ m.decimal_scale as decimalScale
+ </sql>
+
+ <sql id="qualityProfileFindingColumns">
+ r.language as language,
+ r.name as title,
+ r.plugin_name as repository,
+ r.plugin_rule_key as ruleKey,
+ r.status as status,
+ r.rule_type as type,
+ r.priority as defaultSeverity,
+ ar.failure_level as severity
+ </sql>
+
<sql id="issueColumns">
i.kee as kee,
i.severity as severity,
<include refid="org.sonar.db.issue.IssueMapper.isNewCodeReferenceIssue"/>
</sql>
+ <select id="getQualityGateFindings" parameterType="String" resultType="org.sonar.db.report.QualityGateFindingDto">
+ select
+ <include refid="qualityGateFindingColumns"/>
+ from quality_gates qg
+ left join quality_gate_conditions qgc on qgc.qgate_uuid = qg.uuid
+ left join metrics m on m.uuid = qgc.metric_uuid
+ where qg.uuid=#{qualityGateUuid,jdbcType=VARCHAR}
+ </select>
+
+ <select id="getQualityProfileFindings" parameterType="String" resultType="org.sonar.db.report.QualityProfileFindingDto" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
+ select
+ <include refid="qualityProfileFindingColumns"/>
+ from rules r
+ left join active_rules ar on ar.rule_uuid = r.uuid
+ inner join org_qprofiles oqp on oqp.rules_profile_uuid = ar.profile_uuid
+ where oqp.uuid=#{qualityProfileUuid,jdbcType=VARCHAR}
+ </select>
+
<select id="scrollIssues" parameterType="String" resultType="org.sonar.db.report.IssueFindingDto" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
select
<include refid="issueColumns"/>
where i.project_uuid=#{branchUuid,jdbcType=VARCHAR}
and i.status !='CLOSED'
</select>
-
</mapper>
.isEmpty();
}
+ @Test
+ public void test_selectQProfileUuidsByProjectUuid() {
+ ProjectDto project1 = db.components().insertPublicProjectDto();
+ ProjectDto project2 = db.components().insertPublicProjectDto();
+ ProjectDto project3 = db.components().insertPublicProjectDto();
+ QProfileDto javaProfile = db.qualityProfiles().insert(p -> p.setLanguage("java"));
+ QProfileDto jsProfile = db.qualityProfiles().insert(p -> p.setLanguage("js"));
+ QProfileDto cProfile = db.qualityProfiles().insert(p -> p.setLanguage("c"));
+ db.qualityProfiles().associateWithProject(project1, javaProfile, cProfile);
+ db.qualityProfiles().associateWithProject(project2, jsProfile);
+
+ assertThat(underTest.selectQProfileUuidsByProjectUuid(dbSession, project1.getUuid()))
+ .hasSize(2)
+ .containsExactly(javaProfile.getKee(), cProfile.getKee());
+
+ assertThat(underTest.selectQProfileUuidsByProjectUuid(dbSession, project2.getUuid()))
+ .hasSize(1)
+ .containsExactly(jsProfile.getKee());
+
+ assertThat(underTest.selectQProfileUuidsByProjectUuid(dbSession, project3.getUuid()))
+ .isEmpty();
+ }
+
@Test
public void test_updateProjectProfileAssociation() {
ProjectDto project = db.components().insertPrivateProjectDto();
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
+import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.issue.IssueDto;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.qualitygate.QualityGateConditionDto;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.db.qualityprofile.ActiveRuleDto;
+import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.rule.RuleDto;
+import org.sonar.db.rule.SeverityUtil;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.within;
import static org.sonar.api.issue.Issue.RESOLUTION_WONT_FIX;
import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.report.QualityGateFindingDto.NEW_CODE_METRIC_PREFIX;
public class RegulatoryReportDaoTest {
private static final String PROJECT_UUID = "prj_uuid";
private static final String PROJECT_KEY = "prj_key";
private static final String FILE_UUID = "file_uuid";
private static final String FILE_KEY = "file_key";
+ private static final String BRANCH_UUID = "branch_uuid";
+ private static final String BRANCH_NAME = "branch";
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
file = db.components().insertComponent(newFileDto(project).setUuid(FILE_UUID).setDbKey(FILE_KEY));
}
+ @Test
+ public void getQualityGateFindings_returns_all_quality_gate_details_for_project() {
+ ProjectDto project = db.components().insertPublicProjectDto();
+ BranchDto branch = db.components().insertProjectBranch(project).setBranchType(BranchType.BRANCH);
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ db.qualityGates().setDefaultQualityGate(gate);
+
+ MetricDto metric1 = db.measures().insertMetric(m -> m.setDescription("metric 1 description").setDecimalScale(0));
+ QualityGateConditionDto condition1 = db.qualityGates().addCondition(gate, metric1);
+
+ MetricDto metric2 = db.measures().insertMetric(m -> m.setDescription("metric 2 description").setDecimalScale(1));
+ QualityGateConditionDto condition2 = db.qualityGates().addCondition(gate, metric2);
+
+ MetricDto metric3 = db.measures().insertMetric(m -> m.setDescription("metric 3 description").setDecimalScale(0));
+ QualityGateConditionDto condition3 = db.qualityGates().addCondition(gate, metric3);
+
+ db.qualityGates().associateProjectToQualityGate(project, gate);
+ db.commit();
+
+ List<QualityGateFindingDto> findings = new ArrayList<>();
+ underTest.getQualityGateFindings(db.getSession(), gate.getUuid(), result -> findings.add(result.getResultObject()));
+
+ QualityGateFindingDto finding = findings.stream().filter(f -> f.getDescription().equals("metric 1 description")).findFirst().get();
+
+ // check fields
+ assertThat(findings).hasSize(3);
+ assertThat(findings.stream().map(f -> f.getDescription()).collect(Collectors.toSet())).containsExactlyInAnyOrder("metric 1 description", "metric 2 description", "metric 3 description");
+ assertThat(finding.getDescription()).isEqualTo(metric1.getDescription());
+ assertThat(finding.getOperatorDescription()).isEqualTo(QualityGateFindingDto.OperatorDescription.valueOf(condition1.getOperator()).getDescription());
+ assertThat(finding.getErrorThreshold()).isEqualTo(condition1.getErrorThreshold());
+ assertThat(finding.getValueType()).isEqualTo(metric1.getValueType());
+ assertThat(finding.isNewCodeMetric()).isEqualTo(metric1.getKey().startsWith(NEW_CODE_METRIC_PREFIX));
+ assertThat(finding.isEnabled()).isEqualTo(metric1.isEnabled());
+ assertThat(finding.getBestValue()).isEqualTo(metric1.getBestValue(), within(0.00001));
+ assertThat(finding.getWorstValue()).isEqualTo(metric1.getWorstValue(), within(0.00001));
+ assertThat(finding.isOptimizedBestValue()).isEqualTo(metric1.isOptimizedBestValue());
+ assertThat(finding.getDecimalScale()).isEqualTo(metric1.getDecimalScale());
+ }
+
+ @Test
+ public void getQualityProfileFindings_returns_all_quality_profile_details_for_project() {
+ String projectUuid = "project_uuid";
+ String projectKey = "project_key";
+ String branchUuid = "branch_uuid";
+ String branchName = "branch";
+
+ BranchDto branch = new BranchDto()
+ .setBranchType(BranchType.BRANCH)
+ .setKey(branchName)
+ .setUuid(branchUuid)
+ .setProjectUuid(projectUuid);
+
+ db.getDbClient().branchDao().insert(db.getSession(), branch);
+
+ ProjectDto project = db.components().insertPublicProjectDto(t -> t.setProjectUuid(projectUuid)
+ .setUuid(projectUuid)
+ .setDbKey(projectKey)
+ .setMainBranchProjectUuid(branchUuid));
+
+ QProfileDto cppQPWithoutActiveRules = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage("cpp"));
+ db.qualityProfiles().setAsDefault(cppQPWithoutActiveRules);
+
+ QProfileDto javaBuiltInQPWithActiveRules = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage("java"));
+ RuleDto rule1 = db.rules().insert(r -> r.setName("rule 1 title"));
+ ActiveRuleDto activeRule1 = db.qualityProfiles().activateRule(javaBuiltInQPWithActiveRules, rule1);
+ RuleDto rule2 = db.rules().insert(r -> r.setName("rule 2 title"));
+ ActiveRuleDto activeRule2 = db.qualityProfiles().activateRule(javaBuiltInQPWithActiveRules, rule2);
+ RuleDto rule3 = db.rules().insert(r -> r.setName("rule 3 title"));
+ ActiveRuleDto activeRule3 = db.qualityProfiles().activateRule(javaBuiltInQPWithActiveRules, rule3);
+
+ db.qualityProfiles().associateWithProject(project, cppQPWithoutActiveRules, javaBuiltInQPWithActiveRules);
+ db.getSession().commit();
+
+ List<QualityProfileFindingDto> findings = new ArrayList<>();
+ underTest.getQualityProfileFindings(db.getSession(), javaBuiltInQPWithActiveRules.getKee(), result -> findings.add(result.getResultObject()));
+
+ QualityProfileFindingDto finding = findings.stream().filter(f -> f.getTitle().equals("rule 1 title")).findFirst().get();
+
+ assertThat(findings).hasSize(3);
+ assertThat(findings.stream().map(f -> f.getTitle()).collect(Collectors.toSet())).containsExactlyInAnyOrder("rule 1 title", "rule 2 title", "rule 3 title");
+ assertThat(finding.getLanguage()).isEqualTo(rule1.getLanguage());
+ assertThat(finding.getTitle()).isEqualTo(rule1.getName());
+ assertThat(finding.getReferenceKey()).isEqualTo(RuleKey.of(rule1.getRepositoryKey(), rule1.getRuleKey()));
+ assertThat(finding.getStatus()).isEqualTo(rule1.getStatus());
+ assertThat(finding.getType()).isEqualTo(RuleType.valueOf(rule1.getType()));
+ assertThat(finding.getSeverity()).isEqualTo(SeverityUtil.getSeverityFromOrdinal(activeRule1.getSeverity()));
+ }
+
@Test
public void scrollIssues_returns_all_non_closed_issues_for_project() {
IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setStatus("OPEN").setResolution(null));