assertThat(rule.getUuid()).isNotBlank();
assertThat(rule.getKey()).isEqualTo(RuleKey.of("external_eslint", "no-cond-assign"));
assertThat(rule.getName()).isEqualTo("eslint:no-cond-assign");
- assertThat(rule.getDescription()).isNull();
+ assertThat(rule.getRuleDescriptionSectionDtos()).isEmpty();
assertThat(rule.getSeverity()).isNull();
assertThat(rule.getType()).isZero();
assertThat(rule.getMetadata().getAdHocName()).isNull();
assertThat(rule.getUuid()).isNotBlank();
assertThat(rule.getKey()).isEqualTo(RuleKey.of("external_eslint", "no-cond-assign"));
assertThat(rule.getName()).isEqualTo("eslint:no-cond-assign");
- assertThat(rule.getDescription()).isNull();
+ assertThat(rule.getRuleDescriptionSectionDtos()).isEmpty();
assertThat(rule.getSeverity()).isNull();
assertThat(rule.getType()).isZero();
assertThat(rule.getMetadata().getAdHocName()).isEqualTo("No condition assigned");
assertThat(ruleUpdated.getUuid()).isNotBlank();
assertThat(ruleUpdated.getKey()).isEqualTo(RuleKey.of("external_eslint", "no-cond-assign"));
assertThat(ruleUpdated.getName()).isEqualTo("eslint:no-cond-assign");
- assertThat(ruleUpdated.getDescription()).isNull();
+ assertThat(ruleUpdated.getRuleDescriptionSectionDtos()).isEmpty();
assertThat(ruleUpdated.getSeverity()).isNull();
assertThat(ruleUpdated.getType()).isZero();
assertThat(ruleUpdated.getMetadata().getAdHocName()).isEqualTo("No condition assigned updated");
assertThat(ruleUpdated.isAdHoc()).isTrue();
assertThat(ruleUpdated.getKey()).isEqualTo(rule.getKey());
assertThat(ruleUpdated.getName()).isEqualTo(rule.getName());
- assertThat(ruleUpdated.getDescription()).isEqualTo(rule.getDescription());
+ assertThat(ruleUpdated.getRuleDescriptionSectionDtos()).usingRecursiveFieldByFieldElementComparator().isEqualTo(rule.getRuleDescriptionSectionDtos());
assertThat(ruleUpdated.getSeverity()).isEqualTo(rule.getSeverity());
assertThat(ruleUpdated.getType()).isEqualTo(rule.getType());
assertThat(ruleUpdated.getDefinition().getCreatedAt()).isEqualTo(rule.getCreatedAt());
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.CheckForNull;
import org.sonar.db.rule.RuleDto.Scope;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Collections.unmodifiableCollection;
public class RuleDefinitionDto {
private String repositoryKey;
private String ruleKey;
- /**
- * Description can be null on external rule, otherwise it should never be null
- */
- private String description;
+ private Map<String, RuleDescriptionSectionDto> ruleDescriptionSectionDtos = new HashMap<>();
/**
* Description format can be null on external rule, otherwise it should never be null
return this;
}
+ public Collection<RuleDescriptionSectionDto> getRuleDescriptionSectionDtos() {
+ return unmodifiableCollection(ruleDescriptionSectionDtos.values());
+ }
+
+ @CheckForNull
+ public RuleDescriptionSectionDto getRuleDescriptionSectionDto(String ruleDescriptionSectionKey) {
+ return ruleDescriptionSectionDtos.get(ruleDescriptionSectionKey);
+ }
+
@CheckForNull
- public String getDescription() {
- return description;
+ public RuleDescriptionSectionDto getDefaultRuleDescriptionSectionDto() {
+ return ruleDescriptionSectionDtos.get(RuleDescriptionSectionDto.DEFAULT_KEY);
+ }
+
+ public RuleDefinitionDto addRuleDescriptionSectionDto(RuleDescriptionSectionDto ruleDescriptionSectionDto) {
+ checkArgument(!isSectionKeyUsed(ruleDescriptionSectionDto.getKey()), "A section with key %s already exists", ruleDescriptionSectionDto.getKey());
+ this.ruleDescriptionSectionDtos.put(ruleDescriptionSectionDto.getKey(), ruleDescriptionSectionDto);
+ return this;
+ }
+
+ private boolean isSectionKeyUsed(String sectionKey) {
+ return ruleDescriptionSectionDtos.containsKey(sectionKey);
}
- public RuleDefinitionDto setDescription(@Nullable String description) {
- this.description = description;
+ public RuleDefinitionDto addOrReplaceRuleDescriptionSectionDto(RuleDescriptionSectionDto ruleDescriptionSectionDto) {
+ this.ruleDescriptionSectionDtos.put(ruleDescriptionSectionDto.getKey(), ruleDescriptionSectionDto);
return this;
}
"uuid=" + uuid +
", repositoryKey='" + repositoryKey + '\'' +
", ruleKey='" + ruleKey + '\'' +
- ", description='" + description + '\'' +
+ ", ruleDescriptionSections='" + ruleDescriptionSectionDtos + '\'' +
", descriptionFormat=" + descriptionFormat +
", status=" + status +
", name='" + name + '\'' +
--- /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.rule;
+
+import java.util.StringJoiner;
+
+import static org.sonar.api.utils.Preconditions.checkArgument;
+
+public class RuleDescriptionSectionDto {
+ static final String DEFAULT_KEY = "default";
+ private final String key;
+ private final String description;
+
+ private RuleDescriptionSectionDto(String key, String description) {
+ this.key = key;
+ this.description = description;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public static RuleDescriptionSectionDto createDefaultRuleDescriptionSection(String description) {
+ return RuleDescriptionSectionDto.builder()
+ .setDefault()
+ .description(description)
+ .build();
+ }
+
+ public static RuleDescriptionSectionDtoBuilder builder() {
+ return new RuleDescriptionSectionDtoBuilder();
+ }
+
+ public boolean isDefault() {
+ return DEFAULT_KEY.equals(key);
+ }
+
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", RuleDescriptionSectionDto.class.getSimpleName() + "[", "]")
+ .add("key='" + key + "'")
+ .add("description='" + description + "'")
+ .toString();
+ }
+
+ public static final class RuleDescriptionSectionDtoBuilder {
+ private String key = null;
+ private String description;
+
+ private RuleDescriptionSectionDtoBuilder() {
+ }
+
+ public RuleDescriptionSectionDtoBuilder setDefault() {
+ checkArgument(this.key == null, "Only one of setDefault and key methods can be called");
+ this.key = DEFAULT_KEY;
+ return this;
+ }
+
+ public RuleDescriptionSectionDtoBuilder key(String key) {
+ checkArgument(this.key == null, "Only one of setDefault and key methods can be called");
+ this.key = key;
+ return this;
+ }
+
+
+ public RuleDescriptionSectionDtoBuilder description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ public RuleDescriptionSectionDto build() {
+ return new RuleDescriptionSectionDto(key, description);
+ }
+ }
+}
*/
package org.sonar.db.rule;
+import java.util.Collection;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
return this;
}
- public String getDescription() {
- return definition.getDescription();
+ @CheckForNull
+ public RuleDescriptionSectionDto getRuleDescriptionSection(String ruleDescriptionSectionKey) {
+ return definition.getRuleDescriptionSectionDto(ruleDescriptionSectionKey);
+ }
+
+ @CheckForNull
+ public RuleDescriptionSectionDto getDefaultRuleDescriptionSection() {
+ return definition.getDefaultRuleDescriptionSectionDto();
+ }
+
+ public Collection<RuleDescriptionSectionDto> getRuleDescriptionSectionDtos() {
+ return definition.getRuleDescriptionSectionDtos();
+ }
+
+ public RuleDto addRuleDescriptionSectionDto(RuleDescriptionSectionDto ruleDescriptionSectionDto) {
+ definition.addRuleDescriptionSectionDto(ruleDescriptionSectionDto);
+ return this;
}
- public RuleDto setDescription(String description) {
- definition.setDescription(description);
+ public RuleDto addOrReplaceRuleDescriptionSectionDto(RuleDescriptionSectionDto ruleDescriptionSectionDto) {
+ definition.addOrReplaceRuleDescriptionSectionDto(ruleDescriptionSectionDto);
return this;
}
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;
assertThat(exportCustomRuleDto).isNotNull();
assertThat(exportCustomRuleDto.isCustomRule()).isTrue();
assertThat(exportCustomRuleDto.getParams()).isEmpty();
- assertThat(exportCustomRuleDto.getDescription()).isEqualTo(customRule.getDescription());
+ //FIXME SONAR-16314
+ assertThat(exportCustomRuleDto.getDescription()).isEqualTo(customRule.getRuleDescriptionSectionDtos().stream().map(RuleDescriptionSectionDto::getDescription).collect(Collectors.joining()));
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();
- assertThat(exportRuleDto.getDescription()).isEqualTo(rule.getDescription());
+ //FIXME SONAR-16314
+ assertThat(exportRuleDto.getDescription()).isEqualTo(rule.getRuleDescriptionSectionDtos().stream().map(RuleDescriptionSectionDto::getDescription).collect(Collectors.joining()));
assertThat(exportRuleDto.getExtendedDescription()).isEqualTo(ruleMetadata.getNoteData());
assertThat(exportRuleDto.getName()).isEqualTo(rule.getName());
assertThat(exportRuleDto.getRuleKey()).isEqualTo(rule.getKey());
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.session.ResultHandler;
import org.junit.Rule;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.api.rule.RuleStatus.REMOVED;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.newRuleMetadata;
public class RuleDaoTest {
private static final String UNKNOWN_RULE_UUID = "unknown-uuid";
+ private static final RuleDescriptionSectionDto RULE_DESCRIPTION_SECTION_1 = createDefaultRuleDescriptionSection("new description");
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
assertThat(actual.getRepositoryKey()).isEqualTo(expected.getRepositoryKey());
assertThat(actual.getRuleKey()).isEqualTo(expected.getRuleKey());
assertThat(actual.getKey()).isEqualTo(expected.getKey());
- assertThat(actual.getDescription()).isEqualTo(expected.getDescription());
- assertThat(actual.getDescriptionFormat()).isEqualTo(expected.getDescriptionFormat());
assertThat(actual.getStatus()).isEqualTo(expected.getStatus());
assertThat(actual.getName()).isEqualTo(expected.getName());
assertThat(actual.getConfigKey()).isEqualTo(expected.getConfigKey());
assertThat(actual.getSystemTags()).isEqualTo(expected.getSystemTags());
assertThat(actual.getSecurityStandards()).isEqualTo(expected.getSecurityStandards());
assertThat(actual.getType()).isEqualTo(expected.getType());
+ assertThat(actual.getDescriptionFormat()).isEqualTo(expected.getDescriptionFormat());
+ assertThat(actual.getRuleDescriptionSectionDtos()).usingRecursiveFieldByFieldElementComparator()
+ .isEqualTo(expected.getRuleDescriptionSectionDtos());
}
private static void verifyMetadata(RuleMetadataDto metadata, RuleMetadataDto expected) {
.setRuleKey("NewRuleKey")
.setRepositoryKey("plugin")
.setName("new name")
- .setDescription("new description")
.setDescriptionFormat(RuleDto.Format.MARKDOWN)
+ .addRuleDescriptionSectionDto(RULE_DESCRIPTION_SECTION_1)
.setStatus(RuleStatus.DEPRECATED)
.setConfigKey("NewConfigKey")
.setSeverity(Severity.INFO)
RuleDefinitionDto ruleDto = underTest.selectOrFailDefinitionByKey(db.getSession(), RuleKey.of("plugin", "NewRuleKey"));
assertThat(ruleDto.getUuid()).isNotNull();
assertThat(ruleDto.getName()).isEqualTo("new name");
- assertThat(ruleDto.getDescription()).isEqualTo("new description");
- assertThat(ruleDto.getDescriptionFormat()).isEqualTo(RuleDto.Format.MARKDOWN);
assertThat(ruleDto.getStatus()).isEqualTo(RuleStatus.DEPRECATED);
assertThat(ruleDto.getRuleKey()).isEqualTo("NewRuleKey");
assertThat(ruleDto.getRepositoryKey()).isEqualTo("plugin");
assertThat(ruleDto.getType()).isEqualTo(RuleType.BUG.getDbConstant());
assertThat(ruleDto.getCreatedAt()).isEqualTo(1_500_000_000_000L);
assertThat(ruleDto.getUpdatedAt()).isEqualTo(2_000_000_000_000L);
+ assertThat(ruleDto.getDescriptionFormat()).isEqualTo(RuleDto.Format.MARKDOWN);
+ assertThat(ruleDto.getRuleDescriptionSectionDtos()).usingRecursiveFieldByFieldElementComparator()
+ .containsOnly(RULE_DESCRIPTION_SECTION_1);
}
@Test
.setRuleKey("NewRuleKey")
.setRepositoryKey("plugin")
.setName("new name")
- .setDescription("new description")
.setDescriptionFormat(RuleDto.Format.MARKDOWN)
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(randomAlphabetic(5)))
.setStatus(RuleStatus.DEPRECATED)
.setConfigKey("NewConfigKey")
.setSeverity(Severity.INFO)
RuleDefinitionDto ruleDto = underTest.selectOrFailDefinitionByKey(db.getSession(), RuleKey.of("plugin", "NewRuleKey"));
assertThat(ruleDto.getName()).isEqualTo("new name");
- assertThat(ruleDto.getDescription()).isEqualTo("new description");
- assertThat(ruleDto.getDescriptionFormat()).isEqualTo(RuleDto.Format.MARKDOWN);
assertThat(ruleDto.getStatus()).isEqualTo(RuleStatus.DEPRECATED);
assertThat(ruleDto.getRuleKey()).isEqualTo("NewRuleKey");
assertThat(ruleDto.getRepositoryKey()).isEqualTo("plugin");
assertThat(ruleDto.getType()).isEqualTo(RuleType.BUG.getDbConstant());
assertThat(ruleDto.getCreatedAt()).isEqualTo(rule.getCreatedAt());
assertThat(ruleDto.getUpdatedAt()).isEqualTo(2_000_000_000_000L);
+ assertThat(ruleDto.getDescriptionFormat()).isEqualTo(RuleDto.Format.MARKDOWN);
+ assertThat(ruleDto.getRuleDescriptionSectionDtos()).usingRecursiveFieldByFieldElementComparator()
+ .containsOnly(RULE_DESCRIPTION_SECTION_1);
}
@Test
assertThat(firstRule.getRepository()).isEqualTo(r1.getRepositoryKey());
assertThat(firstRule.getPluginRuleKey()).isEqualTo(r1.getRuleKey());
assertThat(firstRule.getName()).isEqualTo(r1.getName());
- assertThat(firstRule.getDescription()).isEqualTo(r1.getDescription());
+ //FIXME SONAR-16309
+ assertThat(firstRule.getDescription()).isEqualTo(r1.getRuleDescriptionSectionDtos().stream().map(RuleDescriptionSectionDto::getDescription).collect(Collectors.joining()));
assertThat(firstRule.getDescriptionFormat()).isEqualTo(r1.getDescriptionFormat());
assertThat(firstRule.getSeverity()).isEqualTo(r1.getSeverity());
assertThat(firstRule.getStatus()).isEqualTo(r1.getStatus());
assertThat(firstRule.getRepository()).isEqualTo(r1.getRepositoryKey());
assertThat(firstRule.getPluginRuleKey()).isEqualTo(r1.getRuleKey());
assertThat(firstRule.getName()).isEqualTo(r1.getName());
- assertThat(firstRule.getDescription()).isEqualTo(r1.getDescription());
+ //FIXME SONAR-16309
+ assertThat(firstRule.getDescription()).isEqualTo(r1.getRuleDescriptionSectionDtos().stream().map(RuleDescriptionSectionDto::getDescription).collect(Collectors.joining()));
assertThat(firstRule.getDescriptionFormat()).isEqualTo(r1.getDescriptionFormat());
assertThat(firstRule.getSeverity()).isEqualTo(r1.getSeverity());
assertThat(firstRule.getSeverityAsString()).isEqualTo(SeverityUtil.getSeverityFromOrdinal(r1.getSeverity()));
import org.sonar.core.util.UuidFactory;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.core.util.Uuids;
-import org.sonar.db.rule.RuleDto.Format;
import org.sonar.db.rule.RuleDto.Scope;
import org.sonar.db.user.UserDto;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.apache.commons.lang.math.RandomUtils.nextInt;
import static org.sonar.api.rule.RuleKey.EXTERNAL_RULE_REPO_PREFIX;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
/**
* Utility class for tests involving rules
}
public static RuleDefinitionDto newRule(RuleKey key) {
+ RuleDefinitionDto ruleDefinitionDto = newRuleWithoutSection(key);
+ ruleDefinitionDto.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("description_" + randomAlphabetic(5)));
+ return ruleDefinitionDto;
+ }
+
+ public static RuleDefinitionDto newRuleWithoutSection() {
+ return newRuleWithoutSection(randomRuleKey());
+ }
+
+ public static RuleDefinitionDto newRuleWithoutSection(RuleKey ruleKey) {
return new RuleDefinitionDto()
- .setRepositoryKey(key.repository())
- .setRuleKey(key.rule())
+ .setRepositoryKey(ruleKey.repository())
+ .setRuleKey(ruleKey.rule())
.setUuid("rule_uuid_" + randomAlphanumeric(5))
.setName("name_" + randomAlphanumeric(5))
- .setDescription("description_" + randomAlphanumeric(5))
- .setDescriptionFormat(Format.HTML)
+ .setDescriptionFormat(RuleDto.Format.HTML)
.setType(RuleType.values()[nextInt(RuleType.values().length)])
.setStatus(RuleStatus.READY)
.setConfigKey("configKey_" + randomAlphanumeric(5))
.setRuleKey(ruleKey.rule())
.setRepositoryKey(ruleKey.repository())
.setName("Rule " + ruleKey.rule())
- .setDescription("Description " + ruleKey.rule())
- .setDescriptionFormat(Format.HTML)
+ .setDescriptionFormat(RuleDto.Format.HTML)
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Description" + ruleKey.rule()))
.setStatus(RuleStatus.READY)
.setConfigKey("InternalKey" + ruleKey.rule())
.setSeverity(Severity.INFO)
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
-import org.sonar.markdown.Markdown;
+
+import static org.sonar.server.rule.RuleDescriptionFormatter.getDescriptionAsHtml;
/**
* Will be removed in the future.
private static org.sonar.api.rules.Rule toRule(RuleDto rule, List<RuleParamDto> params) {
String severity = rule.getSeverityString();
- String description = rule.getDescription();
- RuleDto.Format descriptionFormat = rule.getDescriptionFormat();
org.sonar.api.rules.Rule apiRule = new org.sonar.api.rules.Rule();
apiRule
.setSeverity(severity != null ? RulePriority.valueOf(severity) : null)
.setStatus(rule.getStatus().name())
.setSystemTags(rule.getSystemTags().toArray(new String[rule.getSystemTags().size()]))
- .setTags(rule.getTags().toArray(new String[rule.getTags().size()]));
- if (description != null && descriptionFormat != null) {
- if (RuleDto.Format.HTML.equals(descriptionFormat)) {
- apiRule.setDescription(description);
- } else {
- apiRule.setDescription(Markdown.convertToHtml(description));
- }
- }
+ .setTags(rule.getTags().toArray(new String[rule.getTags().size()]))
+ .setDescription(getDescriptionAsHtml(rule.getDefinition()));
+
List<org.sonar.api.rules.RuleParam> apiParams = new ArrayList<>();
for (RuleParamDto param : params) {
}
public static HotspotRuleDescription from(RuleDefinitionDto dto) {
- String description = dto.isCustomRule() ? RuleDescriptionFormatter.getDescriptionAsHtml(dto) : dto.getDescription();
+ String description = RuleDescriptionFormatter.getDescriptionAsHtml(dto);
return from(description);
}
*/
package org.sonar.server.rule;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.markdown.Markdown;
+import static com.google.common.collect.MoreCollectors.toOptional;
import static java.lang.String.format;
public class RuleDescriptionFormatter {
private RuleDescriptionFormatter() { /* static helpers */ }
- public static String getDescriptionAsHtml(RuleDefinitionDto ruleDto) {
- String description = ruleDto.getDescription();
- RuleDto.Format descriptionFormat = ruleDto.getDescriptionFormat();
- if (description != null && descriptionFormat != null) {
- switch (descriptionFormat) {
- case MARKDOWN:
- return Markdown.convertToHtml(description);
- case HTML:
- return description;
- default:
- throw new IllegalStateException(format("Rule description format '%s' is unknown for key '%s'", descriptionFormat, ruleDto.getKey().toString()));
- }
+ public static String getDescriptionAsHtml(RuleDefinitionDto ruleDefinitionDto) {
+ if (ruleDefinitionDto.getDescriptionFormat() == null) {
+ return null;
+ }
+ Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos = ruleDefinitionDto.getRuleDescriptionSectionDtos();
+ Optional<RuleDescriptionSectionDto> ruleDescriptionSectionDto = findDefaultDescription(ruleDescriptionSectionDtos);
+ return ruleDescriptionSectionDto
+ .map(ruleDescriptionSection -> toHtml(ruleDefinitionDto, ruleDescriptionSection))
+ .orElse(null);
+ }
+
+ private static Optional<RuleDescriptionSectionDto> findDefaultDescription(Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos) {
+ return ruleDescriptionSectionDtos.stream()
+ .filter(RuleDescriptionSectionDto::isDefault)
+ .collect(toOptional());
+ }
+
+ private static String toHtml(RuleDefinitionDto ruleDefinitionDto, RuleDescriptionSectionDto ruleDescriptionSectionDto) {
+ RuleDto.Format descriptionFormat = Objects.requireNonNull(ruleDefinitionDto.getDescriptionFormat(),
+ "Rule " + ruleDefinitionDto.getDescriptionFormat() + " contains section(s) but has no format set");
+ switch (descriptionFormat) {
+ case MARKDOWN:
+ return Markdown.convertToHtml(ruleDescriptionSectionDto.getDescription());
+ case HTML:
+ return ruleDescriptionSectionDto.getDescription();
+ default:
+ throw new IllegalStateException(format("Rule description section format '%s' is unknown for rule key '%s'", descriptionFormat, ruleDefinitionDto.getKey()));
}
- return null;
}
}
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;
@RunWith(DataProviderRunner.class)
public class HotspotRuleDescriptionTest {
@Test
public void parse_returns_all_empty_fields_when_no_description() {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription(null);
+ RuleDefinitionDto dto = newRuleWithoutSection();
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_returns_all_empty_fields_when_empty_description() {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription("");
+ RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(""));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
@UseDataProvider("descriptionsWithoutTitles")
public void parse_to_risk_description_fields_when_desc_contains_no_section(String description) {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription(description);
+ RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(description));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_return_null_risk_when_desc_starts_with_ask_yourself_title() {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription(ASKATRISK + RECOMMENTEDCODINGPRACTICE);
+ RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ createDefaultRuleDescriptionSection((ASKATRISK + RECOMMENTEDCODINGPRACTICE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_return_null_vulnerable_when_no_ask_yourself_whether_title() {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription(DESCRIPTION + RECOMMENTEDCODINGPRACTICE);
+ RuleDefinitionDto dto = newRuleWithoutSection()
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection((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 = RuleTesting.newRule().setDescription(DESCRIPTION + ASKATRISK);
+ RuleDefinitionDto dto = newRuleWithoutSection()
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection((DESCRIPTION + ASKATRISK)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_with_noncompliant_section_not_removed() {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription(DESCRIPTION + NONCOMPLIANTCODE + COMPLIANTCODE);
+ RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ createDefaultRuleDescriptionSection((DESCRIPTION + NONCOMPLIANTCODE + COMPLIANTCODE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_moved_noncompliant_code() {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription(DESCRIPTION + RECOMMENTEDCODINGPRACTICE + NONCOMPLIANTCODE + SEE);
+ RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ createDefaultRuleDescriptionSection((DESCRIPTION + RECOMMENTEDCODINGPRACTICE + NONCOMPLIANTCODE + SEE)));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
@Test
public void parse_moved_sensitivecode_code() {
- RuleDefinitionDto dto = RuleTesting.newRule().setDescription(DESCRIPTION + ASKATRISK + RECOMMENTEDCODINGPRACTICE + SENSITIVECODE + SEE);
+ RuleDefinitionDto dto = newRuleWithoutSection().addRuleDescriptionSectionDto(
+ createDefaultRuleDescriptionSection((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 = RuleTesting.newRule()
+ RuleDefinitionDto dto = newRuleWithoutSection()
.setTemplateUuid("123")
.setDescriptionFormat(RuleDto.Format.MARKDOWN)
- .setDescription(
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(
ruleDescription + "\n"
- + "== Exceptions" + "\n"
- + exceptionsContent + "\n"
- + "== Ask Yourself Whether" + "\n"
- + askContent + "\n"
- + "== Recommended Secure Coding Practices" + "\n"
- + recommendedContent + "\n"
- );
+ + "== Exceptions" + "\n"
+ + exceptionsContent + "\n"
+ + "== Ask Yourself Whether" + "\n"
+ + askContent + "\n"
+ + "== Recommended Secure Coding Practices" + "\n"
+ + recommendedContent + "\n"
+ ));
HotspotRuleDescription result = HotspotRuleDescription.from(dto);
import org.junit.Test;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
public class RuleDescriptionFormatterTest {
+ private static final RuleDescriptionSectionDto HTML_SECTION = createDefaultRuleDescriptionSection("<span class=\"example\">*md* ``description``</span>");
+ private static final RuleDescriptionSectionDto MARKDOWN_SECTION = createDefaultRuleDescriptionSection("*md* ``description``");
+
@Test
public void getMarkdownDescriptionAsHtml() {
- RuleDefinitionDto rule = new RuleDefinitionDto().setDescription("*md* ``description``").setDescriptionFormat(RuleDto.Format.MARKDOWN);
+ RuleDefinitionDto rule = new RuleDefinitionDto().setDescriptionFormat(RuleDto.Format.MARKDOWN).addRuleDescriptionSectionDto(MARKDOWN_SECTION);
String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
assertThat(html).isEqualTo("<strong>md</strong> <code>description</code>");
}
@Test
public void getHtmlDescriptionAsIs() {
- String description = "<span class=\"example\">*md* ``description``</span>";
- RuleDefinitionDto rule = new RuleDefinitionDto().setDescription(description).setDescriptionFormat(RuleDto.Format.HTML);
+ RuleDefinitionDto rule = new RuleDefinitionDto().setDescriptionFormat(RuleDto.Format.HTML).addRuleDescriptionSectionDto(HTML_SECTION);
String html = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
- assertThat(html).isEqualTo(description);
+ assertThat(html).isEqualTo(HTML_SECTION.getDescription());
}
@Test
- public void handleNullDescription() {
- RuleDefinitionDto rule = new RuleDefinitionDto().setDescription(null).setDescriptionFormat(RuleDto.Format.HTML);
+ public void handleEmptyDescription() {
+ RuleDefinitionDto rule = new RuleDefinitionDto().setDescriptionFormat(RuleDto.Format.HTML);
String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
assertThat(result).isNull();
}
@Test
public void handleNullDescriptionFormat() {
- RuleDefinitionDto rule = new RuleDefinitionDto().setDescription("whatever").setDescriptionFormat(null);
+ RuleDescriptionSectionDto sectionWithNullFormat = createDefaultRuleDescriptionSection("whatever");
+ RuleDefinitionDto rule = new RuleDefinitionDto().addRuleDescriptionSectionDto(sectionWithNullFormat);
String result = RuleDescriptionFormatter.getDescriptionAsHtml(rule);
assertThat(result).isNull();
}
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
-import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import static org.sonar.api.rules.RuleType.CODE_SMELL;
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
import static org.sonar.api.rules.RuleType.VULNERABILITY;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.setCreatedAt;
import static org.sonar.db.rule.RuleTesting.setIsExternal;
import static org.sonar.db.rule.RuleTesting.setIsTemplate;
// otherwise the generated random values may raise false-positives
RuleDefinitionDto rule1 = createJavaRule(rule -> rule.setRuleKey("123")
.setName("rule 123")
- .setDescription("My great rule CWE-123 which makes your code 1000 times better!"));
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("My great rule CWE-123 which makes your code 1000 times better!")));
RuleDefinitionDto rule2 = createJavaRule(rule -> rule.setRuleKey("124")
.setName("rule 124")
- .setDescription("Another great and shiny rule CWE-124"));
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Another great and shiny rule CWE-124")));
RuleDefinitionDto rule3 = createJavaRule(rule -> rule.setRuleKey("1000")
.setName("rule 1000")
- .setDescription("Another great rule CWE-1000"));
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Another great rule CWE-1000")));
RuleDefinitionDto rule4 = createJavaRule(rule -> rule.setRuleKey("404")
.setName("rule 404")
- .setDescription("<h1>HTML-Geeks</h1><p style=\"color:blue\">special formatting!</p><table><tr><td>inside</td><td>tables</td></tr></table>"));
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("<h1>HTML-Geeks</h1><p style=\"color:blue\">special formatting!</p><table><tr><td>inside</td><td>tables</td></tr></table>")));
RuleDefinitionDto rule5 = createJavaRule(rule -> rule.setRuleKey("405")
.setName("rule 405")
- .setDescription("internationalization missunderstandings alsdkjfnadklsjfnadkdfnsksdjfn"));
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("internationalization missunderstandings alsdkjfnadklsjfnadkdfnsksdjfn")));
index();
// partial match at word boundary
import java.util.Set;
import java.util.stream.IntStream;
import java.util.stream.Stream;
-import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
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.RuleDto;
import org.sonar.db.rule.RuleDto.Scope;
import org.sonar.db.rule.RuleTesting;
import static java.util.stream.Collectors.toSet;
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.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;
@RunWith(DataProviderRunner.class)
public class RuleIndexerTest {
- public static final String VALID_HOTSPOT_RULE_DESCRIPTION = "acme\n" +
+ private static final String VALID_HOTSPOT_RULE_DESCRIPTION = "acme\n" +
"<h2>Ask Yourself Whether</h2>\n" +
"bar\n" +
"<h2>Recommended Secure Coding Practices</h2>\n" +
"foo";
+
+ private static final RuleDescriptionSectionDto RULE_DESCRIPTION_SECTION_DTO = createDefaultRuleDescriptionSection(VALID_HOTSPOT_RULE_DESCRIPTION);
+
@Rule
public EsTester es = EsTester.create();
@Rule
.setRepositoryKey("xoo")
.setConfigKey("S1")
.setName("Null Pointer")
- .setDescription("S001 desc")
.setDescriptionFormat(RuleDto.Format.HTML)
+ .addRuleDescriptionSectionDto(RULE_DESCRIPTION_SECTION_DTO)
.setLanguage("xoo")
.setSeverity(Severity.BLOCKER)
.setStatus(RuleStatus.READY)
@Test
public void index_long_rule_description() {
String description = IntStream.range(0, 100000).map(i -> i % 100).mapToObj(Integer::toString).collect(joining(" "));
- RuleDefinitionDto rule = dbTester.rules().insert(r -> r.setDescription(description));
+ RuleDescriptionSectionDto ruleDescriptionSectionDto = createDefaultRuleDescriptionSection(description);
+ RuleDefinitionDto rule = dbTester.rules().insert(r -> r.addRuleDescriptionSectionDto(ruleDescriptionSectionDto));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
assertThat(es.countDocuments(TYPE_RULE)).isOne();
RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRule()
.setType(RuleType.SECURITY_HOTSPOT)
.setSecurityStandards(standards)
- .setDescription(VALID_HOTSPOT_RULE_DESCRIPTION));
+ .addRuleDescriptionSectionDto(RULE_DESCRIPTION_SECTION_DTO));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
assertThat(logTester.getLogs()).hasSize(1);
}
@Test
- @UseDataProvider("nullEmptyOrNoTitleDescription")
- public void log_debug_when_hotspot_rule_description_is_null_or_empty(@Nullable String description) {
- RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRule()
- .setType(RuleType.SECURITY_HOTSPOT)
- .setDescription(description));
+ public void log_debug_when_hotspot_rule_no_description () {
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRuleWithoutSection()
+ .setType(RuleType.SECURITY_HOTSPOT));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
assertThat(logTester.getLogs()).hasSize(1);
rule.getKey()));
}
- @DataProvider
- public static Object[][] nullEmptyOrNoTitleDescription() {
- return new Object[][] {
- {null},
- {""},
- };
- }
-
@Test
public void log_debug_when_hotspot_rule_description_has_none_of_the_key_titles() {
RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRule()
.setType(RuleType.SECURITY_HOTSPOT)
- .setDescription(randomAlphabetic(30)));
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(randomAlphabetic(30))));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
assertThat(logTester.getLogs()).hasSize(1);
public void log_debug_when_hotspot_rule_description_is_missing_fixIt_tab_content() {
RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRule()
.setType(RuleType.SECURITY_HOTSPOT)
- .setDescription("bar\n" +
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("bar\n" +
"<h2>Ask Yourself Whether</h2>\n" +
- "foo"));
+ "foo")));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
assertThat(logTester.getLogs()).hasSize(1);
public void log_debug_when_hotspot_rule_description_is_missing_risk_tab_content() {
RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRule()
.setType(RuleType.SECURITY_HOTSPOT)
- .setDescription("<h2>Ask Yourself Whether</h2>\n" +
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("<h2>Ask Yourself Whether</h2>\n" +
"bar\n" +
"<h2>Recommended Secure Coding Practices</h2>\n" +
- "foo"));
+ "foo")));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
assertThat(logTester.getLogs()).hasSize(1);
public void log_debug_when_hotspot_rule_description_is_missing_vulnerable_tab_content() {
RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRule()
.setType(RuleType.SECURITY_HOTSPOT)
- .setDescription("bar\n" +
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("bar\n" +
"<h2>Recommended Secure Coding Practices</h2>\n" +
- "foo"));
+ "foo")));
underTest.commitAndIndex(dbTester.getSession(), rule.getUuid());
assertThat(logTester.getLogs()).hasSize(1);
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
-import org.sonar.markdown.Markdown;
import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableMap;
private static Rule toRule(RuleDefinitionDto ruleDefinition, List<RuleParamDto> params) {
String severity = ruleDefinition.getSeverityString();
- String description = ruleDefinition.getDescription();
- RuleDto.Format descriptionFormat = ruleDefinition.getDescriptionFormat();
Rule apiRule = new Rule();
apiRule
.setSeverity(severity != null ? RulePriority.valueOf(severity) : null)
.setStatus(ruleDefinition.getStatus().name())
.setSystemTags(ruleDefinition.getSystemTags().toArray(new String[ruleDefinition.getSystemTags().size()]))
- .setTags(new String[0]);
- if (description != null && descriptionFormat != null) {
- if (RuleDto.Format.HTML.equals(descriptionFormat)) {
- apiRule.setDescription(description);
- } else {
- apiRule.setDescription(Markdown.convertToHtml(description));
- }
- }
+ .setTags(new String[0])
+ .setDescription(RuleDescriptionFormatter.getDescriptionAsHtml(ruleDefinition));
+
List<org.sonar.api.rules.RuleParam> apiParams = new ArrayList<>();
for (RuleParamDto param : params) {
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
public class CachingRuleFinderTest {
@org.junit.Rule
assertThat(rule.getSeverity().name()).isEqualTo(ruleDefinition.getSeverityString());
assertThat(rule.getSystemTags()).isEqualTo(ruleDefinition.getSystemTags().toArray(new String[0]));
assertThat(rule.getTags()).isEmpty();
- assertThat(rule.getDescription()).isEqualTo(ruleDefinition.getDescription());
+ assertThat(rule.getDescription()).isEqualTo(createDefaultRuleDescriptionSection(randomAlphabetic(5)).getDescription());
assertThat(rule.getParams()).hasSize(1);
org.sonar.api.rules.RuleParam param = rule.getParams().iterator().next();
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableMap;
+import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
/**
* Register rules at server startup
private Stream<RuleDefinitionDto> getAllModified() {
return Stream.of(
- created.stream(),
- updated.stream(),
- removed.stream(),
- renamed.keySet().stream())
+ created.stream(),
+ updated.stream(),
+ removed.stream(),
+ renamed.keySet().stream())
.flatMap(s -> s);
}
.setIsAdHoc(false)
.setCreatedAt(system2.now())
.setUpdatedAt(system2.now());
- if (ruleDef.htmlDescription() != null) {
- ruleDto.setDescription(ruleDef.htmlDescription());
+ if (isNotEmpty(ruleDef.htmlDescription())) {
+ ruleDto.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(ruleDef.htmlDescription()));
ruleDto.setDescriptionFormat(Format.HTML);
- } else {
- ruleDto.setDescription(ruleDef.markdownDescription());
+ } else if (isNotEmpty(ruleDef.markdownDescription())) {
+ ruleDto.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(ruleDef.markdownDescription()));
ruleDto.setDescriptionFormat(Format.MARKDOWN);
}
+
DebtRemediationFunction debtRemediationFunction = ruleDef.debtRemediationFunction();
if (debtRemediationFunction != null) {
ruleDto.setDefRemediationFunction(debtRemediationFunction.type().name());
return changed;
}
- private static boolean mergeDescription(RulesDefinition.Rule def, RuleDefinitionDto dto) {
+ private static boolean mergeDescription(RulesDefinition.Rule rule, RuleDefinitionDto ruleDefinitionDto) {
boolean changed = false;
- if (def.htmlDescription() != null && !Objects.equals(dto.getDescription(), def.htmlDescription())) {
- dto.setDescription(def.htmlDescription());
- dto.setDescriptionFormat(Format.HTML);
+
+ String currentDescription = ruleDefinitionDto.getDefaultRuleDescriptionSectionDto() != null ? ruleDefinitionDto.getDefaultRuleDescriptionSectionDto().getDescription() : null;
+ if (isHtmlDescriptionUpdated(rule, currentDescription)) {
+ ruleDefinitionDto.addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(rule.htmlDescription()));
+ ruleDefinitionDto.setDescriptionFormat(Format.HTML);
changed = true;
- } else if (def.markdownDescription() != null && !Objects.equals(dto.getDescription(), def.markdownDescription())) {
- dto.setDescription(def.markdownDescription());
- dto.setDescriptionFormat(Format.MARKDOWN);
+ } else if (isMarkdownDescriptionUpdated(rule, currentDescription)) {
+ ruleDefinitionDto.addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(rule.markdownDescription()));
+ ruleDefinitionDto.setDescriptionFormat(Format.MARKDOWN);
changed = true;
}
return changed;
}
+ private static boolean isMarkdownDescriptionUpdated(RulesDefinition.Rule rule, @Nullable String currentDescription) {
+ return isNotEmpty(rule.markdownDescription()) && !Objects.equals(rule.markdownDescription(), currentDescription);
+ }
+
+ private static boolean isHtmlDescriptionUpdated(RulesDefinition.Rule def, @Nullable String currentDescription) {
+ return isNotEmpty(def.htmlDescription()) && !Objects.equals(def.htmlDescription(), currentDescription);
+ }
+
private static boolean mergeDebtDefinitions(RulesDefinition.Rule def, RuleDefinitionDto dto) {
// Debt definitions are set to null if the sub-characteristic and the remediation function are null
DebtRemediationFunction debtRemediationFunction = def.debtRemediationFunction();
import static org.sonar.api.server.rule.RulesDefinition.NewRule;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2021;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
@RunWith(DataProviderRunner.class)
public class RegisterRulesTest {
private ActiveRuleIndexer activeRuleIndexer;
private RuleIndex ruleIndex;
-
@Before
public void before() {
ruleIndexer = new RuleIndexer(es.client(), dbClient);
assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RULE_KEY1);
assertThat(rule1.getName()).isEqualTo("One");
- assertThat(rule1.getDescription()).isEqualTo("Description of One");
+ assertThat(rule1.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Description of One");
assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER);
assertThat(rule1.getTags()).isEmpty();
assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag2", "tag3");
RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), HOTSPOT_RULE_KEY);
assertThat(hotspotRule.getName()).isEqualTo("Hotspot");
- assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot");
+ assertThat(hotspotRule.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Minimal hotspot");
assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime());
assertThat(hotspotRule.getUpdatedAt()).isEqualTo(DATE1.getTime());
assertThat(hotspotRule.getType()).isEqualTo(RuleType.SECURITY_HOTSPOT.getDbConstant());
assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(2);
RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), EXTERNAL_RULE_KEY1);
assertThat(rule1.getName()).isEqualTo("One");
- assertThat(rule1.getDescription()).isEqualTo("Description of One");
+ assertThat(rule1.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Description of One");
assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER);
assertThat(rule1.getTags()).isEmpty();
assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag2", "tag3");
RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), EXTERNAL_HOTSPOT_RULE_KEY);
assertThat(hotspotRule.getName()).isEqualTo("Hotspot");
- assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot");
+ assertThat(hotspotRule.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Minimal hotspot");
assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime());
assertThat(hotspotRule.getUpdatedAt()).isEqualTo(DATE1.getTime());
assertThat(hotspotRule.getType()).isEqualTo(RuleType.SECURITY_HOTSPOT.getDbConstant());
// rule1 has been updated
rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RULE_KEY1);
assertThat(rule1.getName()).isEqualTo("One v2");
- assertThat(rule1.getDescription()).isEqualTo("Description of One v2");
+ assertThat(rule1.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Description of One v2");
assertThat(rule1.getSeverityString()).isEqualTo(INFO);
assertThat(rule1.getTags()).containsOnly("usertag1", "usertag2");
assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag4");
// rule1 has been updated
RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RuleKey.of("fake", "rule"));
assertThat(rule1.getName()).isEqualTo("Name2");
- assertThat(rule1.getDescription()).isEqualTo("Description");
+ assertThat(rule1.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Description");
assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()).getTotal()).isOne();
assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getTotal()).isZero();
RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RuleKey.of(repository, ruleKey2));
assertThat(rule2.getUuid()).isEqualTo(rule1.getUuid());
assertThat(rule2.getName()).isEqualTo("Name2");
- assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
+ assertThat(rule2.getDefaultRuleDescriptionSection().getDescription()).isEqualTo(rule1.getDefaultRuleDescriptionSection().getDescription());
SearchIdResult<String> searchRule2 = ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions());
assertThat(searchRule2.getUuids()).containsOnly(rule2.getUuid());
RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RuleKey.of(repository2, ruleKey));
assertThat(rule2.getUuid()).isEqualTo(rule1.getUuid());
assertThat(rule2.getName()).isEqualTo("Name2");
- assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
+ assertThat(rule2.getDefaultRuleDescriptionSection().getDescription()).isEqualTo(rule1.getDefaultRuleDescriptionSection().getDescription());
SearchIdResult<String> searchRule2 = ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions());
assertThat(searchRule2.getUuids()).containsOnly(rule2.getUuid());
RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RuleKey.of(repo2, ruleKey2));
assertThat(rule2.getUuid()).isEqualTo(rule1.getUuid());
assertThat(rule2.getName()).isEqualTo(rule1.getName());
- assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
+ assertThat(rule2.getDefaultRuleDescriptionSection().getDescription()).isEqualTo(rule1.getDefaultRuleDescriptionSection().getDescription());
assertThat(ruleIndex.search(new RuleQuery().setQueryText(name), new SearchOptions()).getUuids())
.containsOnly(rule2.getUuid());
@DataProvider
public static Object[][] allRenamingCases() {
- return new Object[][]{
+ return new Object[][] {
{"repo1", "rule1", "repo1", "rule2"},
{"repo1", "rule1", "repo2", "rule1"},
{"repo1", "rule1", "repo2", "rule2"},
// rule1 has been updated
RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RuleKey.of("fake", "rule"));
assertThat(rule1.getName()).isEqualTo("Name");
- assertThat(rule1.getDescription()).isEqualTo("Desc2");
+ assertThat(rule1.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Desc2");
assertThat(ruleIndex.search(new RuleQuery().setQueryText("Desc2"), new SearchOptions()).getTotal()).isOne();
assertThat(ruleIndex.search(new RuleQuery().setQueryText("Desc1"), new SearchOptions()).getTotal()).isZero();
NewRepository repo = context.createExternalRepository("fake", rule.getLanguage());
repo.createRule(rule.getRuleKey())
.setName(rule.getName())
- .setHtmlDescription(rule.getDescription());
+ .setHtmlDescription(rule.getDefaultRuleDescriptionSectionDto().getDescription());
repo.done();
});
.setRepositoryKey("findbugs")
.setName("Rule One")
.setScope(Scope.ALL)
- .setDescription("Rule one description")
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Rule one description"))
.setDescriptionFormat(RuleDto.Format.HTML)
.setSystemTags(newHashSet("tag1", "tag2")));
db.getSession().commit();
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.newCustomRule;
import static org.sonar.db.rule.RuleTesting.newTemplateRule;
import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED;
.setLanguage("xoo")
.setRepositoryKey("repo")
.setRuleKey("ruleKey")
- .setDescription("<div>line1\nline2</div>")
- .setDescriptionFormat(MARKDOWN);
+ .setDescriptionFormat(RuleDto.Format.MARKDOWN)
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("<div>line1\nline2</div>"));
db.rules().insert(rule1);
ActiveRuleDto activeRuleDto = ActiveRuleDto.createFor(qualityProfileDto, rule1);
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDto.Format;
import org.sonar.db.rule.RuleMetadataDto;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.server.exceptions.BadRequestException.checkRequest;
@ServerSide
.setTemplateUuid(templateRuleDto.getUuid())
.setConfigKey(templateRuleDto.getConfigKey())
.setName(newRule.name())
- .setDescription(newRule.markdownDescription())
- .setDescriptionFormat(Format.MARKDOWN)
.setSeverity(newRule.severity())
.setStatus(newRule.status())
.setType(newRule.type() == null ? templateRuleDto.getType() : newRule.type().getDbConstant())
.setIsAdHoc(false)
.setCreatedAt(system2.now())
.setUpdatedAt(system2.now());
+
+ if (newRule.markdownDescription() != null) {
+ RuleDescriptionSectionDto ruleDescriptionSectionDto = createDefaultRuleDescriptionSection(newRule.markdownDescription());
+ ruleDefinition.setDescriptionFormat(Format.MARKDOWN);
+ ruleDefinition.addRuleDescriptionSectionDto(ruleDescriptionSectionDto);
+ }
+
dbClient.ruleDao().insert(dbSession, ruleDefinition);
Set<String> tags = templateRuleDto.getTags();
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.server.rule.index.RuleIndexer;
import static com.google.common.collect.FluentIterable.from;
import static com.google.common.collect.Lists.newArrayList;
import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
@ServerSide
public class RuleUpdater {
if (isNullOrEmpty(description)) {
throw new IllegalArgumentException("The description is missing");
}
- rule.setDescription(description);
+ RuleDescriptionSectionDto descriptionSectionDto = createDefaultRuleDescriptionSection(description);
rule.setDescriptionFormat(RuleDto.Format.MARKDOWN);
+ rule.addOrReplaceRuleDescriptionSectionDto(descriptionSectionDto);
}
private static void updateSeverity(RuleUpdate update, RuleDto rule) {
import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
import org.sonar.db.rule.DeprecatedRuleKeyDto;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDescriptionSectionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDto.Scope;
import org.sonar.db.rule.RuleMetadataDto;
import org.sonarqube.ws.Common.RuleScope;
import org.sonarqube.ws.Rules;
+import static java.util.stream.Collectors.joining;
import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_CREATED_AT;
}
}
- String description = ruleDto.getDescription();
- if (shouldReturnField(fieldsToReturn, FIELD_MARKDOWN_DESCRIPTION) && description != null) {
+ if (shouldReturnField(fieldsToReturn, FIELD_MARKDOWN_DESCRIPTION)
+ && !ruleDto.getRuleDescriptionSectionDtos().isEmpty()) {
+ String description = concatenateSectionTemporaryForSonar16302(ruleDto);
ruleResponse.setMdDesc(description);
}
}
+ private static String concatenateSectionTemporaryForSonar16302(RuleDefinitionDto ruleDto) {
+ return ruleDto.getRuleDescriptionSectionDtos().stream()
+ .map(RuleDescriptionSectionDto::getDescription)
+ .collect(joining());
+ }
+
private void setNotesFields(Rules.Rule.Builder ruleResponse, RuleMetadataDto ruleDto, Map<String, UserDto> usersByUuid, Set<String> fieldsToReturn) {
String noteData = ruleDto.getNoteData();
if (shouldReturnField(fieldsToReturn, "htmlNote") && noteData != null) {
import java.util.Random;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static org.mockito.Mockito.when;
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
@RunWith(DataProviderRunner.class)
String description = "== Title\n<div>line1\nline2</div>";
- RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT,
+ RuleDefinitionDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
r -> r.setTemplateUuid("123")
- .setDescription(description)
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(description))
.setDescriptionFormat(MARKDOWN));
IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
- RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT, r -> r.setTemplateUuid("123").setDescription(null));
+ RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT, r -> r.setTemplateUuid("123"));
IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
mockChangelogAndCommentsFormattingContext();
}
private RuleDefinitionDto newRule(RuleType ruleType, Consumer<RuleDefinitionDto> populate) {
- RuleDefinitionDto ruleDefinition = RuleTesting.newRule()
- .setType(ruleType);
- populate.accept(ruleDefinition);
- dbTester.rules().insert(ruleDefinition);
- return ruleDefinition;
+ return newRule(ruleType, RuleTesting::newRule, populate);
+ }
+
+ private RuleDefinitionDto newRuleWithoutSection(RuleType ruleType, Consumer<RuleDefinitionDto> populate) {
+ return newRule(ruleType, RuleTesting::newRuleWithoutSection, populate);
+ }
+
+ private RuleDefinitionDto newRule(RuleType ruleType, Supplier<RuleDefinitionDto> ruleDefinitionDtoSupplier, Consumer<RuleDefinitionDto> populate) {
+ RuleDefinitionDto ruleDefinitionDto = ruleDefinitionDtoSupplier.get().setType(ruleType);
+ populate.accept(ruleDefinitionDto);
+ dbTester.rules().insert(ruleDefinitionDto);
+ return ruleDefinitionDto;
}
private static class IssueDtoSetArgumentMatcher implements ArgumentMatcher<Set<IssueDto>> {
import static org.sonar.db.component.ComponentDto.PULL_REQUEST_SEPARATOR;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.issue.IssueTesting.newDto;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.server.tester.UserSessionRule.standalone;
import static org.sonarqube.ws.Common.RuleType.BUG;
import static org.sonarqube.ws.Common.RuleType.SECURITY_HOTSPOT_VALUE;
private RuleDto newIssueRule() {
RuleDto rule = RuleTesting.newXooX1()
.setName("Rule name")
- .setDescription("Rule desc")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Rule desc"))
.setStatus(RuleStatus.READY);
db.rules().insert(rule.getDefinition());
return rule;
private RuleDto newHotspotRule() {
RuleDto rule = RuleTesting.newXooX2()
.setName("Rule name")
- .setDescription("Rule desc")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Rule desc"))
.setStatus(RuleStatus.READY)
.setType(SECURITY_HOTSPOT_VALUE);
db.rules().insert(rule.getDefinition());
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
public class QProfileBackuperImplTest {
RuleDefinitionDto templateRule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto
.setIsTemplate(true));
RuleDefinitionDto rule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto
- .setDescription("custom rule description")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("custom rule description"))
.setName("custom rule name")
.setStatus(RuleStatus.READY)
.setTemplateUuid(templateRule.getUuid()));
"<priority>" + activeRule.getSeverityString() + "</priority>" +
"<name>" + rule.getName() + "</name>" +
"<templateKey>" + templateRule.getKey().rule() + "</templateKey>" +
- "<description>" + rule.getDescription() + "</description>" +
+ "<description>" + rule.getDefaultRuleDescriptionSectionDto().getDescription() + "</description>" +
"<parameters><parameter>" +
"<key>" + param.getName() + "</key>" +
"<value>20</value>" +
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.fail;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations;
assertThat(rule.getPluginKey()).isEqualTo("sonarjava");
assertThat(rule.getTemplateUuid()).isEqualTo(templateRule.getUuid());
assertThat(rule.getName()).isEqualTo("My custom");
- assertThat(rule.getDescription()).isEqualTo("Some description");
+ assertThat(rule.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("Some description");
assertThat(rule.getSeverityString()).isEqualTo("MAJOR");
assertThat(rule.getStatus()).isEqualTo(RuleStatus.READY);
assertThat(rule.getLanguage()).isEqualTo("java");
.setRuleKey(key)
.setStatus(RuleStatus.REMOVED)
.setName("Old name")
- .setDescription("Old description")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Old description"))
.setDescriptionFormat(Format.MARKDOWN)
.setSeverity(Severity.INFO);
dbTester.rules().insert(rule.getDefinition());
// These values should be the same than before
assertThat(result.getName()).isEqualTo("Old name");
- assertThat(result.getDescription()).isEqualTo("Old description");
+ assertThat(result.getDefaultRuleDescriptionSectionDto().getDescription()).isEqualTo("Old description");
assertThat(result.getSeverityString()).isEqualTo(Severity.INFO);
List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey);
.setRuleKey(key)
.setStatus(RuleStatus.REMOVED)
.setName("Old name")
- .setDescription("Old description")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Old description"))
.setSeverity(Severity.INFO);
dbTester.rules().insert(rule.getDefinition());
dbTester.rules().insertRuleParam(rule.getDefinition(), param -> param.setDefaultValue("a.*"));
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.sonar.api.rule.Severity.CRITICAL;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.server.rule.RuleUpdate.createForCustomRule;
import static org.sonar.server.rule.RuleUpdate.createForPluginRule;
// Create custom rule
RuleDefinitionDto customRule = RuleTesting.newCustomRule(templateRule)
.setName("Old name")
- .setDescription("Old description")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Old description"))
.setSeverity(Severity.MINOR)
.setStatus(RuleStatus.BETA)
.getDefinition();
RuleDto customRuleReloaded = db.getDbClient().ruleDao().selectOrFailByKey(dbSession, customRule.getKey());
assertThat(customRuleReloaded).isNotNull();
assertThat(customRuleReloaded.getName()).isEqualTo("New name");
- assertThat(customRuleReloaded.getDescription()).isEqualTo("New description");
+ assertThat(customRuleReloaded.getDefaultRuleDescriptionSection().getDescription()).isEqualTo("New description");
assertThat(customRuleReloaded.getSeverityString()).isEqualTo("MAJOR");
assertThat(customRuleReloaded.getStatus()).isEqualTo(RuleStatus.READY);
// Create custom rule
RuleDefinitionDto customRule = RuleTesting.newCustomRule(templateRule)
.setName("Old name")
- .setDescription("Old description")
+ .addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Old description"))
.setSeverity(Severity.MINOR)
.setStatus(RuleStatus.BETA)
.getDefinition();
import static org.sonar.api.rules.RuleType.BUG;
import static org.sonar.api.rules.RuleType.CODE_SMELL;
import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.newCustomRule;
import static org.sonar.db.rule.RuleTesting.newTemplateRule;
import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations;
.setRuleKey("MY_CUSTOM")
.setStatus(RuleStatus.REMOVED)
.setName("My custom rule")
- .setDescription("Description")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Description"))
.setDescriptionFormat(RuleDto.Format.MARKDOWN)
.setSeverity(Severity.MAJOR);
db.rules().insert(customRule);
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.sonar.api.rule.Severity.BLOCKER;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.setSystemTags;
import static org.sonar.db.rule.RuleTesting.setTags;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION;
@Test
public void filter_by_rule_description() {
- RuleDefinitionDto rule1 = db.rules().insert(r1 -> r1.setDescription("This is the <bold>best</bold> rule now&for<b>ever</b>"));
+ RuleDefinitionDto rule1 = db.rules()
+ .insert(r1 -> r1.addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("This is the <bold>best</bold> rule now&for<b>ever</b>")));
RuleDefinitionDto rule2 = db.rules().insert(r1 -> r1.setName("Some other stuff"));
indexRules();
@Test
public void filter_by_rule_name_or_descriptions_requires_all_words_to_match_anywhere() {
- RuleDefinitionDto rule1 = db.rules().insert(r1 -> r1.setName("Best rule ever").setDescription("This is a good rule"));
- RuleDefinitionDto rule2 = db.rules().insert(r1 -> r1.setName("Some other stuff").setDescription("Another thing"));
+ RuleDefinitionDto rule1 = db.rules().insert(r1 -> r1.setName("Best rule ever")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("This is a good rule")));
+ RuleDefinitionDto rule2 = db.rules().insert(r1 -> r1.setName("Another thing")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Another thing")));
indexRules();
verify(r -> r.setParam("q", "Best good"), rule1);
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
import static org.sonar.db.rule.RuleTesting.newCustomRule;
import static org.sonar.db.rule.RuleTesting.newTemplateRule;
db.rules().insert(templateRule.getDefinition());
// Custom rule
RuleDefinitionDto customRule = newCustomRule(templateRule.getDefinition())
- .setDescription("<div>line1\nline2</div>")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("<div>line1\nline2</div>"))
.setDescriptionFormat(MARKDOWN);
db.rules().insert(customRule);
doReturn("<div>line1<br/>line2</div>").when(macroInterpreter).interpret("<div>line1\nline2</div>");
.setIsExternal(true)
.setIsAdHoc(true)
.setName("predefined name")
- .setDescription("<div>predefined desc</div>")
+ .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("<div>predefined desc</div>"))
.setSeverity(Severity.BLOCKER)
.setType(RuleType.VULNERABILITY));
RuleMetadataDto metadata = db.rules().insertOrUpdateMetadata(externalRule, m -> m
.setIsExternal(true)
.setIsAdHoc(true)
.setName(null)
- .setDescription(null)
.setDescriptionFormat(null)
.setSeverity((String) null)
.setType(0));
import static org.sonar.api.server.debt.DebtRemediationFunction.Type.LINEAR;
import static org.sonar.api.server.debt.DebtRemediationFunction.Type.LINEAR_OFFSET;
import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES;
+import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection;
import static org.sonar.db.rule.RuleTesting.setSystemTags;
import static org.sonar.db.rule.RuleTesting.setTags;
import static org.sonar.server.rule.ws.UpdateAction.PARAM_KEY;
RuleDefinitionDto customRule = db.rules().insert(
r -> r.setRuleKey(RuleKey.of("java", "MY_CUSTOM")),
r -> r.setName("Old custom"),
- r -> r.setDescription("Old description"),
+ r -> r.addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Old description")),
r -> r.setSeverity(Severity.MINOR),
r -> r.setStatus(RuleStatus.BETA),
r -> r.setTemplateUuid(templateRule.getUuid()),
RuleDefinitionDto customRule = db.rules().insert(
r -> r.setRuleKey(RuleKey.of("java", "MY_CUSTOM")),
r -> r.setName("Old custom"),
- r -> r.setDescription("Old description"),
+ r -> r.addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("Old description")),
r -> r.setTemplateUuid(templateRule.getUuid()),
r -> r.setCreatedAt(PAST),
r -> r.setUpdatedAt(PAST));