aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server/src
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-03-06 20:11:32 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-03-06 20:11:32 +0100
commit35ff7a07d5d86e2c0e6f9ce83645d1d6f34fc33a (patch)
treee9480c3bdefc4012e98c415685cd9323dd62a2a3 /sonar-server/src
parent0bfbecd3d0562f62e5e61c42579b2dce45d33a2c (diff)
downloadsonarqube-35ff7a07d5d86e2c0e6f9ce83645d1d6f34fc33a.tar.gz
sonarqube-35ff7a07d5d86e2c0e6f9ce83645d1d6f34fc33a.zip
SONAR-5056 Synchronize rule debt definitions from plugin debt models
Diffstat (limited to 'sonar-server/src')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java9
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java77
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java99
-rw-r--r--sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java45
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java95
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java20
-rw-r--r--sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java41
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml22
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml20
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml17
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml2
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml2
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml22
13 files changed, 366 insertions, 105 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index 4a4f73cb465..d08ff9f9a66 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -63,10 +63,7 @@ import org.sonar.core.qualitygate.db.QualityGateConditionDao;
import org.sonar.core.qualitygate.db.QualityGateDao;
import org.sonar.core.resource.DefaultResourcePermissions;
import org.sonar.core.rule.DefaultRuleFinder;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
-import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
-import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer;
-import org.sonar.core.technicaldebt.TechnicalDebtXMLImporter;
+import org.sonar.core.technicaldebt.*;
import org.sonar.core.test.TestPlanPerspectiveLoader;
import org.sonar.core.test.TestablePerspectiveLoader;
import org.sonar.core.timemachine.Periods;
@@ -387,8 +384,11 @@ public final class Platform {
// technical debt
servicesContainer.addSingleton(DebtService.class);
servicesContainer.addSingleton(TechnicalDebtModelSynchronizer.class);
+ servicesContainer.addSingleton(DebtCharacteristicsSynchronizer.class);
servicesContainer.addSingleton(TechnicalDebtModelRepository.class);
servicesContainer.addSingleton(TechnicalDebtXMLImporter.class);
+ servicesContainer.addSingleton(RuleDebtXMLImporter.class);
+ servicesContainer.addSingleton(CharacteristicsXMLImporter.class);
servicesContainer.addSingleton(DefaultTechnicalDebtManager.class);
// source
@@ -437,6 +437,7 @@ public final class Platform {
startupContainer.addSingleton(RuleRegistration.class);
startupContainer.addSingleton(RegisterNewProfiles.class);
startupContainer.addSingleton(JdbcDriverDeployer.class);
+ startupContainer.addSingleton(RegisterDebtCharacteristicModel.class);
startupContainer.addSingleton(RegisterTechnicalDebtModel.class);
startupContainer.addSingleton(DeleteDeprecatedMeasures.class);
startupContainer.addSingleton(GeneratePluginIndex.class);
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java b/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java
index 650aae01ff0..f96f117a034 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java
@@ -19,37 +19,58 @@
*/
package org.sonar.server.rule;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.server.rule.RuleDefinitions;
-import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.rules.RuleParam;
import org.sonar.api.rules.RuleRepository;
+import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.api.server.rule.RuleParamType;
import org.sonar.check.Cardinality;
import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.technicaldebt.RuleDebtXMLImporter;
+import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import javax.annotation.CheckForNull;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
/**
* Inject deprecated RuleRepository into RuleDefinitions for backward-compatibility.
*
* @since 4.2
*/
public class DeprecatedRuleDefinitions implements RuleDefinitions {
+
private final RuleI18nManager i18n;
private final RuleRepository[] repositories;
- public DeprecatedRuleDefinitions(RuleI18nManager i18n, RuleRepository[] repositories) {
+ private final TechnicalDebtModelRepository languageModelFinder;
+ private final RuleDebtXMLImporter importer;
+
+ public DeprecatedRuleDefinitions(RuleI18nManager i18n, RuleRepository[] repositories, TechnicalDebtModelRepository languageModelFinder, RuleDebtXMLImporter importer) {
this.i18n = i18n;
this.repositories = repositories;
+ this.languageModelFinder = languageModelFinder;
+ this.importer = importer;
}
- public DeprecatedRuleDefinitions(RuleI18nManager i18n) {
- this(i18n, new RuleRepository[0]);
+ public DeprecatedRuleDefinitions(RuleI18nManager i18n, TechnicalDebtModelRepository languageModelFinder, RuleDebtXMLImporter importer) {
+ this(i18n, new RuleRepository[0], languageModelFinder, importer);
}
@Override
public void define(Context context) {
+ // Load rule debt definitions from xml files provided by plugin
+ List<RuleDebtXMLImporter.RuleDebt> ruleDebts = loadRuleDebtList();
+
for (RuleRepository repository : repositories) {
// RuleRepository API does not handle difference between new and extended repositories,
NewRepository newRepository;
@@ -74,11 +95,22 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions {
newParam.setDescription(paramDescription(repository.getKey(), rule.getKey(), param));
newParam.setType(RuleParamType.parse(param.getType()));
}
+ updateRuleDebtDefinitions(newRule, repository.getKey(), rule.getKey(), ruleDebts);
}
newRepository.done();
}
}
+ private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<RuleDebtXMLImporter.RuleDebt> ruleDebts){
+ RuleDebtXMLImporter.RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
+ if (ruleDebt != null) {
+ newRule.setCharacteristicKey(ruleDebt.characteristicKey());
+ newRule.setRemediationFunction(ruleDebt.function());
+ newRule.setRemediationFactor(ruleDebt.factor());
+ newRule.setRemediationOffset(ruleDebt.offset());
+ }
+ }
+
@CheckForNull
private String ruleName(String repositoryKey, org.sonar.api.rules.Rule rule) {
String name = i18n.getName(repositoryKey, rule.getKey());
@@ -105,4 +137,39 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions {
);
return StringUtils.defaultIfBlank(desc, null);
}
+
+ public List<RuleDebtXMLImporter.RuleDebt> loadRuleDebtList() {
+ List<RuleDebtXMLImporter.RuleDebt> ruleDebtList = newArrayList();
+ for (String pluginKey : getContributingPluginListWithoutSqale()) {
+ ruleDebtList.addAll(loadRuleDebtsFromXml(pluginKey));
+ }
+ return ruleDebtList;
+ }
+
+ public List<RuleDebtXMLImporter.RuleDebt> loadRuleDebtsFromXml(String pluginKey) {
+ Reader xmlFileReader = null;
+ try {
+ xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
+ return importer.importXML(xmlFileReader);
+ } finally {
+ IOUtils.closeQuietly(xmlFileReader);
+ }
+ }
+
+ private Collection<String> getContributingPluginListWithoutSqale() {
+ Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
+ pluginList.remove(TechnicalDebtModelRepository.DEFAULT_MODEL);
+ return pluginList;
+ }
+
+ @CheckForNull
+ private RuleDebtXMLImporter.RuleDebt findRequirement(List<RuleDebtXMLImporter.RuleDebt> requirements, final String repoKey, final String ruleKey) {
+ return Iterables.find(requirements, new Predicate<RuleDebtXMLImporter.RuleDebt>() {
+ @Override
+ public boolean apply(RuleDebtXMLImporter.RuleDebt input) {
+ return input.ruleKey().equals(RuleKey.of(repoKey, ruleKey));
+ }
+ }, null);
+ }
+
}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java
index 2ab48037f8e..852273d4009 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java
@@ -20,6 +20,7 @@
package org.sonar.server.rule;
import com.google.common.base.Function;
+import com.google.common.base.Predicate;
import com.google.common.collect.*;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
@@ -37,7 +38,10 @@ import org.sonar.check.Cardinality;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.qualityprofile.db.ActiveRuleDao;
import org.sonar.core.rule.*;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
import org.sonar.server.qualityprofile.ProfilesManager;
+import org.sonar.server.startup.RegisterDebtCharacteristicModel;
import javax.annotation.CheckForNull;
@@ -51,6 +55,7 @@ import static com.google.common.collect.Lists.newArrayList;
* @since 4.2
*/
public class RuleRegistration implements Startable {
+
private static final Logger LOG = LoggerFactory.getLogger(RuleRegistration.class);
private final RuleDefinitionsLoader defLoader;
@@ -62,11 +67,16 @@ public class RuleRegistration implements Startable {
private final RuleTagDao ruleTagDao;
private final RuleTagOperations ruleTagOperations;
private final ActiveRuleDao activeRuleDao;
+ private final CharacteristicDao characteristicDao;
private final System2 system = System2.INSTANCE;
+ /**
+ * @param registerTechnicalDebtModel used only to be started after init of the technical debt model
+ */
public RuleRegistration(RuleDefinitionsLoader defLoader, ProfilesManager profilesManager,
RuleRegistry ruleRegistry, ESRuleTags esRuleTags, RuleTagOperations ruleTagOperations,
- MyBatis myBatis, RuleDao ruleDao, RuleTagDao ruleTagDao, ActiveRuleDao activeRuleDao) {
+ MyBatis myBatis, RuleDao ruleDao, RuleTagDao ruleTagDao, ActiveRuleDao activeRuleDao, CharacteristicDao characteristicDao,
+ RegisterDebtCharacteristicModel registerTechnicalDebtModel) {
this.defLoader = defLoader;
this.profilesManager = profilesManager;
this.ruleRegistry = ruleRegistry;
@@ -76,6 +86,7 @@ public class RuleRegistration implements Startable {
this.ruleDao = ruleDao;
this.ruleTagDao = ruleTagDao;
this.activeRuleDao = activeRuleDao;
+ this.characteristicDao = characteristicDao;
}
@Override
@@ -85,8 +96,9 @@ public class RuleRegistration implements Startable {
try {
RuleDefinitions.Context context = defLoader.load();
Buffer buffer = new Buffer(system.now());
+ List<CharacteristicDto> characteristicDtos = characteristicDao.selectEnabledCharacteristics();
selectRulesFromDb(buffer, sqlSession);
- enableRuleDefinitions(context, buffer, sqlSession);
+ enableRuleDefinitions(context, buffer, characteristicDtos, sqlSession);
List<RuleDto> removedRules = processRemainingDbRules(buffer, sqlSession);
removeActiveRulesOnStillExistingRepositories(removedRules, context);
index(buffer);
@@ -120,27 +132,27 @@ public class RuleRegistration implements Startable {
}
}
- private void enableRuleDefinitions(RuleDefinitions.Context context, Buffer buffer, SqlSession sqlSession) {
+ private void enableRuleDefinitions(RuleDefinitions.Context context, Buffer buffer, List<CharacteristicDto> characteristicDtos, SqlSession sqlSession) {
for (RuleDefinitions.Repository repoDef : context.repositories()) {
- enableRepository(buffer, sqlSession, repoDef);
+ enableRepository(buffer, sqlSession, repoDef, characteristicDtos);
}
for (RuleDefinitions.ExtendedRepository extendedRepoDef : context.extendedRepositories()) {
if (context.repository(extendedRepoDef.key()) == null) {
LOG.warn(String.format("Extension is ignored, repository %s does not exist", extendedRepoDef.key()));
} else {
- enableRepository(buffer, sqlSession, extendedRepoDef);
+ enableRepository(buffer, sqlSession, extendedRepoDef, characteristicDtos);
}
}
}
- private void enableRepository(Buffer buffer, SqlSession sqlSession, RuleDefinitions.ExtendedRepository repoDef) {
+ private void enableRepository(Buffer buffer, SqlSession sqlSession, RuleDefinitions.ExtendedRepository repoDef, List<CharacteristicDto> characteristicDtos) {
int count = 0;
for (RuleDefinitions.Rule ruleDef : repoDef.rules()) {
RuleDto dto = buffer.rule(RuleKey.of(ruleDef.repository().key(), ruleDef.key()));
if (dto == null) {
- dto = enableAndInsert(buffer, sqlSession, ruleDef);
+ dto = enableAndInsert(buffer, sqlSession, ruleDef, characteristicDtos);
} else {
- enableAndUpdate(buffer, sqlSession, ruleDef, dto);
+ enableAndUpdate(buffer, sqlSession, ruleDef, dto, characteristicDtos);
}
buffer.markProcessed(dto);
count++;
@@ -151,8 +163,9 @@ public class RuleRegistration implements Startable {
sqlSession.commit();
}
- private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef) {
+ private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, List<CharacteristicDto> characteristicDtos) {
RemediationFunction remediationFunction = ruleDef.remediationFunction();
+
RuleDto ruleDto = new RuleDto()
.setCardinality(ruleDef.template() ? Cardinality.MULTIPLE : Cardinality.SINGLE)
.setConfigKey(ruleDef.internalKey())
@@ -164,12 +177,17 @@ public class RuleRegistration implements Startable {
.setSeverity(ruleDef.severity())
.setCreatedAt(buffer.now())
.setUpdatedAt(buffer.now())
- .setStatus(ruleDef.status().name())
- // TODO set default characteristic id
- .setDefaultRemediationFunction(remediationFunction != null ? remediationFunction.name() : null)
- .setDefaultRemediationFactor(ruleDef.remediationFactor())
- .setDefaultRemediationOffset(ruleDef.remediationOffset())
- .setEffortToFixL10nKey(ruleDef.effortToFixL10nKey());
+ .setStatus(ruleDef.status().name());
+
+ CharacteristicDto characteristic = findCharacteristic(characteristicDtos, ruleDef);
+ if (characteristic != null) {
+ ruleDto.setDefaultCharacteristicId(characteristic.getId())
+ .setDefaultRemediationFunction(remediationFunction != null ? remediationFunction.name() : null)
+ .setDefaultRemediationFactor(ruleDef.remediationFactor())
+ .setDefaultRemediationOffset(ruleDef.remediationOffset())
+ .setEffortToFixL10nKey(ruleDef.effortToFixL10nKey());
+ }
+
ruleDao.insert(ruleDto, sqlSession);
buffer.add(ruleDto);
@@ -187,8 +205,8 @@ public class RuleRegistration implements Startable {
return ruleDto;
}
- private void enableAndUpdate(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto) {
- if (mergeRule(buffer, ruleDef, dto)) {
+ private void enableAndUpdate(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
+ if (mergeRule(buffer, ruleDef, dto, characteristicDtos)) {
ruleDao.update(dto);
}
mergeParams(buffer, sqlSession, ruleDef, dto);
@@ -196,7 +214,7 @@ public class RuleRegistration implements Startable {
buffer.markProcessed(dto);
}
- private boolean mergeRule(Buffer buffer, RuleDefinitions.Rule def, RuleDto dto) {
+ private boolean mergeRule(Buffer buffer, RuleDefinitions.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
boolean changed = false;
if (!StringUtils.equals(dto.getName(), def.name())) {
dto.setName(def.name());
@@ -229,34 +247,42 @@ public class RuleRegistration implements Startable {
dto.setLanguage(def.repository().language());
changed = true;
}
- changed = mergeDebtRule(def, dto) || changed;
+ changed = mergeDebtDefinitions(def, dto, characteristicDtos) || changed;
if (changed) {
dto.setUpdatedAt(buffer.now());
}
return changed;
}
- private boolean mergeDebtRule(RuleDefinitions.Rule def, RuleDto dto){
+ private boolean mergeDebtDefinitions(RuleDefinitions.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
boolean changed = false;
- // TODO add characteristic id change verification
+ CharacteristicDto characteristic = findCharacteristic(characteristicDtos, def);
+ Integer characteristicId = characteristic != null ? characteristic.getId() : null;
+ RemediationFunction remediationFunction = characteristic != null ? def.remediationFunction() : null;
+ String remediationFactor = characteristic != null ? def.remediationFactor() : null;
+ String remediationOffset = characteristic != null ? def.remediationOffset() : null;
+ String effortToFixL10nKey = characteristic != null ? def.effortToFixL10nKey() : null;
- RemediationFunction remediationFunction = def.remediationFunction();
+ if (!ObjectUtils.equals(dto.getDefaultCharacteristicId(), characteristicId)) {
+ dto.setDefaultCharacteristicId(characteristicId);
+ changed = true;
+ }
String remediationFunctionString = remediationFunction != null ? remediationFunction.name() : null;
if (!StringUtils.equals(dto.getDefaultRemediationFunction(), remediationFunctionString)) {
dto.setDefaultRemediationFunction(remediationFunctionString);
changed = true;
}
- if (!StringUtils.equals(dto.getDefaultRemediationFactor(), def.remediationFactor())) {
- dto.setDefaultRemediationFactor(def.remediationFactor());
+ if (!StringUtils.equals(dto.getDefaultRemediationFactor(), remediationFactor)) {
+ dto.setDefaultRemediationFactor(remediationFactor);
changed = true;
}
- if (!StringUtils.equals(dto.getDefaultRemediationOffset(), def.remediationOffset())) {
- dto.setDefaultRemediationOffset(def.remediationOffset());
+ if (!StringUtils.equals(dto.getDefaultRemediationOffset(), remediationOffset)) {
+ dto.setDefaultRemediationOffset(remediationOffset);
changed = true;
}
- if (!StringUtils.equals(dto.getEffortToFixL10nKey(), def.effortToFixL10nKey())) {
- dto.setEffortToFixL10nKey(def.effortToFixL10nKey());
+ if (!StringUtils.equals(dto.getEffortToFixL10nKey(), effortToFixL10nKey)) {
+ dto.setEffortToFixL10nKey(effortToFixL10nKey);
changed = true;
}
return changed;
@@ -508,4 +534,21 @@ public class RuleRegistration implements Startable {
unprocessedRuleIds.remove(ruleDto.getId());
}
}
+
+ @CheckForNull
+ private CharacteristicDto findCharacteristic(List<CharacteristicDto> characteristicDtos, RuleDefinitions.Rule ruleDef) {
+ final String key = ruleDef.characteristicKey();
+ CharacteristicDto characteristicDto = Iterables.find(characteristicDtos, new Predicate<CharacteristicDto>() {
+ @Override
+ public boolean apply(CharacteristicDto input) {
+ // TODO remove check on null rule id when only characteristics without requirements will be returned
+ return input.getRuleId() == null && input.getKey().equals(key);
+ }
+ }, null);
+ // TODO check not root characteristic
+ if (characteristicDto == null) {
+ LOG.warn(String.format("Characteristic : '%s' has not been found, Technical debt definitions on rule '%s:%s' will be ignored", key, ruleDef.repository(), ruleDef.key()));
+ }
+ return characteristicDto;
+ }
}
diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java
new file mode 100644
index 00000000000..5395740c127
--- /dev/null
+++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.startup;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.TimeProfiler;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.technicaldebt.DebtCharacteristicsSynchronizer;
+
+public class RegisterDebtCharacteristicModel {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RegisterDebtCharacteristicModel.class);
+
+ private final DebtCharacteristicsSynchronizer manager;
+
+ public RegisterDebtCharacteristicModel(DebtCharacteristicsSynchronizer manager) {
+ this.manager = manager;
+ }
+
+ public void start() {
+ TimeProfiler profiler = new TimeProfiler(LOGGER).start("Register Debt Characteristics Model");
+ manager.synchronize(ValidationMessages.create());
+ profiler.stop();
+ }
+
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java b/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java
index 5937637d48d..00fd9e91ece 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java
@@ -20,23 +20,43 @@
package org.sonar.server.rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.server.rule.RuleDefinitions;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.RuleRepository;
+import org.sonar.api.server.rule.RuleDefinitions;
import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.technicaldebt.RuleDebtXMLImporter;
+import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
+import java.io.Reader;
import java.util.Arrays;
import java.util.List;
+import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+@RunWith(MockitoJUnitRunner.class)
public class DeprecatedRuleDefinitionsTest {
+ @Mock
+ RuleI18nManager i18n;
+
+ @Mock
+ TechnicalDebtModelRepository debtModelRepository;
+
+ @Mock
+ RuleDebtXMLImporter importer;
+
static class CheckstyleRules extends RuleRepository {
public CheckstyleRules() {
super("checkstyle", "java");
@@ -56,12 +76,24 @@ public class DeprecatedRuleDefinitionsTest {
}
}
+ static class UseBundles extends RuleRepository {
+ public UseBundles() {
+ super("checkstyle", "java");
+ setName("Checkstyle");
+ }
+
+ @Override
+ public List<Rule> createRules() {
+ Rule rule = Rule.create("checkstyle", "ConstantName");
+ rule.createParameter("format");
+ return Arrays.asList(rule);
+ }
+ }
+
@Test
public void wrap_deprecated_rule_repositories() throws Exception {
RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleI18nManager i18n = mock(RuleI18nManager.class);
-
- new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}).define(context);
+ new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context);
assertThat(context.repositories()).hasSize(1);
RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
@@ -91,38 +123,21 @@ public class DeprecatedRuleDefinitionsTest {
@Test
public void emulate_the_day_deprecated_api_can_be_dropped() throws Exception {
RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleI18nManager i18n = mock(RuleI18nManager.class);
// no more RuleRepository !
- new DeprecatedRuleDefinitions(i18n);
+ new DeprecatedRuleDefinitions(i18n, debtModelRepository, importer);
assertThat(context.repositories()).isEmpty();
}
-
- static class UseBundles extends RuleRepository {
- public UseBundles() {
- super("checkstyle", "java");
- setName("Checkstyle");
- }
-
- @Override
- public List<Rule> createRules() {
- Rule rule = Rule.create("checkstyle", "ConstantName");
- rule.createParameter("format");
- return Arrays.asList(rule);
- }
- }
-
@Test
public void use_l10n_bundles() throws Exception {
RuleDefinitions.Context context = new RuleDefinitions.Context();
- RuleI18nManager i18n = mock(RuleI18nManager.class);
when(i18n.getName("checkstyle", "ConstantName")).thenReturn("Constant Name");
when(i18n.getDescription("checkstyle", "ConstantName")).thenReturn("Checks that constant names conform to the specified format");
when(i18n.getParamDescription("checkstyle", "ConstantName", "format")).thenReturn("Regular expression");
- new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new UseBundles()}).define(context);
+ new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new UseBundles()}, debtModelRepository, importer).define(context);
RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
RuleDefinitions.Rule rule = checkstyle.rule("ConstantName");
@@ -134,4 +149,38 @@ public class DeprecatedRuleDefinitionsTest {
assertThat(param.name()).isEqualTo("format");
assertThat(param.description()).isEqualTo("Regular expression");
}
+
+ @Test
+ public void define_rule_debt() throws Exception {
+ RuleDefinitions.Context context = new RuleDefinitions.Context();
+
+ List<RuleDebtXMLImporter.RuleDebt> ruleDebts = newArrayList(
+ new RuleDebtXMLImporter.RuleDebt()
+ .setCharacteristicKey("MEMORY_EFFICIENCY")
+ .setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
+ .setFunction(RemediationFunction.LINEAR_OFFSET)
+ .setFactor("1d")
+ .setOffset("10min")
+ );
+
+ Reader javaModelReader = mock(Reader.class);
+ when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+ when(debtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+ when(importer.importXML(eq(javaModelReader))).thenReturn(ruleDebts);
+
+ new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context);
+
+ assertThat(context.repositories()).hasSize(1);
+ RuleDefinitions.Repository checkstyle = context.repository("checkstyle");
+ assertThat(checkstyle.rules()).hasSize(1);
+
+ RuleDefinitions.Rule rule = checkstyle.rule("ConstantName");
+ assertThat(rule).isNotNull();
+ assertThat(rule.key()).isEqualTo("ConstantName");
+ assertThat(rule.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(rule.remediationFunction()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
+ assertThat(rule.remediationFactor()).isEqualTo("1d");
+ assertThat(rule.remediationOffset()).isEqualTo("10min");
+ }
+
}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java
index 3853bff4914..7b75b8b8401 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java
@@ -31,7 +31,9 @@ import org.sonar.core.persistence.MyBatis;
import org.sonar.core.qualityprofile.db.ActiveRuleDao;
import org.sonar.core.rule.RuleDao;
import org.sonar.core.rule.RuleTagDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.server.qualityprofile.ProfilesManager;
+import org.sonar.server.startup.RegisterDebtCharacteristicModel;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.*;
@@ -53,6 +55,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
RuleDao ruleDao;
RuleTagDao ruleTagDao;
ActiveRuleDao activeRuleDao;
+ CharacteristicDao characteristicDao;
@Before
public void before() {
@@ -61,8 +64,9 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
ruleTagDao = new RuleTagDao(myBatis);
activeRuleDao = new ActiveRuleDao(myBatis);
ruleTagOperations = new RuleTagOperations(ruleTagDao, esRuleTags);
+ characteristicDao = new CharacteristicDao(myBatis);
task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new FakeRepository()}),
- profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao);
+ profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtCharacteristicModel.class));
}
@Test
@@ -162,6 +166,14 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
}
@Test
+ public void remove_rule_debt_definitions_if_characteristic_not_found() {
+ setupData("remove_rule_debt_definitions_if_characteristic_not_found");
+ task.start();
+
+ checkTables("remove_rule_debt_definitions_if_characteristic_not_found", EXCLUDED_COLUMN_NAMES, "rules");
+ }
+
+ @Test
public void not_disable_template_rules_if_parent_is_enabled() {
setupData("not_disable_template_rules_if_parent_is_enabled");
task.start();
@@ -189,7 +201,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
@Test
public void test_high_number_of_rules() {
task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new BigRepository()}),
- profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao);
+ profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtCharacteristicModel.class));
setupData("shared");
task.start();
@@ -204,7 +216,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
public void insert_extended_repositories() {
task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{
new FindbugsRepository(), new FbContribRepository()}),
- profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao);
+ profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtCharacteristicModel.class));
setupData("empty");
task.start();
@@ -221,7 +233,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
.setName("One")
.setHtmlDescription("Description of One")
.setSeverity(Severity.BLOCKER)
- .setCharacteristicKey("COMPILER")
+ .setCharacteristicKey("MEMORY_EFFICIENCY")
.setRemediationFunction(RemediationFunction.LINEAR_OFFSET)
.setRemediationFactor("5d")
.setRemediationOffset("10h")
diff --git a/sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java b/sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java
new file mode 100644
index 00000000000..0dcd74a24c6
--- /dev/null
+++ b/sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java
@@ -0,0 +1,41 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.startup;
+
+import org.junit.Test;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.technicaldebt.DebtCharacteristicsSynchronizer;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+
+public class RegisterDebtCharacteristicModelTest {
+
+ @Test
+ public void create_model() throws Exception {
+ DebtCharacteristicsSynchronizer synchronizer = mock(DebtCharacteristicsSynchronizer.class);
+ RegisterDebtCharacteristicModel sqaleDefinition = new RegisterDebtCharacteristicModel(synchronizer);
+
+ sqaleDefinition.start();
+
+ verify(synchronizer, times(1)).synchronize(any(ValidationMessages.class));
+ }
+}
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml
index 050c8b4377c..489e2108e85 100644
--- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml
@@ -1,23 +1,3 @@
-<!--
- ~ SonarQube, open source software quality management tool.
- ~ Copyright (C) 2008-2013 SonarSource
- ~ mailto:contact AT sonarsource DOT com
- ~
- ~ SonarQube 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.
- ~
- ~ SonarQube 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.
- -->
-
<dataset>
<rules id="1" plugin_rule_key="deprecated-key" plugin_name="deprecated-repo" plugin_config_key="[null]" name="Deprecated" description="[null]"
@@ -30,7 +10,7 @@
<rules id="2" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="config1" name="One" description="Description of One"
status="READY" priority="4" cardinality="SINGLE" parent_id="[null]" language="java"
- characteristic_id="[null]" default_characteristic_id="[null]"
+ characteristic_id="[null]" default_characteristic_id="2"
remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
remediation_factor="[null]" default_remediation_factor="5d"
remediation_offset="[null]" default_remediation_offset="10h"
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml
new file mode 100644
index 00000000000..52e53e0cf39
--- /dev/null
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml
@@ -0,0 +1,20 @@
+<dataset>
+
+ <!-- All debt parameters are reset as the characteristic MEMORY_EFFICIENCY do not exists -->
+ <rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="config1" name="One" description="Description of One"
+ status="READY" priority="4" cardinality="SINGLE" parent_id="[null]" language="java"
+ characteristic_id="[null]" default_characteristic_id="[null]"
+ remediation_function="[null]" default_remediation_function="[null]"
+ remediation_factor="[null]" default_remediation_factor="[null]"
+ remediation_offset="[null]" default_remediation_offset="[null]"
+ effort_to_fix_l10n_key="[null]"/>
+
+ <rules id="2" plugin_rule_key="rule2" plugin_name="fake" plugin_config_key="[null]" name="Two" description="Description of Two"
+ status="DEPRECATED" priority="0" cardinality="SINGLE" parent_id="[null]" language="java"
+ characteristic_id="[null]" default_characteristic_id="[null]"
+ remediation_function="[null]" default_remediation_function="[null]"
+ remediation_factor="[null]" default_remediation_factor="[null]"
+ remediation_offset="[null]" default_remediation_offset="[null]"
+ effort_to_fix_l10n_key="[null]"/>
+
+</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml
new file mode 100644
index 00000000000..f926443c2de
--- /dev/null
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml
@@ -0,0 +1,17 @@
+<dataset>
+
+ <characteristics id="999" kee="NEW" name="New" root_id="1" characteristic_order="1" enabled="[true]"/>
+
+ <rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="old_config_key" name="old name" description="old description"
+ status="READY" priority="2" cardinality="SINGLE" parent_id="[null]"
+ characteristic_id="[null]" default_characteristic_id="200"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_factor="[null]" default_remediation_factor="14min"
+ remediation_offset="[null]" default_remediation_offset="[null]"
+ effort_to_fix_l10n_key="[null]"/>
+
+ <rules id="2" plugin_rule_key="rule2" plugin_name="fake" plugin_config_key="old_config_key2" name="old name2" description="old description2"
+ status="READY" priority="1" cardinality="SINGLE" parent_id="[null]"/>
+
+
+</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml
index 84192cc4810..17f652e7255 100644
--- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml
@@ -1,5 +1,7 @@
<dataset>
+ <characteristics id="2" kee="MEMORY_EFFICIENCY" name="Memory Efficiency" root_id="1" characteristic_order="1" enabled="[true]"/>
+
<rules id="1" plugin_rule_key="deprecated-key" plugin_name="deprecated-repo" plugin_config_key="[null]" name="Deprecated" description="[null]"
status="READY" priority="4" cardinality="SINGLE" parent_id="[null]"/>
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml
index 416104e8287..cfa18f014e5 100644
--- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml
@@ -1,5 +1,7 @@
<dataset>
+ <characteristics id="200" kee="MEMORY_EFFICIENCY" name="Memory Efficiency" root_id="1" characteristic_order="1" enabled="[true]"/>
+
<rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="old_config_key" name="old name" description="old description"
status="READY" priority="2" cardinality="SINGLE" parent_id="[null]"
characteristic_id="[null]" default_characteristic_id="200"
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml
index b5a6352ede7..0ea5e06aa17 100644
--- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml
+++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml
@@ -1,25 +1,7 @@
-<!--
- ~ SonarQube, open source software quality management tool.
- ~ Copyright (C) 2008-2013 SonarSource
- ~ mailto:contact AT sonarsource DOT com
- ~
- ~ SonarQube 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.
- ~
- ~ SonarQube 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.
- -->
-
<dataset>
+ <characteristics id="100" kee="MEMORY_EFFICIENCY" name="Memory Efficiency" root_id="1" characteristic_order="1" enabled="[true]"/>
+
<rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="[null]" name="Rule one" description="[null]"
status="READY" priority="4" cardinality="MULTIPLE" parent_id="[null]" language="[null]"
characteristic_id="[null]" default_characteristic_id="100"