aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLéo Geoffroy <99647462+leo-geoffroy-sonarsource@users.noreply.github.com>2022-04-22 14:13:59 +0200
committersonartech <sonartech@sonarsource.com>2022-05-06 20:02:43 +0000
commit6e2ed638eeb353c4048575e9ba16c968455d3142 (patch)
tree8cc600e82076e13a06b8124d8101884711316fe7
parent988512fbbf60d11ec53c2add9a277f4c04c163f8 (diff)
downloadsonarqube-6e2ed638eeb353c4048575e9ba16c968455d3142.tar.gz
sonarqube-6e2ed638eeb353c4048575e9ba16c968455d3142.zip
SONAR-16302 adapt RuleDto, RuleDefinitionDto and introduce RuleSectionDescriptionDto to prepare for multiple section support
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/AdHocRuleCreatorTest.java8
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java38
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDescriptionSectionDto.java96
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDto.java24
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java7
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java29
-rw-r--r--server/sonar-db-dao/src/testFixtures/java/org/sonar/db/rule/RuleTesting.java23
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/rule/DefaultRuleFinder.java16
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java2
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java45
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java45
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java19
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java14
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java45
-rw-r--r--server/sonar-webserver-api/src/main/java/org/sonar/server/rule/CachingRuleFinder.java15
-rw-r--r--server/sonar-webserver-api/src/test/java/org/sonar/server/rule/CachingRuleFinderTest.java3
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/rule/RegisterRules.java43
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/rule/RegisterRulesTest.java28
-rw-r--r--server/sonar-webserver-pushapi/src/test/java/org/sonar/server/qualityprofile/builtin/QualityProfileChangeEventServiceImplTest.java6
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java11
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleUpdater.java5
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java13
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java25
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java5
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java5
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java9
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java7
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java3
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java10
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java6
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java5
31 files changed, 412 insertions, 198 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/AdHocRuleCreatorTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/AdHocRuleCreatorTest.java
index bc0391f9f8e..d3e2524d08d 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/AdHocRuleCreatorTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/AdHocRuleCreatorTest.java
@@ -61,7 +61,7 @@ public class AdHocRuleCreatorTest {
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();
@@ -89,7 +89,7 @@ public class AdHocRuleCreatorTest {
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");
@@ -144,7 +144,7 @@ public class AdHocRuleCreatorTest {
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");
@@ -175,7 +175,7 @@ public class AdHocRuleCreatorTest {
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());
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java
index fcdfe997c2e..1cd974855ff 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java
@@ -21,6 +21,9 @@ package org.sonar.db.rule;
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;
@@ -33,6 +36,7 @@ import org.sonar.api.rules.RuleType;
import org.sonar.db.rule.RuleDto.Scope;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Collections.unmodifiableCollection;
public class RuleDefinitionDto {
@@ -42,10 +46,7 @@ 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
@@ -166,13 +167,32 @@ public class RuleDefinitionDto {
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;
}
@@ -434,7 +454,7 @@ public class RuleDefinitionDto {
"uuid=" + uuid +
", repositoryKey='" + repositoryKey + '\'' +
", ruleKey='" + ruleKey + '\'' +
- ", description='" + description + '\'' +
+ ", ruleDescriptionSections='" + ruleDescriptionSectionDtos + '\'' +
", descriptionFormat=" + descriptionFormat +
", status=" + status +
", name='" + name + '\'' +
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDescriptionSectionDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDescriptionSectionDto.java
new file mode 100644
index 00000000000..bff3a3d30d1
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDescriptionSectionDto.java
@@ -0,0 +1,96 @@
+/*
+ * 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);
+ }
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDto.java
index 28fe1ca75ee..3e518801fa7 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDto.java
@@ -19,6 +19,7 @@
*/
package org.sonar.db.rule;
+import java.util.Collection;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -100,12 +101,27 @@ public class RuleDto {
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;
}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java
index 629418aaa75..fb9efff61ed 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java
@@ -36,6 +36,7 @@ import org.sonar.api.rules.RuleType;
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;
@@ -94,7 +95,8 @@ public class QualityProfileExportDaoTest {
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());
@@ -110,7 +112,8 @@ public class QualityProfileExportDaoTest {
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());
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java
index 41893e0c3e8..438b517a244 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java
@@ -28,6 +28,7 @@ import java.util.List;
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;
@@ -48,15 +49,18 @@ import static com.google.common.collect.Sets.newHashSet;
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);
@@ -244,8 +248,6 @@ public class RuleDaoTest {
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());
@@ -262,6 +264,9 @@ public class RuleDaoTest {
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) {
@@ -427,8 +432,8 @@ public class RuleDaoTest {
.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)
@@ -453,8 +458,6 @@ public class RuleDaoTest {
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");
@@ -475,6 +478,9 @@ public class RuleDaoTest {
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
@@ -485,8 +491,8 @@ public class RuleDaoTest {
.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)
@@ -510,8 +516,6 @@ public class RuleDaoTest {
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");
@@ -532,6 +536,9 @@ public class RuleDaoTest {
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
@@ -798,7 +805,8 @@ public class RuleDaoTest {
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());
@@ -877,7 +885,8 @@ public class RuleDaoTest {
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()));
diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/rule/RuleTesting.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/rule/RuleTesting.java
index b86f5ddb33d..b544afa6379 100644
--- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/rule/RuleTesting.java
+++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/rule/RuleTesting.java
@@ -32,7 +32,6 @@ import org.sonar.api.server.rule.RuleParamType;
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;
@@ -43,6 +42,7 @@ import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
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
@@ -65,13 +65,22 @@ public class RuleTesting {
}
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))
@@ -171,8 +180,8 @@ public class RuleTesting {
.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)
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/DefaultRuleFinder.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/DefaultRuleFinder.java
index c31892506c8..e821838fd17 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/DefaultRuleFinder.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/DefaultRuleFinder.java
@@ -40,7 +40,8 @@ import org.sonar.db.rule.RuleDao;
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.
@@ -135,8 +136,6 @@ public class DefaultRuleFinder implements ServerRuleFinder {
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
@@ -151,14 +150,9 @@ public class DefaultRuleFinder implements ServerRuleFinder {
.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) {
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java
index a9e685e0cd4..b3b27628cb0 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/HotspotRuleDescription.java
@@ -48,7 +48,7 @@ public class HotspotRuleDescription {
}
public static HotspotRuleDescription from(RuleDefinitionDto dto) {
- String description = dto.isCustomRule() ? RuleDescriptionFormatter.getDescriptionAsHtml(dto) : dto.getDescription();
+ String description = RuleDescriptionFormatter.getDescriptionAsHtml(dto);
return from(description);
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java
index 0eeaaa83d9a..2cae26e2695 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java
@@ -19,30 +19,49 @@
*/
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;
}
}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java
index 18982042bd3..12c34c19c62 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/HotspotRuleDescriptionTest.java
@@ -26,17 +26,18 @@ import org.junit.Test;
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);
@@ -47,7 +48,7 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -59,7 +60,7 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -80,7 +81,8 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -91,7 +93,8 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -102,7 +105,8 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -113,7 +117,8 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -124,7 +129,8 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -137,7 +143,8 @@ public class HotspotRuleDescriptionTest {
@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);
@@ -153,18 +160,18 @@ public class HotspotRuleDescriptionTest {
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);
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java
index d0f5d6df339..b50f77deb3e 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java
@@ -21,37 +21,42 @@ package org.sonar.server.rule;
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();
}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
index 9ca8078f54f..d4ae6d45d5b 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
@@ -22,14 +22,11 @@ package org.sonar.server.rule.index;
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;
@@ -66,6 +63,7 @@ import static org.sonar.api.rules.RuleType.BUG;
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;
@@ -216,19 +214,19 @@ public class RuleIndexTest {
// 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
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java
index 6fc13907884..e3362dd71ee 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java
@@ -28,7 +28,6 @@ import java.util.Random;
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;
@@ -41,6 +40,7 @@ import org.sonar.db.DbClient;
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;
@@ -55,6 +55,7 @@ import static java.util.stream.Collectors.joining;
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;
@@ -62,11 +63,14 @@ import static org.sonar.server.security.SecurityStandards.SQ_CATEGORY_KEYS_ORDER
@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
@@ -83,8 +87,8 @@ public class RuleIndexerTest {
.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)
@@ -127,7 +131,8 @@ public class RuleIndexerTest {
@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();
@@ -143,7 +148,7 @@ public class RuleIndexerTest {
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);
@@ -174,11 +179,9 @@ public class RuleIndexerTest {
}
@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);
@@ -188,19 +191,11 @@ public class RuleIndexerTest {
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);
@@ -214,9 +209,9 @@ public class RuleIndexerTest {
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);
@@ -230,10 +225,10 @@ public class RuleIndexerTest {
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);
@@ -247,9 +242,9 @@ public class RuleIndexerTest {
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);
diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/rule/CachingRuleFinder.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/rule/CachingRuleFinder.java
index 17199eb9ce1..43f6fdb03c6 100644
--- a/server/sonar-webserver-api/src/main/java/org/sonar/server/rule/CachingRuleFinder.java
+++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/rule/CachingRuleFinder.java
@@ -41,9 +41,7 @@ import org.sonar.core.util.stream.MoreCollectors;
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;
@@ -147,8 +145,6 @@ public class CachingRuleFinder implements ServerRuleFinder {
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
@@ -163,14 +159,9 @@ public class CachingRuleFinder implements ServerRuleFinder {
.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) {
diff --git a/server/sonar-webserver-api/src/test/java/org/sonar/server/rule/CachingRuleFinderTest.java b/server/sonar-webserver-api/src/test/java/org/sonar/server/rule/CachingRuleFinderTest.java
index 0d37e1221fe..cd2c2235981 100644
--- a/server/sonar-webserver-api/src/test/java/org/sonar/server/rule/CachingRuleFinderTest.java
+++ b/server/sonar-webserver-api/src/test/java/org/sonar/server/rule/CachingRuleFinderTest.java
@@ -46,6 +46,7 @@ import static org.mockito.Mockito.mock;
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
@@ -422,7 +423,7 @@ public class CachingRuleFinderTest {
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();
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/RegisterRules.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/RegisterRules.java
index 5309cbb697f..fb4e08ec15a 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/RegisterRules.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/RegisterRules.java
@@ -75,9 +75,11 @@ import static java.lang.String.format;
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
@@ -261,10 +263,10 @@ public class RegisterRules implements Startable {
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);
}
@@ -398,13 +400,14 @@ public class RegisterRules implements Startable {
.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());
@@ -481,20 +484,30 @@ public class RegisterRules implements Startable {
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();
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/RegisterRulesTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
index 6c7f40dc89f..e9cbb4ebbc7 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
@@ -88,6 +88,7 @@ import static org.sonar.api.server.rule.RulesDefinition.NewRepository;
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 {
@@ -124,7 +125,6 @@ public class RegisterRulesTest {
private ActiveRuleIndexer activeRuleIndexer;
private RuleIndex ruleIndex;
-
@Before
public void before() {
ruleIndexer = new RuleIndexer(es.client(), dbClient);
@@ -140,7 +140,7 @@ public class RegisterRulesTest {
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");
@@ -159,7 +159,7 @@ public class RegisterRulesTest {
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());
@@ -188,7 +188,7 @@ public class RegisterRulesTest {
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");
@@ -207,7 +207,7 @@ public class RegisterRulesTest {
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());
@@ -335,7 +335,7 @@ public class RegisterRulesTest {
// 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");
@@ -449,7 +449,7 @@ public class RegisterRulesTest {
// 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();
@@ -528,7 +528,7 @@ public class RegisterRulesTest {
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());
@@ -570,7 +570,7 @@ public class RegisterRulesTest {
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());
@@ -610,7 +610,7 @@ public class RegisterRulesTest {
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());
@@ -618,7 +618,7 @@ public class RegisterRulesTest {
@DataProvider
public static Object[][] allRenamingCases() {
- return new Object[][]{
+ return new Object[][] {
{"repo1", "rule1", "repo1", "rule2"},
{"repo1", "rule1", "repo2", "rule1"},
{"repo1", "rule1", "repo2", "rule2"},
@@ -688,7 +688,7 @@ public class RegisterRulesTest {
// 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();
@@ -702,7 +702,7 @@ public class RegisterRulesTest {
NewRepository repo = context.createExternalRepository("fake", rule.getLanguage());
repo.createRule(rule.getRuleKey())
.setName(rule.getName())
- .setHtmlDescription(rule.getDescription());
+ .setHtmlDescription(rule.getDefaultRuleDescriptionSectionDto().getDescription());
repo.done();
});
@@ -836,7 +836,7 @@ public class RegisterRulesTest {
.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();
diff --git a/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/qualityprofile/builtin/QualityProfileChangeEventServiceImplTest.java b/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/qualityprofile/builtin/QualityProfileChangeEventServiceImplTest.java
index 1e12fda35ca..77b5db39783 100644
--- a/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/qualityprofile/builtin/QualityProfileChangeEventServiceImplTest.java
+++ b/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/qualityprofile/builtin/QualityProfileChangeEventServiceImplTest.java
@@ -47,7 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
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;
@@ -73,8 +73,8 @@ public class QualityProfileChangeEventServiceImplTest {
.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);
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java
index ed07ddfa98c..e67c9d22a4d 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java
@@ -39,6 +39,7 @@ import org.sonar.core.util.UuidFactory;
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;
@@ -50,6 +51,7 @@ import org.sonar.server.util.TypeValidations;
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
@@ -189,8 +191,6 @@ public class RuleCreator {
.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())
@@ -206,6 +206,13 @@ public class RuleCreator {
.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();
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleUpdater.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleUpdater.java
index 09dc0e58de0..78e4aebf313 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleUpdater.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleUpdater.java
@@ -43,6 +43,7 @@ import org.sonar.db.qualityprofile.ActiveRuleDto;
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;
@@ -53,6 +54,7 @@ import static com.google.common.base.Strings.isNullOrEmpty;
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 {
@@ -136,8 +138,9 @@ 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) {
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java
index 867e323cabd..4b4afd81a9a 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java
@@ -34,6 +34,7 @@ import org.sonar.api.server.debt.DebtRemediationFunction;
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;
@@ -47,6 +48,7 @@ import org.sonarqube.ws.Common;
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;
@@ -329,12 +331,19 @@ public class RuleMapper {
}
}
- 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) {
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java
index f571e58bbd9..fd9c031e807 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java
@@ -30,6 +30,7 @@ import java.util.List;
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;
@@ -89,6 +90,7 @@ import static org.mockito.Mockito.verify;
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)
@@ -431,9 +433,9 @@ public class ShowActionTest {
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);
@@ -452,7 +454,7 @@ public class ShowActionTest {
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();
@@ -1024,11 +1026,18 @@ public class ShowActionTest {
}
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>> {
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
index c1c4ba82695..cfc87dc6e5f 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
@@ -100,6 +100,7 @@ import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
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;
@@ -1441,7 +1442,7 @@ public class SearchActionTest {
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;
@@ -1450,7 +1451,7 @@ public class SearchActionTest {
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());
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java
index 800c5623d59..a4faa701fa1 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java
@@ -54,6 +54,7 @@ import static org.mockito.ArgumentMatchers.any;
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 {
@@ -141,7 +142,7 @@ 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()));
@@ -163,7 +164,7 @@ public class QProfileBackuperImplTest {
"<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>" +
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java
index dd98bd59223..63627fd5556 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java
@@ -55,6 +55,7 @@ import org.sonar.server.rule.index.RuleQuery;
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;
@@ -95,7 +96,7 @@ public class RuleCreatorTest {
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");
@@ -288,7 +289,7 @@ public class RuleCreatorTest {
.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());
@@ -310,7 +311,7 @@ public class RuleCreatorTest {
// 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);
@@ -328,7 +329,7 @@ public class RuleCreatorTest {
.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.*"));
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java
index 5670c5d1489..0c2fbae7dc7 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleUpdaterTest.java
@@ -57,6 +57,7 @@ import org.sonar.server.tester.UserSessionRule;
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;
@@ -341,7 +342,7 @@ public class RuleUpdaterTest {
// 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();
@@ -364,7 +365,7 @@ public class RuleUpdaterTest {
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);
@@ -389,7 +390,7 @@ public class RuleUpdaterTest {
// 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();
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java
index f81c42ce1d1..dca7895a189 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java
@@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock;
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;
@@ -141,7 +142,7 @@ public class CreateActionTest {
.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);
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
index 81e08380c3d..3b6db659ba2 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
@@ -79,6 +79,7 @@ import static org.mockito.ArgumentMatchers.anyString;
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;
@@ -232,7 +233,8 @@ public class SearchActionTest {
@Test
public void filter_by_rule_description() {
- RuleDefinitionDto rule1 = db.rules().insert(r1 -> r1.setDescription("This is the <bold>best</bold> rule now&amp;for<b>ever</b>"));
+ RuleDefinitionDto rule1 = db.rules()
+ .insert(r1 -> r1.addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection("This is the <bold>best</bold> rule now&amp;for<b>ever</b>")));
RuleDefinitionDto rule2 = db.rules().insert(r1 -> r1.setName("Some other stuff"));
indexRules();
@@ -243,8 +245,10 @@ public class SearchActionTest {
@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);
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java
index 6a0400dd5d3..41ba8fab653 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java
@@ -50,6 +50,7 @@ import static org.mockito.ArgumentMatchers.anyString;
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;
@@ -284,7 +285,7 @@ public class ShowActionTest {
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("&lt;div&gt;line1<br/>line2&lt;/div&gt;").when(macroInterpreter).interpret("<div>line1\nline2</div>");
@@ -342,7 +343,7 @@ public class ShowActionTest {
.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
@@ -370,7 +371,6 @@ public class ShowActionTest {
.setIsExternal(true)
.setIsAdHoc(true)
.setName(null)
- .setDescription(null)
.setDescriptionFormat(null)
.setSeverity((String) null)
.setType(0));
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java
index 60f00c186e0..8be2f583b11 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java
@@ -53,6 +53,7 @@ import static org.mockito.Mockito.mock;
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;
@@ -107,7 +108,7 @@ public class UpdateActionTest {
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()),
@@ -243,7 +244,7 @@ public class UpdateActionTest {
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));