group=org.sonarsource.sonarqube
version=10.2
-pluginApiVersion=10.0.0.790
+pluginApiVersion=10.1.0.809
description=Open source platform for continuous inspection of code quality
projectTitle=SonarQube
org.gradle.jvmargs=-Xmx2048m
private static void insertRuleDefaultImpacts(RuleDto ruleDto, RuleMapper mapper) {
ruleDto.getDefaultImpacts()
- .forEach(section -> mapper.insertRuleDefaultImpact(ruleDto.getUuid(), section));
+ .forEach(impact -> mapper.insertRuleDefaultImpact(ruleDto.getUuid(), impact));
}
public void scrollIndexingRuleExtensionsByIds(DbSession dbSession, Collection<String> ruleExtensionIds, Consumer<RuleExtensionForIndexingDto> consumer) {
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.db.issue.ImpactDto;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
import static java.util.Optional.ofNullable;
-import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.sonar.db.rule.RuleDescriptionSectionDto.DEFAULT_KEY;
public class RuleDto {
return type;
}
+ public RuleType getEnumType() {
+ return RuleType.valueOf(type);
+ }
+
public RuleDto setType(int type) {
this.type = type;
return this;
return strings == null || strings.isEmpty() ? null : String.join(",", strings);
}
- public static RuleDto from(RulesDefinition.Rule ruleDef, Set<RuleDescriptionSectionDto> ruleDescriptionSectionDtos, String uuid,
- long now) {
- RuleDto ruleDto = new RuleDto()
- .setUuid(uuid)
- .setRuleKey(RuleKey.of(ruleDef.repository().key(), ruleDef.key()))
- .setPluginKey(ruleDef.pluginKey())
- .setIsTemplate(ruleDef.template())
- .setConfigKey(ruleDef.internalKey())
- .setLanguage(ruleDef.repository().language())
- .setName(ruleDef.name())
- .setSeverity(ruleDef.severity())
- .setStatus(ruleDef.status())
- .setGapDescription(ruleDef.gapDescription())
- .setSystemTags(ruleDef.tags())
- .setSecurityStandards(ruleDef.securityStandards())
- .setType(RuleType.valueOf(ruleDef.type().name()))
- .setScope(Scope.valueOf(ruleDef.scope().name()))
- .setIsExternal(ruleDef.repository().isExternal())
- .setIsAdHoc(false)
- .setCreatedAt(now)
- .setUpdatedAt(now)
- .setCleanCodeAttribute(ruleDef.cleanCodeAttribute() != null ? ruleDef.cleanCodeAttribute() : CleanCodeAttribute.defaultCleanCodeAttribute())
- .setEducationPrinciples(ruleDef.educationPrincipleKeys());
-
- if (isNotEmpty(ruleDef.htmlDescription())) {
- ruleDto.setDescriptionFormat(Format.HTML);
- } else if (isNotEmpty(ruleDef.markdownDescription())) {
- ruleDto.setDescriptionFormat(Format.MARKDOWN);
- }
-
- ruleDescriptionSectionDtos.forEach(ruleDto::addRuleDescriptionSectionDto);
-
- DebtRemediationFunction debtRemediationFunction = ruleDef.debtRemediationFunction();
- if (debtRemediationFunction != null) {
- ruleDto.setDefRemediationFunction(debtRemediationFunction.type().name());
- ruleDto.setDefRemediationGapMultiplier(debtRemediationFunction.gapMultiplier());
- ruleDto.setDefRemediationBaseEffort(debtRemediationFunction.baseEffort());
- ruleDto.setGapDescription(ruleDef.gapDescription());
- }
-
- return ruleDto;
- }
-
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RuleDto)) {
.hasMessage(String.format(ERROR_MESSAGE_SECTION_ALREADY_EXISTS, SECTION_KEY, contextKey));
}
- @Test
- public void from_whenRuleDefinitionDoesntHaveCleanCodeAttribute_shouldAlwaysSetCleanCodeAttribute() {
- RulesDefinition.Rule ruleDef = getDefaultRule();
-
- RuleDto newRuleDto = RuleDto.from(ruleDef, Set.of(), "uuid", Long.MAX_VALUE);
-
- assertThat(newRuleDto.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CONVENTIONAL);
- }
-
- @Test
- public void from_whenRuleDefinitionDoesHaveCleanCodeAttribute_shouldReturnThisAttribute() {
- RulesDefinition.Rule ruleDef = getDefaultRule(CleanCodeAttribute.TESTED);
-
- RuleDto newRuleDto = RuleDto.from(ruleDef, Set.of(), "uuid", Long.MAX_VALUE);
-
- assertThat(newRuleDto.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.TESTED);
- }
-
@Test
public void addDefaultImpact_whenSoftwareQualityAlreadyDefined_shouldThrowISE() {
RuleDto dto = new RuleDto();
.containsExactlyInAnyOrder(
tuple(SoftwareQuality.MAINTAINABILITY, Severity.HIGH),
tuple(SoftwareQuality.SECURITY, Severity.LOW));
+ }
+
+ @Test
+ public void getEnumType_shouldReturnCorrectValue() {
+ RuleDto ruleDto = new RuleDto();
+ ruleDto.setType(RuleType.CODE_SMELL);
+
+ RuleType enumType = ruleDto.getEnumType();
+ assertThat(enumType).isEqualTo(RuleType.CODE_SMELL);
}
@NotNull
.setSoftwareQuality(softwareQuality)
.setSeverity(severity);
}
- private static RulesDefinition.Rule getDefaultRule(@Nullable CleanCodeAttribute attribute) {
- RulesDefinition.Rule ruleDef = mock(RulesDefinition.Rule.class);
- RulesDefinition.Repository repository = mock(RulesDefinition.Repository.class);
- when(ruleDef.repository()).thenReturn(repository);
-
- when(ruleDef.key()).thenReturn("key");
- when(repository.key()).thenReturn("repoKey");
- when(ruleDef.type()).thenReturn(RuleType.CODE_SMELL);
- when(ruleDef.scope()).thenReturn(RuleScope.TEST);
- when(ruleDef.cleanCodeAttribute()).thenReturn(attribute);
- return ruleDef;
- }
- private static RulesDefinition.Rule getDefaultRule() {
- return getDefaultRule(null);
- }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.rule.registration;
+
+import java.util.stream.Collectors;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.CleanCodeAttribute;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.issue.ImpactDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.rule.RuleDescriptionSectionsGeneratorResolver;
+
+import static org.apache.commons.lang.StringUtils.isNotEmpty;
+
+public class NewRuleCreator {
+
+ private final DbClient dbClient;
+ private final RuleDescriptionSectionsGeneratorResolver ruleDescriptionSectionsGeneratorResolver;
+ private final UuidFactory uuidFactory;
+ private final System2 system2;
+
+ public NewRuleCreator(DbClient dbClient, RuleDescriptionSectionsGeneratorResolver ruleDescriptionSectionsGeneratorResolver, UuidFactory uuidFactory, System2 system2) {
+ this.dbClient = dbClient;
+ this.ruleDescriptionSectionsGeneratorResolver = ruleDescriptionSectionsGeneratorResolver;
+ this.uuidFactory = uuidFactory;
+ this.system2 = system2;
+ }
+
+ RuleDto createNewRule(RulesRegistrationContext context, RulesDefinition.Rule ruleDef, DbSession session) {
+ RuleDto newRule = createRuleWithSimpleFields(ruleDef, uuidFactory.create(), system2.now());
+
+ newRule.replaceAllDefaultImpacts(ruleDef.defaultImpacts().entrySet()
+ .stream()
+ .map(e -> new ImpactDto().setUuid(uuidFactory.create()).setSoftwareQuality(e.getKey()).setSeverity(e.getValue()))
+ .collect(Collectors.toSet()));
+
+ ruleDescriptionSectionsGeneratorResolver.generateFor(ruleDef).forEach(newRule::addRuleDescriptionSectionDto);
+
+ dbClient.ruleDao().insert(session, newRule);
+ context.created(newRule);
+ return newRule;
+ }
+
+ RuleDto createRuleWithSimpleFields(RulesDefinition.Rule ruleDef, String uuid, long now) {
+ RuleDto ruleDto = new RuleDto()
+ .setUuid(uuid)
+ .setRuleKey(RuleKey.of(ruleDef.repository().key(), ruleDef.key()))
+ .setPluginKey(ruleDef.pluginKey())
+ .setIsTemplate(ruleDef.template())
+ .setConfigKey(ruleDef.internalKey())
+ .setLanguage(ruleDef.repository().language())
+ .setName(ruleDef.name())
+ .setSeverity(ruleDef.severity())
+ .setStatus(ruleDef.status())
+ .setGapDescription(ruleDef.gapDescription())
+ .setSystemTags(ruleDef.tags())
+ .setSecurityStandards(ruleDef.securityStandards())
+ .setType(RuleType.valueOf(ruleDef.type().name()))
+ .setScope(RuleDto.Scope.valueOf(ruleDef.scope().name()))
+ .setIsExternal(ruleDef.repository().isExternal())
+ .setIsAdHoc(false)
+ .setCreatedAt(now)
+ .setUpdatedAt(now)
+ .setCleanCodeAttribute(ruleDef.cleanCodeAttribute() != null ? ruleDef.cleanCodeAttribute() : CleanCodeAttribute.defaultCleanCodeAttribute())
+ .setEducationPrinciples(ruleDef.educationPrincipleKeys());
+
+ if (isNotEmpty(ruleDef.htmlDescription())) {
+ ruleDto.setDescriptionFormat(RuleDto.Format.HTML);
+ } else if (isNotEmpty(ruleDef.markdownDescription())) {
+ ruleDto.setDescriptionFormat(RuleDto.Format.MARKDOWN);
+ }
+
+ DebtRemediationFunction debtRemediationFunction = ruleDef.debtRemediationFunction();
+ if (debtRemediationFunction != null) {
+ ruleDto.setDefRemediationFunction(debtRemediationFunction.type().name());
+ ruleDto.setDefRemediationGapMultiplier(debtRemediationFunction.gapMultiplier());
+ ruleDto.setDefRemediationBaseEffort(debtRemediationFunction.baseEffort());
+ ruleDto.setGapDescription(ruleDef.gapDescription());
+ }
+
+ return ruleDto;
+ }
+}
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import javax.annotation.Nonnull;
import org.sonar.api.Startable;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.qualityprofile.QProfileRules;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.RuleDefinitionsLoader;
-import org.sonar.server.rule.RuleDescriptionSectionsGeneratorResolver;
import org.sonar.server.rule.WebServerRuleFinder;
import org.sonar.server.rule.index.RuleIndexer;
private final Languages languages;
private final System2 system2;
private final WebServerRuleFinder webServerRuleFinder;
- private final UuidFactory uuidFactory;
private final MetadataIndex metadataIndex;
- private final RuleDescriptionSectionsGeneratorResolver ruleDescriptionSectionsGeneratorResolver;
private final RulesKeyVerifier rulesKeyVerifier;
private final StartupRuleUpdater startupRuleUpdater;
+ private final NewRuleCreator newRuleCreator;
public RulesRegistrant(RuleDefinitionsLoader defLoader, QProfileRules qProfileRules, DbClient dbClient, RuleIndexer ruleIndexer,
- ActiveRuleIndexer activeRuleIndexer, Languages languages, System2 system2,
- WebServerRuleFinder webServerRuleFinder, UuidFactory uuidFactory, MetadataIndex metadataIndex,
- RuleDescriptionSectionsGeneratorResolver ruleDescriptionSectionsGeneratorResolver,
- RulesKeyVerifier rulesKeyVerifier, StartupRuleUpdater startupRuleUpdater) {
+ ActiveRuleIndexer activeRuleIndexer, Languages languages, System2 system2, WebServerRuleFinder webServerRuleFinder,
+ MetadataIndex metadataIndex, RulesKeyVerifier rulesKeyVerifier, StartupRuleUpdater startupRuleUpdater,
+ NewRuleCreator newRuleCreator) {
this.defLoader = defLoader;
this.qProfileRules = qProfileRules;
this.dbClient = dbClient;
this.languages = languages;
this.system2 = system2;
this.webServerRuleFinder = webServerRuleFinder;
- this.uuidFactory = uuidFactory;
this.metadataIndex = metadataIndex;
- this.ruleDescriptionSectionsGeneratorResolver = ruleDescriptionSectionsGeneratorResolver;
this.rulesKeyVerifier = rulesKeyVerifier;
this.startupRuleUpdater = startupRuleUpdater;
+ this.newRuleCreator = newRuleCreator;
}
@Override
for (RulesDefinition.Rule ruleDef : ruleDefs) {
RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key());
- RuleDto ruleDto = findOrCreateRuleDto(context, session, ruleDef);
+ RuleDto ruleDto = context.getDbRuleFor(ruleDef).orElseGet(() -> newRuleCreator.createNewRule(context, ruleDef, session));
dtos.put(ruleDef, ruleDto);
// we must detect renaming __before__ we modify the DTO
ruleDto.setRuleKey(ruleKey);
}
- if (startupRuleUpdater.findChangesAndUpdateRule(ruleDef, ruleDto)) {
+ if (!context.isCreated(ruleDto) && startupRuleUpdater.findChangesAndUpdateRule(ruleDef, ruleDto)) {
context.updated(ruleDto);
}
}
}
- @Nonnull
- private RuleDto findOrCreateRuleDto(RulesRegistrationContext context, DbSession session, RulesDefinition.Rule ruleDef) {
- return context.getDbRuleFor(ruleDef)
- .orElseGet(() -> {
- RuleDto newRule = RuleDto.from(ruleDef, ruleDescriptionSectionsGeneratorResolver.generateFor(ruleDef), uuidFactory.create(), system2.now());
- dbClient.ruleDao().insert(session, newRule);
- context.created(newRule);
- return newRule;
- });
- }
-
private void processRemainingDbRules(RulesRegistrationContext recorder, DbSession dbSession) {
// custom rules check status of template, so they must be processed at the end
List<RuleDto> customRules = new ArrayList<>();
private static Set<String> getExistingAndRenamedRepositories(RulesRegistrationContext recorder, Collection<RulesDefinition.Repository> context) {
return Stream.concat(
- context.stream().map(RulesDefinition.ExtendedRepository::key),
- recorder.getRenamed().map(Map.Entry::getValue).map(RuleKey::repository))
+ context.stream().map(RulesDefinition.ExtendedRepository::key),
+ recorder.getRenamed().map(Map.Entry::getValue).map(RuleKey::repository))
.collect(Collectors.toSet());
}
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.issue.impact.Severity;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.issue.ImpactDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.rule.DeprecatedRuleKeyDto;
changed = true;
}
changed |= mergeCleanCodeAttribute(def, dto);
- changed |= mergeImpacts(def, dto);
+ changed |= mergeImpacts(def, dto, uuidFactory);
if (dto.isAdHoc()) {
dto.setIsAdHoc(false);
changed = true;
return changed;
}
- private static boolean mergeImpacts(RulesDefinition.Rule def, RuleDto dto) {
- boolean changed = false;
- // TODO when DTOs for impacts are ready
- return changed;
- }
-
private static boolean mergeCleanCodeAttribute(RulesDefinition.Rule def, RuleDto dto) {
boolean changed = false;
if (!Objects.equals(dto.getCleanCodeAttribute(), def.cleanCodeAttribute()) && (def.cleanCodeAttribute() != null)) {
return changed;
}
+ boolean mergeImpacts(RulesDefinition.Rule def, RuleDto dto, UuidFactory uuidFactory) {
+ if (dto.getEnumType() == RuleType.SECURITY_HOTSPOT) {
+ return false;
+ }
+
+ Map<SoftwareQuality, Severity> impactsFromPlugin = def.defaultImpacts();
+ Map<SoftwareQuality, Severity> impactsFromDb = dto.getDefaultImpacts().stream().collect(Collectors.toMap(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity));
+
+ if (impactsFromPlugin.isEmpty()) {
+ throw new IllegalStateException("There should be at least one impact defined for the rule " + def.key());
+ }
+
+ if (!Objects.equals(impactsFromDb, impactsFromPlugin)) {
+ dto.replaceAllDefaultImpacts(impactsFromPlugin.entrySet()
+ .stream()
+ .map(e -> new ImpactDto().setUuid(uuidFactory.create()).setSoftwareQuality(e.getKey()).setSeverity(e.getValue()))
+ .collect(Collectors.toSet()));
+ return true;
+ }
+
+ return false;
+ }
+
private static boolean mergeEducationPrinciples(RulesDefinition.Rule ruleDef, RuleDto dto) {
boolean changed = false;
if (dto.getEducationPrinciples().size() != ruleDef.educationPrincipleKeys().size() ||
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.rule.registration;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.issue.impact.Severity;
+import org.sonar.api.issue.impact.SoftwareQuality;
+import org.sonar.api.rule.RuleScope;
+import org.sonar.api.rules.CleanCodeAttribute;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.DbClient;
+import org.sonar.db.issue.ImpactDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.rule.RuleDescriptionSectionsGeneratorResolver;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.groups.Tuple.tuple;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.rule.Severity.MAJOR;
+
+public class NewRuleCreatorTest {
+
+ private final DbClient dbClient = mock();
+ private final RuleDescriptionSectionsGeneratorResolver ruleDescriptionSectionsGeneratorResolver = mock();
+ private final UuidFactory uuidFactory = mock();
+ private final System2 system2 = mock();
+ private final RulesRegistrationContext context = mock();
+
+ private final NewRuleCreator underTest = new NewRuleCreator(dbClient, ruleDescriptionSectionsGeneratorResolver, uuidFactory, system2);
+
+ @Before
+ public void before() {
+ when(dbClient.ruleDao()).thenReturn(mock());
+ }
+
+ @Test
+ public void from_whenRuleDefinitionDoesntHaveCleanCodeAttribute_shouldAlwaysSetCleanCodeAttribute() {
+ RulesDefinition.Rule ruleDef = getDefaultRule();
+
+ RuleDto newRuleDto = underTest.createNewRule(context, ruleDef, mock());
+
+ assertThat(newRuleDto.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CONVENTIONAL);
+ }
+
+ @Test
+ public void from_whenRuleDefinitionDoesHaveCleanCodeAttribute_shouldReturnThisAttribute() {
+ RulesDefinition.Rule ruleDef = getDefaultRule(CleanCodeAttribute.TESTED);
+
+ RuleDto newRuleDto = underTest.createNewRule(context, ruleDef, mock());
+
+ assertThat(newRuleDto.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.TESTED);
+ }
+
+ @Test
+ public void createNewRule_whenImpactDefined_shouldReturnThisImpact() {
+ RulesDefinition.Rule ruleDef = getDefaultRule();
+ Map<SoftwareQuality, Severity> singleImpact = new HashMap<>();
+ singleImpact.put(SoftwareQuality.RELIABILITY, Severity.LOW);
+ when(ruleDef.defaultImpacts()).thenReturn(singleImpact);
+
+ RuleDto newRuleDto = underTest.createNewRule(context, ruleDef, mock());
+
+ assertThat(newRuleDto.getDefaultImpacts()).extracting(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity)
+ .containsOnly(tuple(SoftwareQuality.RELIABILITY, Severity.LOW));
+ }
+
+ private static RulesDefinition.Rule getDefaultRule(@Nullable CleanCodeAttribute attribute) {
+ RulesDefinition.Rule ruleDef = mock(RulesDefinition.Rule.class);
+ RulesDefinition.Repository repository = mock(RulesDefinition.Repository.class);
+ when(ruleDef.repository()).thenReturn(repository);
+
+ when(ruleDef.key()).thenReturn("key");
+ when(repository.key()).thenReturn("repoKey");
+ when(ruleDef.type()).thenReturn(RuleType.CODE_SMELL);
+ when(ruleDef.scope()).thenReturn(RuleScope.TEST);
+ when(ruleDef.cleanCodeAttribute()).thenReturn(attribute);
+ when(ruleDef.severity()).thenReturn(MAJOR);
+ when(ruleDef.defaultImpacts()).thenReturn(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.LOW));
+ return ruleDef;
+ }
+
+ private static RulesDefinition.Rule getDefaultRule() {
+ return getDefaultRule(null);
+ }
+}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sonar.api.impl.utils.TestSystem2;
+import org.sonar.api.issue.impact.Severity;
+import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.issue.ImpactDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.QProfileChangeDto;
import org.sonar.db.qualityprofile.QProfileChangeQuery;
import static org.sonar.api.rule.RuleStatus.READY;
import static org.sonar.api.rule.RuleStatus.REMOVED;
import static org.sonar.api.rule.Severity.BLOCKER;
+import static org.sonar.api.rule.Severity.CRITICAL;
import static org.sonar.api.rule.Severity.INFO;
import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
private final RulesKeyVerifier rulesKeyVerifier = new RulesKeyVerifier();
private final StartupRuleUpdater startupRuleUpdater = new StartupRuleUpdater(dbClient, system, uuidFactory, resolver);
+ private final NewRuleCreator newRuleCreator = new NewRuleCreator(dbClient, resolver, uuidFactory, system);
@Before
public void before() {
// verify db
assertThat(dbClient.ruleDao().selectAll(db.getSession())).hasSize(3);
RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RULE_KEY1);
- verifyRule(rule1);
+ verifyRule(rule1, RuleType.CODE_SMELL, BLOCKER);
assertThat(rule1.isExternal()).isFalse();
assertThat(rule1.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CONVENTIONAL);
+ assertThat(rule1.getDefaultImpacts()).extracting(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity).containsOnly(tuple(SoftwareQuality.RELIABILITY, Severity.HIGH));
assertThat(rule1.getDefRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET.name());
assertThat(rule1.getDefRemediationGapMultiplier()).isEqualTo("5d");
assertThat(rule1.getDefRemediationBaseEffort()).isEqualTo("10h");
// verify index
RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), RULE_KEY2);
assertThat(rule2.getCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.EFFICIENT);
+ assertThat(rule2.getDefaultImpacts()).extracting(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity).containsOnly(tuple(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM));
assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getUuids()).containsOnly(rule1.getUuid(), rule2.getUuid(), hotspotRule.getUuid());
verifyIndicesMarkedAsInitialized();
// verify db
assertThat(dbClient.ruleDao().selectAll(db.getSession())).hasSize(2);
RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), EXTERNAL_RULE_KEY1);
- verifyRule(rule1);
+ verifyRule(rule1, RuleType.CODE_SMELL, BLOCKER);
assertThat(rule1.isExternal()).isTrue();
assertThat(rule1.getDefRemediationFunction()).isNull();
assertThat(rule1.getDefRemediationGapMultiplier()).isNull();
verifyHotspot(hotspotRule);
}
- private void verifyRule(RuleDto rule) {
+ private void verifyRule(RuleDto rule, RuleType type, String expectedSeverity) {
assertThat(rule.getName()).isEqualTo("One");
assertThat(rule.getDefaultRuleDescriptionSection().getContent()).isEqualTo("Description of One");
- assertThat(rule.getSeverityString()).isEqualTo(BLOCKER);
+ assertThat(rule.getSeverityString()).isEqualTo(expectedSeverity);
assertThat(rule.getTags()).isEmpty();
assertThat(rule.getSystemTags()).containsOnly("tag1", "tag2", "tag3");
assertThat(rule.getConfigKey()).isEqualTo("config1");
assertThat(rule.getCreatedAt()).isEqualTo(DATE1.getTime());
assertThat(rule.getScope()).isEqualTo(Scope.ALL);
assertThat(rule.getUpdatedAt()).isEqualTo(DATE1.getTime());
- assertThat(rule.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
+ assertThat(rule.getType()).isEqualTo(type.getDbConstant());
assertThat(rule.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY);
assertThat(rule.isAdHoc()).isFalse();
assertThat(rule.getEducationPrinciples()).containsOnly("concept1", "concept2", "concept3");
.setRuleKey("rule1")
.setRepositoryKey("findbugs")
.setName("Rule One")
+ .setType(RuleType.CODE_SMELL)
.setScope(Scope.ALL)
.addRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "Rule one description"))
.setDescriptionFormat(RuleDto.Format.HTML)
when(languages.get(any())).thenReturn(mock(Language.class));
reset(webServerRuleFinder);
- RulesRegistrant task = new RulesRegistrant(loader, qProfileRules, dbClient, ruleIndexer, activeRuleIndexer, languages, system, webServerRuleFinder, uuidFactory, metadataIndex,
- resolver, rulesKeyVerifier, startupRuleUpdater);
+ RulesRegistrant task = new RulesRegistrant(loader, qProfileRules, dbClient, ruleIndexer, activeRuleIndexer, languages, system, webServerRuleFinder, metadataIndex,
+ rulesKeyVerifier, startupRuleUpdater, newRuleCreator);
task.start();
// Execute a commit to refresh session state as the task is using its own session
db.getSession().commit();
.setType(RuleType.CODE_SMELL)
.setStatus(RuleStatus.BETA)
.setGapDescription("java.S115.effortToFix")
- .addEducationPrincipleKeys("concept1", "concept2", "concept3");
+ .addEducationPrincipleKeys("concept1", "concept2", "concept3")
+ .addDefaultImpact(SoftwareQuality.RELIABILITY, Severity.HIGH);
rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("5d", "10h"));
rule1.createParam("param1").setDescription("parameter one").setDefaultValue("default1");
import org.sonar.server.rule.AdvancedRuleDescriptionSectionsGenerator;
import org.sonar.server.rule.LegacyHotspotRuleDescriptionSectionsGenerator;
import org.sonar.server.rule.LegacyIssueRuleDescriptionSectionsGenerator;
+import org.sonar.server.rule.registration.NewRuleCreator;
import org.sonar.server.rule.registration.RulesKeyVerifier;
import org.sonar.server.rule.registration.RulesRegistrant;
import org.sonar.server.rule.RuleDescriptionSectionsGeneratorResolver;
LegacyHotspotRuleDescriptionSectionsGenerator.class,
LegacyIssueRuleDescriptionSectionsGenerator.class,
RulesRegistrant.class,
+ NewRuleCreator.class,
RulesKeyVerifier.class,
StartupRuleUpdater.class,
BuiltInQProfileLoader.class);