diff options
Diffstat (limited to 'server/sonar-db-dao')
6 files changed, 185 insertions, 32 deletions
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) |