.setEngineId("eslint")
.setRuleId("no-cond-assign")
.setName(repeat("a", 201))
- .setDescription(repeat("a", 16_777_216))
+ .setDescription(repeat("a", 1_000_000))
.setSeverity(Constants.Severity.BLOCKER)
.setType(ScannerReport.IssueType.BUG)
.build());
RuleDto rule = underTest.persistAndIndex(dbSession, addHocRule);
assertThat(rule.getMetadata().getAdHocName()).isEqualTo(repeat("a", 200));
- assertThat(rule.getMetadata().getAdHocDescription()).isEqualTo(repeat("a", 16_777_215));
+ assertThat(rule.getMetadata().getAdHocDescription()).isEqualTo(repeat("a", 1_000_000));
}
@Test
import java.util.LinkedList;
import java.util.List;
+import java.util.Optional;
+import java.util.Set;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
+import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.SeverityUtil;
+import static java.util.Optional.ofNullable;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.DEFAULT_KEY;
+
public class ExportRuleDto {
private String activeRuleUuid = null;
private String repository = null;
private String rule = null;
private String name = null;
- private String description = null;
private String extendedDescription = null;
private String template = null;
private Integer severity = null;
private Integer type = null;
private String tags = null;
- private List<ExportRuleParamDto> params;
+ private List<ExportRuleParamDto> params = null;
+
+ private Set<RuleDescriptionSectionDto> ruleDescriptionSectionDtos = null;
public boolean isCustomRule() {
return template != null;
return tags;
}
- public String getDescription() {
- return description;
- }
-
public String getName() {
return name;
}
void setParams(List<ExportRuleParamDto> params) {
this.params = params;
}
+
+ public Set<RuleDescriptionSectionDto> getRuleDescriptionSections() {
+ return ruleDescriptionSectionDtos;
+ }
+
+ public Optional<RuleDescriptionSectionDto> getDefaultRuleDescriptionSectionDto() {
+ return findExistingSectionWithSameKey(DEFAULT_KEY);
+ }
+
+ private Optional<RuleDescriptionSectionDto> findExistingSectionWithSameKey(String ruleDescriptionSectionKey) {
+ return ofNullable(ruleDescriptionSectionDtos).flatMap(sections ->
+ sections.stream().filter(section -> section.getKey().equals(ruleDescriptionSectionKey)).findAny());
+ }
}
import static org.sonar.api.utils.Preconditions.checkArgument;
public class RuleDescriptionSectionDto {
- static final String DEFAULT_KEY = "default";
+ public static final String DEFAULT_KEY = "default";
private final String uuid;
private final String key;
<mapper namespace="org.sonar.db.qualityprofile.QualityProfileExportMapper">
+ <sql id="selectRuleDescriptionSectionColumns">
+ rds.uuid as "rds_uuid",
+ rds.kee as "rds_kee",
+ rds.description as "rds_description",
+ </sql>
+
+ <sql id="leftOuterJoinRulesDescriptionSections">
+ left outer join rule_desc_sections rds on
+ rds.rule_uuid = r.uuid
+ </sql>
+
<sql id="exportRuleColumns">
+ <include refid="selectRuleDescriptionSectionColumns"/>
a.uuid as "activeRuleUuid",
a.failure_level as "severity",
r.plugin_rule_key as "rule",
r.plugin_name as "repository",
r.priority as "defaultSeverity",
r.name,
- r.description,
r.description_format as "descriptionFormat",
r.rule_type as "type",
rt.plugin_rule_key as "template",
p.value as value
</sql>
- <select id="selectByProfileUuid" parameterType="string" resultType="org.sonar.db.qualityprofile.ExportRuleDto">
+ <resultMap id="ruleDefinitionResultMap" type="org.sonar.db.qualityprofile.ExportRuleDto">
+ <id property="activeRuleUuid" column="activeRuleUuid"/>
+ <result property="ruleKey" column="ruleKey"/>
+ <result property="severity" column="severity"/>
+ <result property="rule" column="rule"/>
+ <result property="repository" column="repository"/>
+ <result property="name" column="name"/>
+ <result property="type" column="type"/>
+ <result property="template" column="template"/>
+ <result property="extendedDescription" column="extendedDescription"/>
+ <result property="tags" column="tags"/>
+
+ <collection property="ruleDescriptionSectionDtos" ofType="org.sonar.db.rule.RuleDescriptionSectionDto">
+ <id property="uuid" column="rds_uuid"/>
+ <result property="key" column="rds_kee"/>
+ <result property="description" column="rds_description" typeHandler="org.apache.ibatis.type.StringTypeHandler"/>
+ </collection>
+
+ </resultMap>
+
+ <select id="selectByProfileUuid" parameterType="string" resultMap="ruleDefinitionResultMap">
select
<include refid="exportRuleColumns"/>
from active_rules a
inner join rules r on r.uuid = a.rule_uuid and r.status != 'REMOVED'
left join rules rt on rt.uuid = r.template_uuid
left join rules_metadata rm on rm.rule_uuid = r.uuid
+ <include refid="leftOuterJoinRulesDescriptionSections"/>
where oqp.uuid = #{id, jdbcType=VARCHAR}
</select>
<result property="createdAtFromDefinition" column="createdAtFromDefinition"/>
<result property="updatedAtFromDefinition" column="updatedAtFromDefinition"/>
- <result property="noteData" column="noteData"/>
+ <result property="noteData" column="noteData" typeHandler="org.apache.ibatis.type.StringTypeHandler"/>
<result property="noteUserUuid" column="noteUserUuid"/>
<result property="noteCreatedAt" column="noteCreatedAt"/>
<result property="noteUpdatedAt" column="noteUpdatedAt"/>
<result property="remediationBaseEffort" column="remediationBaseEffort"/>
<result property="tagsField" column="tagsField"/>
<result property="adHocName" column="adHocName"/>
- <result property="adHocDescription" column="adHocDescription"/>
+ <result property="adHocDescription" column="adHocDescription" typeHandler="org.apache.ibatis.type.StringTypeHandler"/>
<result property="adHocSeverity" column="adHocSeverity"/>
<result property="adHocType" column="adHocType"/>
<result property="createdAtFromMetadata" column="createdAtFromMetadata"/>
<collection property="ruleDescriptionSectionDtos" ofType="org.sonar.db.rule.RuleDescriptionSectionDto">
<id property="uuid" column="rds_uuid"/>
<result property="key" column="rds_kee"/>
- <result property="description" column="rds_description"/>
+ <result property="description" column="rds_description" typeHandler="org.apache.ibatis.type.StringTypeHandler"/>
</collection>
</resultMap>
<collection property="ruleDescriptionSectionDtos" ofType="org.sonar.db.rule.RuleDescriptionSectionDto">
<id property="uuid" column="rds_uuid"/>
<result property="key" column="rds_kee"/>
- <result property="description" column="rds_description"/>
+ <result property="description" column="rds_description" typeHandler="org.apache.ibatis.type.StringTypeHandler"/>
</collection>
</resultMap>
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleMetadataDto;
import org.sonar.db.rule.RuleParamDto;
String language = "java";
RuleDefinitionDto ruleTemplate = createRule(language);
RuleDefinitionDto customRule = createRule(language, RuleStatus.READY, ruleTemplate.getUuid());
+ var customRuleDescription = customRule.getDefaultRuleDescriptionSectionDto().getDescription();
RuleMetadataDto customRuleMetadata = createRuleMetadata(new RuleMetadataDto()
.setRuleUuid(customRule.getUuid())
.setNoteData("Extended description")
.setTags(Sets.newHashSet("tag1", "tag2", "tag3")));
RuleDefinitionDto rule = createRule(language, RuleStatus.READY, null);
+ var ruleDescription = rule.getDefaultRuleDescriptionSectionDto().getDescription();
RuleMetadataDto ruleMetadata = createRuleMetadata(new RuleMetadataDto()
.setRuleUuid(rule.getUuid()));
QProfileDto profile = createProfile(language);
assertThat(exportCustomRuleDto).isNotNull();
assertThat(exportCustomRuleDto.isCustomRule()).isTrue();
assertThat(exportCustomRuleDto.getParams()).isEmpty();
- //FIXME SONAR-16314
- assertThat(exportCustomRuleDto.getDescription()).isEqualTo(customRule.getRuleDescriptionSectionDtos().stream().map(RuleDescriptionSectionDto::getDescription).collect(Collectors.joining()));
+ assertThat(exportCustomRuleDto.getRuleDescriptionSections().iterator().next().getDescription()).isEqualTo(customRuleDescription);
assertThat(exportCustomRuleDto.getExtendedDescription()).isEqualTo(customRuleMetadata.getNoteData());
assertThat(exportCustomRuleDto.getName()).isEqualTo(customRule.getName());
assertThat(exportCustomRuleDto.getRuleKey()).isEqualTo(customRule.getKey());
assertThat(exportRuleDto).isNotNull();
assertThat(exportRuleDto.isCustomRule()).isFalse();
assertThat(exportRuleDto.getParams()).isEmpty();
- //FIXME SONAR-16314
- assertThat(exportRuleDto.getDescription()).isEqualTo(rule.getRuleDescriptionSectionDtos().stream().map(RuleDescriptionSectionDto::getDescription).collect(Collectors.joining()));
+ assertThat(exportRuleDto.getRuleDescriptionSections().iterator().next().getDescription()).isEqualTo(ruleDescription);
assertThat(exportRuleDto.getExtendedDescription()).isEqualTo(ruleMetadata.getNoteData());
assertThat(exportRuleDto.getName()).isEqualTo(rule.getName());
assertThat(exportRuleDto.getRuleKey()).isEqualTo(rule.getKey());
}
public static RuleDefinitionDto newRule(RuleKey key) {
- RuleDefinitionDto ruleDefinitionDto = newRuleWithoutSection(key);
+ RuleDefinitionDto ruleDefinitionDto = newRuleWithoutDescriptionSection(key);
ruleDefinitionDto.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "description_" + randomAlphabetic(5)));
return ruleDefinitionDto;
}
- public static RuleDefinitionDto newRuleWithoutSection() {
- return newRuleWithoutSection(randomRuleKey());
+ public static RuleDefinitionDto newRuleWithoutDescriptionSection() {
+ return newRuleWithoutDescriptionSection(randomRuleKey());
}
- public static RuleDefinitionDto newRuleWithoutSection(RuleKey ruleKey) {
+ public static RuleDefinitionDto newRuleWithoutDescriptionSection(RuleKey ruleKey) {
return new RuleDefinitionDto()
.setRepositoryKey(ruleKey.repository())
.setRuleKey(ruleKey.rule())
import org.junit.runner.RunWith;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
+import org.sonar.db.rule.RuleTesting;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
-import static org.sonar.db.rule.RuleTesting.newRuleWithoutSection;
+import static org.sonar.db.rule.RuleTesting.newRuleWithoutDescriptionSection;
@RunWith(DataProviderRunner.class)
public class HotspotRuleDescriptionTest {
@Test
public void parse_returns_all_empty_fields_when_no_description() {
- RuleDefinitionDto dto = newRuleWithoutSection();
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection();
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_returns_all_empty_fields_when_empty_description() {
- RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("uuid", ""));
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection().addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("uuid", ""));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
@UseDataProvider("descriptionsWithoutTitles")
public void parse_to_risk_description_fields_when_desc_contains_no_section(String description) {
- RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("uuid", description));
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection().addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("uuid", description));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_return_null_risk_when_desc_starts_with_ask_yourself_title() {
- RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection().addRuleDescriptionSectionDto(
createDefaultRuleDescriptionSection("uuid", (ASKATRISK + RECOMMENTEDCODINGPRACTICE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_return_null_vulnerable_when_no_ask_yourself_whether_title() {
- RuleDefinitionDto dto = newRuleWithoutSection()
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection()
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("uuid", (DESCRIPTION + RECOMMENTEDCODINGPRACTICE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_return_null_fixIt_when_desc_has_no_Recommended_Secure_Coding_Practices_title() {
- RuleDefinitionDto dto = newRuleWithoutSection()
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection()
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("uuid", (DESCRIPTION + ASKATRISK)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_with_noncompliant_section_not_removed() {
- RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection().addRuleDescriptionSectionDto(
createDefaultRuleDescriptionSection("uuid", (DESCRIPTION + NONCOMPLIANTCODE + COMPLIANTCODE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_moved_noncompliant_code() {
- RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection().addRuleDescriptionSectionDto(
createDefaultRuleDescriptionSection("uuid", (DESCRIPTION + RECOMMENTEDCODINGPRACTICE + NONCOMPLIANTCODE + SEE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_moved_sensitivecode_code() {
- RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection().addRuleDescriptionSectionDto(
createDefaultRuleDescriptionSection("uuid", (DESCRIPTION + ASKATRISK + RECOMMENTEDCODINGPRACTICE + SENSITIVECODE + SEE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
String askContent = "This is the ask section content";
String recommendedContent = "This is the recommended section content";
- RuleDefinitionDto dto = newRuleWithoutSection()
+ RuleDefinitionDto dto = RuleTesting.newRuleWithoutDescriptionSection()
.setTemplateUuid("123")
.setDescriptionFormat(RuleDto.Format.MARKDOWN)
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(
import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDto.Scope;
+import org.sonar.db.rule.RuleTesting;
import org.sonar.server.es.EsTester;
import org.sonar.server.security.SecurityStandards;
import org.sonar.server.security.SecurityStandards.SQCategory;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
-import static org.sonar.db.rule.RuleTesting.newRuleWithoutSection;
+import static org.sonar.db.rule.RuleTesting.newRuleWithoutDescriptionSection;
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE;
import static org.sonar.server.security.SecurityStandards.CWES_BY_SQ_CATEGORY;
import static org.sonar.server.security.SecurityStandards.SQ_CATEGORY_KEYS_ORDERING;
.flatMap(t -> CWES_BY_SQ_CATEGORY.get(t).stream().map(e -> "cwe:" + e))
.collect(toSet());
SecurityStandards securityStandards = SecurityStandards.fromSecurityStandards(standards);
- RuleDefinitionDto rule = dbTester.rules().insert(newRuleWithoutSection()
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRuleWithoutDescriptionSection()
.setType(RuleType.SECURITY_HOTSPOT)
.setSecurityStandards(standards)
.addRuleDescriptionSectionDto(RULE_DESCRIPTION_SECTION_DTO));
@Test
public void log_debug_when_hotspot_rule_no_description () {
- RuleDefinitionDto rule = dbTester.rules().insert(newRuleWithoutSection()
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRuleWithoutDescriptionSection()
.setType(RuleType.SECURITY_HOTSPOT));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
@Test
public void log_debug_when_hotspot_rule_description_has_none_of_the_key_titles() {
- RuleDefinitionDto rule = dbTester.rules().insert(newRuleWithoutSection()
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRuleWithoutDescriptionSection()
.setType(RuleType.SECURITY_HOTSPOT)
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), randomAlphabetic(30))));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
@Test
public void log_debug_when_hotspot_rule_description_is_missing_fixIt_tab_content() {
- RuleDefinitionDto rule = dbTester.rules().insert(newRuleWithoutSection()
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRuleWithoutDescriptionSection()
.setType(RuleType.SECURITY_HOTSPOT)
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "bar\n" +
"<h2>Ask Yourself Whether</h2>\n" +
@Test
public void log_debug_when_hotspot_rule_description_is_missing_risk_tab_content() {
- RuleDefinitionDto rule = dbTester.rules().insert(newRuleWithoutSection()
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRuleWithoutDescriptionSection()
.setType(RuleType.SECURITY_HOTSPOT)
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "<h2>Ask Yourself Whether</h2>\n" +
"bar\n" +
@Test
public void log_debug_when_hotspot_rule_description_is_missing_vulnerable_tab_content() {
- RuleDefinitionDto rule = dbTester.rules().insert(newRuleWithoutSection()
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRuleWithoutDescriptionSection()
.setType(RuleType.SECURITY_HOTSPOT)
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "bar\n" +
"<h2>Recommended Secure Coding Practices</h2>\n" +
*/
package org.sonar.server.qualityprofile;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import org.sonar.api.rule.RuleKey;
+import org.sonar.server.rule.NewRuleDescriptionSection;
class ImportedRule {
- private RuleKey ruleKey = null;
- private RuleKey templateKey = null;
+ private String key = null;
+
+ private String repository = null;
+
+ private String template = null;
private String name = null;
private String type = null;
private String severity = null;
private String description = null;
private Map<String, String> parameters = null;
-
+ private Set<NewRuleDescriptionSection> ruleDescriptionSections = new HashSet<>();
public Map<String, String> getParameters() {
return parameters;
}
public RuleKey getRuleKey() {
- return ruleKey;
+ return RuleKey.of(repository, key);
}
public RuleKey getTemplateKey() {
- return templateKey;
+ return RuleKey.of(repository, template);
}
public String getName() {
return description;
}
- ImportedRule setRuleKey(RuleKey ruleKey) {
- this.ruleKey = ruleKey;
- return this;
- }
-
- ImportedRule setTemplateKey(RuleKey templateKey) {
- this.templateKey = templateKey;
- return this;
- }
-
ImportedRule setType(String type) {
this.type = type;
return this;
}
boolean isCustomRule() {
- return templateKey != null;
+ return template != null;
+ }
+
+ public Set<NewRuleDescriptionSection> getRuleDescriptionSections() {
+ return ruleDescriptionSections;
+ }
+
+ public void addRuleDescriptionSection(NewRuleDescriptionSection ruleDescriptionSection) {
+ this.ruleDescriptionSections.add(ruleDescriptionSection);
+ }
+
+ public void setRepository(String repository) {
+ this.repository = repository;
+ }
+
+ public void setTemplate(String template) {
+ this.template = template;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
}
}
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.server.qualityprofile.builtin.QProfileName;
import org.sonar.server.rule.NewCustomRule;
+import org.sonar.server.rule.NewRuleDescriptionSection;
import org.sonar.server.rule.RuleCreator;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toSet;
@ServerSide
public class QProfileBackuperImpl implements QProfileBackuper {
List<ImportedRule> importedRules = new ArrayList<>(exportRules.size());
for (ExportRuleDto exportRuleDto : exportRules) {
+ var ruleKey = exportRuleDto.getRuleKey();
ImportedRule importedRule = new ImportedRule();
importedRule.setName(exportRuleDto.getName());
- importedRule.setDescription(exportRuleDto.getDescription());
- importedRule.setRuleKey(exportRuleDto.getRuleKey());
+ importedRule.setRepository(ruleKey.repository());
+ importedRule.setKey(ruleKey.rule());
importedRule.setSeverity(exportRuleDto.getSeverityString());
if (importedRule.isCustomRule()) {
- importedRule.setTemplateKey(exportRuleDto.getTemplateRuleKey());
+ importedRule.setTemplate(exportRuleDto.getTemplateRuleKey().rule());
}
importedRule.setType(exportRuleDto.getRuleType().name());
+ exportRuleDto.getRuleDescriptionSections()
+ .stream()
+ .map(r -> new NewRuleDescriptionSection(r.getKey(), r.getDescription()))
+ .forEach(importedRule::addRuleDescriptionSection);
importedRule.setParameters(exportRuleDto.getParams().stream().collect(Collectors.toMap(ExportRuleParamDto::getKey, ExportRuleParamDto::getValue)));
importedRules.add(importedRule);
}
private Map<RuleKey, RuleDefinitionDto> getImportedRulesDefinitions(DbSession dbSession, List<ImportedRule> rules) {
Set<RuleKey> ruleKeys = rules.stream()
.map(ImportedRule::getRuleKey)
- .collect(Collectors.toSet());
+ .collect(toSet());
Map<RuleKey, RuleDefinitionDto> rulesDefinitions = db.ruleDao().selectDefinitionByKeys(dbSession, ruleKeys).stream()
.collect(Collectors.toMap(RuleDefinitionDto::getKey, identity()));
Set<RuleKey> unrecognizedRuleKeys = ruleKeys.stream()
.filter(r -> !rulesDefinitions.containsKey(r))
- .collect(Collectors.toSet());
+ .collect(toSet());
if (!unrecognizedRuleKeys.isEmpty()) {
Map<String, DeprecatedRuleKeyDto> deprecatedRuleKeysByUuid = db.ruleDao().selectAllDeprecatedRuleKeys(dbSession).stream()
private static NewCustomRule importedRuleToNewCustomRule(ImportedRule r) {
return NewCustomRule.createForCustomRule(r.getRuleKey().rule(), r.getTemplateKey())
.setName(r.getName())
- .setMarkdownDescription(r.getDescription())
.setSeverity(r.getSeverity())
.setStatus(RuleStatus.READY)
.setPreventReactivation(true)
.setType(RuleType.valueOf(r.getType()))
+ .setMarkdownDescription(r.getDescription())
+ .setRuleDescriptionSections(r.getRuleDescriptionSections())
.setParameters(r.getParameters());
}
import org.sonar.db.qualityprofile.ExportRuleDto;
import org.sonar.db.qualityprofile.ExportRuleParamDto;
import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.db.rule.RuleDescriptionSectionDto;
+import org.sonar.server.rule.NewRuleDescriptionSection;
@ServerSide
public class QProfileParser {
private static final String ATTRIBUTE_PROFILE = "profile";
private static final String ATTRIBUTE_NAME = "name";
private static final String ATTRIBUTE_LANGUAGE = "language";
-
private static final String ATTRIBUTE_RULES = "rules";
private static final String ATTRIBUTE_RULE = "rule";
+ private static final String ATTRIBUTE_DESCRIPTION_SECTIONS = "descriptionSections";
+ private static final String ATTRIBUTE_DESCRIPTION_SECTION = "descriptionSection";
+ private static final String ATTRIBUTE_DESCRIPTION_SECTION_KEY = "key";
+ private static final String ATTRIBUTE_DESCRIPTION_SECTION_DESCRIPTION = "content";
private static final String ATTRIBUTE_REPOSITORY_KEY = "repositoryKey";
private static final String ATTRIBUTE_KEY = "key";
private static final String ATTRIBUTE_PRIORITY = "priority";
if (ruleToExport.isCustomRule()) {
xml.prop(ATTRIBUTE_NAME, ruleToExport.getName());
xml.prop(ATTRIBUTE_TEMPLATE_KEY, ruleToExport.getTemplateRuleKey().rule());
- xml.prop(ATTRIBUTE_DESCRIPTION, ruleToExport.getDescription());
+ if (!ruleToExport.getRuleDescriptionSections().isEmpty()) {
+ ruleToExport.getDefaultRuleDescriptionSectionDto()
+ .map(RuleDescriptionSectionDto::getDescription)
+ .ifPresent(desc -> xml.prop(ATTRIBUTE_DESCRIPTION, desc));
+ }
+ xml.begin(ATTRIBUTE_DESCRIPTION_SECTIONS);
+ for (RuleDescriptionSectionDto ruleDescriptionSection : ruleToExport.getRuleDescriptionSections()) {
+ xml.begin(ATTRIBUTE_DESCRIPTION_SECTION)
+ .prop(ATTRIBUTE_DESCRIPTION_SECTION_KEY, ruleDescriptionSection.getKey())
+ .prop(ATTRIBUTE_DESCRIPTION_SECTION_DESCRIPTION, ruleDescriptionSection.getDescription())
+ .end();
+ }
+ xml.end(ATTRIBUTE_DESCRIPTION_SECTIONS);
}
xml.begin(ATTRIBUTE_PARAMETERS);
while (rulesCursor.getNext() != null) {
SMInputCursor ruleCursor = rulesCursor.childElementCursor();
Map<String, String> parameters = new HashMap<>();
- String repositoryKey = null;
- String key = null;
- String templateKey = null;
ImportedRule rule = new ImportedRule();
- while (ruleCursor.getNext() != null) {
- String nodeName = ruleCursor.getLocalName();
- if (StringUtils.equals(ATTRIBUTE_REPOSITORY_KEY, nodeName)) {
- repositoryKey = StringUtils.trim(ruleCursor.collectDescendantText(false));
- } else if (StringUtils.equals(ATTRIBUTE_KEY, nodeName)) {
- key = StringUtils.trim(ruleCursor.collectDescendantText(false));
- } else if (StringUtils.equals(ATTRIBUTE_TEMPLATE_KEY, nodeName)) {
- templateKey = StringUtils.trim(ruleCursor.collectDescendantText(false));
- } else if (StringUtils.equals(ATTRIBUTE_NAME, nodeName)) {
- rule.setName(StringUtils.trim(ruleCursor.collectDescendantText(false)));
- } else if (StringUtils.equals(ATTRIBUTE_TYPE, nodeName)) {
- rule.setType(StringUtils.trim(ruleCursor.collectDescendantText(false)));
- } else if (StringUtils.equals(ATTRIBUTE_DESCRIPTION, nodeName)) {
- rule.setDescription(StringUtils.trim(ruleCursor.collectDescendantText(false)));
- } else if (StringUtils.equals(ATTRIBUTE_PRIORITY, nodeName)) {
- rule.setSeverity(StringUtils.trim(ruleCursor.collectDescendantText(false)));
- } else if (StringUtils.equals(ATTRIBUTE_PARAMETERS, nodeName)) {
- SMInputCursor propsCursor = ruleCursor.childElementCursor(ATTRIBUTE_PARAMETER);
- readParameters(propsCursor, parameters);
- rule.setParameters(parameters);
- }
- }
- RuleKey ruleKey = RuleKey.of(repositoryKey, key);
- rule.setRuleKey(ruleKey);
-
- if (templateKey != null) {
- rule.setTemplateKey(RuleKey.of(repositoryKey, templateKey));
- }
+ readRule(ruleCursor, parameters, rule);
+ var ruleKey = rule.getRuleKey();
if (activatedKeys.contains(ruleKey)) {
duplicatedKeys.add(ruleKey);
}
return activations;
}
+ private static void readRule(SMInputCursor ruleCursor, Map<String, String> parameters, ImportedRule rule) throws XMLStreamException {
+ while (ruleCursor.getNext() != null) {
+ String nodeName = ruleCursor.getLocalName();
+ if (StringUtils.equals(ATTRIBUTE_REPOSITORY_KEY, nodeName)) {
+ rule.setRepository(StringUtils.trim(ruleCursor.collectDescendantText(false)));
+ } else if (StringUtils.equals(ATTRIBUTE_KEY, nodeName)) {
+ rule.setKey(StringUtils.trim(ruleCursor.collectDescendantText(false)));
+ } else if (StringUtils.equals(ATTRIBUTE_TEMPLATE_KEY, nodeName)) {
+ rule.setTemplate(StringUtils.trim(ruleCursor.collectDescendantText(false)));
+ } else if (StringUtils.equals(ATTRIBUTE_NAME, nodeName)) {
+ rule.setName(StringUtils.trim(ruleCursor.collectDescendantText(false)));
+ } else if (StringUtils.equals(ATTRIBUTE_TYPE, nodeName)) {
+ rule.setType(StringUtils.trim(ruleCursor.collectDescendantText(false)));
+ } else if (StringUtils.equals(ATTRIBUTE_DESCRIPTION, nodeName)) {
+ rule.setDescription(StringUtils.trim(ruleCursor.collectDescendantText(false)));
+ } else if (StringUtils.equals(ATTRIBUTE_PRIORITY, nodeName)) {
+ rule.setSeverity(StringUtils.trim(ruleCursor.collectDescendantText(false)));
+ } else if (StringUtils.equals(ATTRIBUTE_PARAMETERS, nodeName)) {
+ SMInputCursor propsCursor = ruleCursor.childElementCursor(ATTRIBUTE_PARAMETER);
+ readParameters(propsCursor, parameters);
+ rule.setParameters(parameters);
+ } else if (StringUtils.equals(ATTRIBUTE_DESCRIPTION_SECTIONS, nodeName)) {
+ SMInputCursor propsCursor = ruleCursor.childElementCursor(ATTRIBUTE_DESCRIPTION_SECTION);
+ readDescriptionSections(propsCursor, rule);
+ }
+ }
+ }
+
private static void readParameters(SMInputCursor propsCursor, Map<String, String> parameters) throws XMLStreamException {
while (propsCursor.getNext() != null) {
SMInputCursor propCursor = propsCursor.childElementCursor();
}
}
}
+
+ private static void readDescriptionSections(SMInputCursor propsCursor, ImportedRule importedRule) throws XMLStreamException {
+ while (propsCursor.getNext() != null) {
+ SMInputCursor propCursor = propsCursor.childElementCursor();
+ String key = null;
+ String description = null;
+ while (propCursor.getNext() != null) {
+ String nodeName = propCursor.getLocalName();
+ if (StringUtils.equals(ATTRIBUTE_DESCRIPTION_SECTION_KEY, nodeName)) {
+ key = StringUtils.trim(propCursor.collectDescendantText(false));
+ } else if (StringUtils.equals(ATTRIBUTE_DESCRIPTION_SECTION_DESCRIPTION, nodeName)) {
+ description = StringUtils.trim(propCursor.collectDescendantText(false));
+ }
+ }
+ if (key != null && description != null) {
+ importedRule.addRuleDescriptionSection(new NewRuleDescriptionSection(key, description));
+ }
+ }
+ }
}
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.rule.RuleKey;
private String ruleKey;
private RuleKey templateKey;
private String name;
- private String htmlDescription;
private String markdownDescription;
private String severity;
private RuleStatus status;
private RuleType type;
- private final Map<String, String> parameters = new HashMap<>();
+ private Map<String, String> parameters = new HashMap<>();
+
+ private Set<NewRuleDescriptionSection> ruleDescriptionSections = new HashSet<>();
private boolean preventReactivation = false;
return this;
}
- @CheckForNull
- public String htmlDescription() {
- return htmlDescription;
- }
-
- public NewCustomRule setHtmlDescription(@Nullable String htmlDescription) {
- this.htmlDescription = htmlDescription;
- return this;
- }
-
@CheckForNull
public String markdownDescription() {
return markdownDescription;
}
public NewCustomRule setParameters(Map<String, String> params) {
- this.parameters.clear();
- this.parameters.putAll(params);
+ this.parameters = params;
+ return this;
+ }
+
+ public Set<NewRuleDescriptionSection> getRuleDescriptionSections() {
+ return Collections.unmodifiableSet(ruleDescriptionSections);
+ }
+
+ public NewCustomRule setRuleDescriptionSections(Set<NewRuleDescriptionSection> sections) {
+ this.ruleDescriptionSections = sections;
return this;
}
newRule.templateKey = templateKey;
return newRule;
}
-
}
--- /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.server.rule;
+
+public class NewRuleDescriptionSection {
+ private final String key;
+
+ private final String description;
+
+ public NewRuleDescriptionSection(String key, String description) {
+ this.key = key;
+ this.description = description;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}
}
private static void validateDescription(List<String> errors, NewCustomRule newRule) {
- if (Strings.isNullOrEmpty(newRule.htmlDescription()) && Strings.isNullOrEmpty(newRule.markdownDescription())) {
+ boolean missingDescription = newRule.getRuleDescriptionSections().isEmpty() ?
+ Strings.isNullOrEmpty(newRule.markdownDescription()) :
+ noDescriptionSectionHasContent(newRule);
+ if (missingDescription) {
errors.add("The description is missing");
}
}
+ private static boolean noDescriptionSectionHasContent(NewCustomRule newRule) {
+ return newRule.getRuleDescriptionSections().stream().map(NewRuleDescriptionSection::getDescription).allMatch(Strings::isNullOrEmpty);
+ }
+
private static void validateRuleKey(List<String> errors, String ruleKey) {
if (!ruleKey.matches("^[\\w]+$")) {
errors.add(format("The rule key \"%s\" is invalid, it should only contain: a-z, 0-9, \"_\"", ruleKey));
.setCreatedAt(system2.now())
.setUpdatedAt(system2.now());
- if (newRule.markdownDescription() != null) {
+ ruleDefinition.setDescriptionFormat(Format.MARKDOWN);
+
+ if (newRule.getRuleDescriptionSections().isEmpty() && newRule.markdownDescription() != null) {
RuleDescriptionSectionDto ruleDescriptionSectionDto = createDefaultRuleDescriptionSection(uuidFactory.create(), newRule.markdownDescription());
- ruleDefinition.setDescriptionFormat(Format.MARKDOWN);
ruleDefinition.addRuleDescriptionSectionDto(ruleDescriptionSectionDto);
+ } else {
+ for (NewRuleDescriptionSection ruleDescriptionSection : newRule.getRuleDescriptionSections()) {
+ RuleDescriptionSectionDto ruleDescriptionSectionDto = RuleDescriptionSectionDto.builder()
+ .uuid(uuidFactory.create())
+ .key(ruleDescriptionSection.getKey())
+ .description(ruleDescriptionSection.getDescription())
+ .build();
+ ruleDefinition.addRuleDescriptionSectionDto(ruleDescriptionSectionDto);
+ }
}
dbClient.ruleDao().insert(dbSession, ruleDefinition);
}
private RuleDefinitionDto newRuleWithoutSection(RuleType ruleType, Consumer<RuleDefinitionDto> populate) {
- return newRule(ruleType, RuleTesting::newRuleWithoutSection, populate);
+ return newRule(ruleType, RuleTesting::newRuleWithoutDescriptionSection, populate);
}
private RuleDefinitionDto newRule(RuleType ruleType, Supplier<RuleDefinitionDto> ruleDefinitionDtoSupplier, Consumer<RuleDefinitionDto> populate) {
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
+import static org.sonar.db.rule.RuleTesting.newRuleWithoutDescriptionSection;
public class QProfileBackuperImplTest {
"<name>" + rule.getName() + "</name>" +
"<templateKey>" + templateRule.getKey().rule() + "</templateKey>" +
"<description>" + rule.getDefaultRuleDescriptionSectionDto().getDescription() + "</description>" +
+ "<descriptionSections><descriptionSection><key>default</key><content>" + rule.getDefaultRuleDescriptionSectionDto().getDescription() + "</content></descriptionSection></descriptionSections>" +
+ "<parameters><parameter>" +
+ "<key>" + param.getName() + "</key>" +
+ "<value>20</value>" +
+ "</parameter></parameters>" +
+ "</rule></rules></profile>");
+ }
+
+ @Test
+ public void backup_custom_rules_without_description_section() {
+ var rule = newRuleWithoutDescriptionSection();
+ db.rules().insert(rule);
+ RuleParamDto param = db.rules().insertRuleParam(rule);
+ QProfileDto profile = createProfile(rule.getLanguage());
+ ActiveRuleDto activeRule = activate(profile, rule, param);
+
+ StringWriter writer = new StringWriter();
+ underTest.backup(db.getSession(), profile, writer);
+
+ assertThat(writer).hasToString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<profile>" +
+ "<name>" + profile.getName() + "</name>" +
+ "<language>" + profile.getLanguage() + "</language>" +
+ "<rules><rule>" +
+ "<repositoryKey>" + rule.getRepositoryKey() + "</repositoryKey>" +
+ "<key>" + rule.getKey().rule() + "</key>" +
+ "<type>" + RuleType.valueOf(rule.getType()) + "</type>" +
+ "<priority>" + activeRule.getSeverityString() + "</priority>" +
"<parameters><parameter>" +
"<key>" + param.getName() + "</key>" +
"<value>20</value>" +
--- /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.server.qualityprofile;
+
+import java.io.Reader;
+import java.io.StringReader;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class QProfileParserTest {
+
+ @Test
+ public void readOlderVersionXml() {
+ Reader backup = new StringReader("<?xml version='1.0' encoding='UTF-8'?>" +
+ "<profile>" +
+ "<name>custom rule</name>" +
+ "<language>js</language>" +
+ "<rules><rule>" +
+ "<repositoryKey>sonarjs</repositoryKey>" +
+ "<key>s001</key>" +
+ "<type>CODE_SMELL</type>" +
+ "<priority>CRITICAL</priority>" +
+ "<name>custom rule name</name>" +
+ "<templateKey>rule_mc8</templateKey>" +
+ "<description>custom rule description</description>" +
+ "<parameters><parameter>" +
+ "<key>bar</key>" +
+ "<value>baz</value>" +
+ "</parameter>" +
+ "</parameters>" +
+ "</rule></rules></profile>");
+ var parser = new QProfileParser();
+ var importedQProfile = parser.readXml(backup);
+ assertThat(importedQProfile.getRules()).hasSize(1);
+ var importedRule = importedQProfile.getRules().get(0);
+ assertThat(importedRule.getDescription()).isEqualTo("custom rule description");
+ }
+
+ @Test
+ public void readNewVersionXml() {
+ Reader backup = new StringReader("<?xml version='1.0' encoding='UTF-8'?>" +
+ "<profile>" +
+ "<name>custom rule</name>" +
+ "<language>js</language>" +
+ "<rules><rule>" +
+ "<repositoryKey>sonarjs</repositoryKey>" +
+ "<key>s001</key>" +
+ "<type>CODE_SMELL</type>" +
+ "<priority>CRITICAL</priority>" +
+ "<name>custom rule name</name>" +
+ "<templateKey>rule_mc8</templateKey>" +
+ "<descriptionSections><descriptionSection><key>default</key><content>custom rule description</content></descriptionSection></descriptionSections>" +
+ "<parameters><parameter>" +
+ "<key>bar</key>" +
+ "<value>baz</value>" +
+ "</parameter>" +
+ "</parameters>" +
+ "</rule></rules></profile>");
+ var parser = new QProfileParser();
+ var importedQProfile = parser.readXml(backup);
+ assertThat(importedQProfile.getRules()).hasSize(1);
+ var importedRule = importedQProfile.getRules().get(0);
+ assertThat(importedRule.getRuleDescriptionSections()).hasSize(1);
+ var section = importedRule.getRuleDescriptionSections().iterator().next();
+ assertThat(section.getKey()).isEqualTo("default");
+ assertThat(section.getDescription()).isEqualTo("custom rule description");
+ }
+}
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.assertj.core.api.Fail;
import org.junit.Rule;
private System2 system2 = new TestSystem2().setNow(Instant.now().toEpochMilli());
-
@Rule
public DbTester dbTester = DbTester.create(system2);
assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getUuids()).containsOnly(rule.getUuid(), templateRule.getUuid());
}
+ @Test
+ public void create_custom_rule_with_both_markdown_description_and_description_sections() {
+ // insert template rule
+ RuleDto templateRule = createTemplateRule();
+ // Create custom rule
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+ .setName("My custom")
+ .setMarkdownDescription("Markdown description")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "new description section")))
+ .setSeverity(Severity.MAJOR)
+ .setStatus(RuleStatus.READY);
+ RuleKey customRuleKey = underTest.create(dbSession, newRule);
+
+ RuleDto rule = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, customRuleKey);
+ assertThat(rule).isNotNull();
+ assertThat(rule.getKey()).isEqualTo(RuleKey.of("java", "CUSTOM_RULE"));
+ assertThat(rule.getPluginKey()).isEqualTo("sonarjava");
+ assertThat(rule.getTemplateUuid()).isEqualTo(templateRule.getUuid());
+ assertThat(rule.getName()).isEqualTo("My custom");
+ assertThat(rule.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("new description section");
+ assertThat(rule.getSeverityString()).isEqualTo("MAJOR");
+ assertThat(rule.getStatus()).isEqualTo(RuleStatus.READY);
+ assertThat(rule.getLanguage()).isEqualTo("java");
+ assertThat(rule.getConfigKey()).isEqualTo("S001");
+ assertThat(rule.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET");
+ assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1h");
+ assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min");
+ assertThat(rule.getGapDescription()).isEqualTo("desc");
+ assertThat(rule.getTags()).containsOnly("usertag1", "usertag2");
+ assertThat(rule.getSystemTags()).containsOnly("tag1", "tag4");
+ assertThat(rule.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123");
+ assertThat(rule.isExternal()).isFalse();
+ assertThat(rule.isAdHoc()).isFalse();
+ }
+
@Test
public void create_custom_rule_with_empty_parameter_value() {
// insert template rule
RuleDto templateRule = createTemplateRule();
+ NewRuleDescriptionSection defaultSection = new NewRuleDescriptionSection("default", "some description");
NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
- .setHtmlDescription("Some description")
+ .setRuleDescriptionSections(Set.of(defaultSection))
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
.setParameters(ImmutableMap.of("regex", ""));
RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam();
NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
- .setHtmlDescription("Some description")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY);
RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam();
NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
- .setHtmlDescription("Some description")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
.setParameters(ImmutableMap.of("myIntegers", "1,3"));
NewCustomRule firstRule = NewCustomRule.createForCustomRule("CUSTOM_RULE_1", templateRule.getKey())
.setName("My custom")
- .setHtmlDescription("Some description")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY);
NewCustomRule secondRule = NewCustomRule.createForCustomRule("CUSTOM_RULE_2", templateRule.getKey())
.setName("My custom")
- .setHtmlDescription("Some description")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY);
dbTester.rules().insert(rule);
dbSession.commit();
- assertThatThrownBy(() -> {
- // Create custom rule with unknown template rule
- NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey())
- .setName("My custom")
- .setHtmlDescription("Some description")
- .setSeverity(Severity.MAJOR)
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*"));
- underTest.create(dbSession, Collections.singletonList(newRule));
- })
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey())
+ .setName("My custom")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setSeverity(Severity.MAJOR)
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, Collections.singletonList(newRule)))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("This rule is not a template rule: java:S001");
}
// Create custom rule with same key, but with different values
NewCustomRule newRule = NewCustomRule.createForCustomRule(key, templateRule.getKey())
.setName("New name")
- .setHtmlDescription("New description")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
.setParameters(ImmutableMap.of("regex", "c.*"))
// insert template rule
RuleDto templateRule = createTemplateRule();
- assertThatThrownBy(() -> {
- NewCustomRule newRule = NewCustomRule.createForCustomRule("*INVALID*", templateRule.getKey())
- .setName("My custom")
- .setHtmlDescription("Some description")
- .setSeverity(Severity.MAJOR)
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*"));
- underTest.create(dbSession, newRule);
- })
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("*INVALID*", templateRule.getKey())
+ .setName("My custom")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setSeverity(Severity.MAJOR)
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, newRule))
.isInstanceOf(BadRequestException.class)
.hasMessage("The rule key \"*INVALID*\" is invalid, it should only contain: a-z, 0-9, \"_\"");
}
// Create a custom rule
AtomicReference<NewCustomRule> newRule = new AtomicReference<>(NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
- .setHtmlDescription("Some description")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
.setSeverity(Severity.MAJOR)
.setStatus(RuleStatus.READY)
.setParameters(ImmutableMap.of("regex", "a.*")));
underTest.create(dbSession, newRule.get());
- assertThatThrownBy(() -> {
- // Create another custom rule having same key
- newRule.set(NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
- .setName("My another custom")
- .setHtmlDescription("Some description")
- .setSeverity(Severity.MAJOR)
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*")));
- underTest.create(dbSession, newRule.get());
- })
+ // Create another custom rule having same key
+ newRule.set(NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+ .setName("My another custom")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setSeverity(Severity.MAJOR)
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*")));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, newRule.get()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("A rule with the key 'CUSTOM_RULE' already exists");
}
// insert template rule
RuleDto templateRule = createTemplateRule();
- assertThatThrownBy(() -> {
- NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
- .setHtmlDescription("Some description")
- .setSeverity(Severity.MAJOR)
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*"));
- underTest.create(dbSession, newRule);
- })
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setSeverity(Severity.MAJOR)
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, newRule))
.isInstanceOf(BadRequestException.class)
.hasMessage("The name is missing");
}
// insert template rule
RuleDto templateRule = createTemplateRule();
- assertThatThrownBy(() -> {
- NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
- .setName("My custom")
- .setHtmlDescription("Some description")
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*"));
- underTest.create(dbSession, newRule);
- })
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+ .setName("My custom")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, newRule))
.isInstanceOf(BadRequestException.class)
.hasMessage("The severity is missing");
}
// insert template rule
RuleDto templateRule = createTemplateRule();
- assertThatThrownBy(() -> {
- NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
- .setName("My custom")
- .setHtmlDescription("Some description")
- .setSeverity("INVALID")
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*"));
- underTest.create(dbSession, newRule);
- })
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+ .setName("My custom")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setSeverity("INVALID")
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, newRule))
.isInstanceOf(BadRequestException.class)
.hasMessage("Severity \"INVALID\" is invalid");
}
// insert template rule
RuleDto templateRule = createTemplateRule();
- assertThatThrownBy(() -> {
- NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
- .setName("My custom")
- .setHtmlDescription("Some description")
- .setSeverity(Severity.MAJOR)
- .setParameters(ImmutableMap.of("regex", "a.*"));
- underTest.create(dbSession, newRule);
- })
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
+ .setName("My custom")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setSeverity(Severity.MAJOR)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, newRule))
.isInstanceOf(BadRequestException.class)
.hasMessage("The status is missing");
}
dbTester.rules().insert(rule);
dbSession.commit();
- assertThatThrownBy(() -> {
- // Create custom rule with unknown template rule
- NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey())
- .setName("My custom")
- .setHtmlDescription("Some description")
- .setSeverity(Severity.MAJOR)
- .setStatus(RuleStatus.READY)
- .setParameters(ImmutableMap.of("regex", "a.*"));
- underTest.create(dbSession, newRule);
- })
+ // Create custom rule with unknown template rule
+ NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey())
+ .setName("My custom")
+ .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description")))
+ .setSeverity(Severity.MAJOR)
+ .setStatus(RuleStatus.READY)
+ .setParameters(ImmutableMap.of("regex", "a.*"));
+
+ assertThatThrownBy(() -> underTest.create(dbSession, newRule))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("This rule is not a template rule: java:S001");
}
*/
package org.sonar.server.rule.ws;
+import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
public class ListActionTest {
+ private static final String RULE_KEY_1 = "S001";
+ private static final String RULE_KEY_2 = "S002";
+
@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
@Test
public void return_rules_in_protobuf() {
- dbTester.rules().insert(RuleTesting.newRule(RuleKey.of("java", "S001")).setConfigKey(null).setName(null));
- dbTester.rules().insert(RuleTesting.newRule(RuleKey.of("java", "S002")).setConfigKey("I002").setName("Rule Two"));
+ dbTester.rules().insert(RuleTesting.newRule(RuleKey.of("java", RULE_KEY_1)).setConfigKey(null).setName(null));
+ dbTester.rules().insert(RuleTesting.newRule(RuleKey.of("java", RULE_KEY_2)).setConfigKey("I002").setName("Rule Two"));
dbTester.getSession().commit();
Rules.ListResponse listResponse = tester.newRequest()
assertThat(listResponse.getRulesCount()).isEqualTo(2);
- assertThat(listResponse.getRules(0).getKey()).isEqualTo("S001");
- assertThat(listResponse.getRules(0).getInternalKey()).isEmpty();
- assertThat(listResponse.getRules(0).getName()).isEmpty();
- assertThat(listResponse.getRules(1).getKey()).isEqualTo("S002");
- assertThat(listResponse.getRules(1).getInternalKey()).isEqualTo("I002");
- assertThat(listResponse.getRules(1).getName()).isEqualTo("Rule Two");
+ Rules.ListResponse.Rule ruleS001 = getRule(listResponse, RULE_KEY_1);
+ assertThat(ruleS001.getKey()).isEqualTo(RULE_KEY_1);
+ assertThat(ruleS001.getInternalKey()).isEmpty();
+ assertThat(ruleS001.getName()).isEmpty();
+
+ Rules.ListResponse.Rule ruleS002 = getRule(listResponse, RULE_KEY_2);
+ assertThat(ruleS002.getKey()).isEqualTo(RULE_KEY_2);
+ assertThat(ruleS002.getInternalKey()).isEqualTo("I002");
+ assertThat(ruleS002.getName()).isEqualTo("Rule Two");
+ }
+
+ private Rules.ListResponse.Rule getRule(Rules.ListResponse listResponse, String ruleKey) {
+ Optional<Rules.ListResponse.Rule> rule = listResponse.getRulesList().stream()
+ .filter(r -> ruleKey.equals(r.getKey()))
+ .findFirst();
+ assertThat(rule).isPresent();
+ return rule.get();
}
}