return getMapper(session).selectByCharacteristicOrSubCharacteristicId(characteristicOrSubCharacteristicId);
}
- public List<RuleDto> selectOverridingDebt() {
+ public List<RuleDto> selectOverridingDebt(List<String> repositories) {
SqlSession session = mybatis.openSession();
try {
- return selectOverridingDebt(session);
+ return selectOverridingDebt(repositories, session);
} finally {
MyBatis.closeQuietly(session);
}
}
- public List<RuleDto> selectOverridingDebt(SqlSession session) {
- return getMapper(session).selectOverridingDebt();
+ public List<RuleDto> selectOverridingDebt(List<String> repositories, SqlSession session) {
+ return getMapper(session).selectOverridingDebt(repositories);
}
@CheckForNull
List<RuleDto> selectByCharacteristicOrSubCharacteristicId(int id);
- List<RuleDto> selectOverridingDebt();
+ List<RuleDto> selectOverridingDebt(@Param("repositories") List<String> repositories);
RuleDto selectById(Integer id);
SELECT <include refid="selectColumns"/> FROM rules
<where>
AND (characteristic_id is NOT NULL or remediation_function IS NOT NULL)
+ <if test="repositories.size()>0">
+ AND
+ <foreach item="repo" index="index" collection="repositories" open="(" separator=" or " close=")">
+ plugin_name=#{repo}
+ </foreach>
+ </if>
</where>
</select>
import org.sonar.check.Cardinality;
import org.sonar.core.persistence.AbstractDaoTestCase;
+import java.util.Collections;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
public void select_overriding_debt_rules() throws Exception {
setupData("select_overriding_debt_rules");
- assertThat(dao.selectOverridingDebt()).hasSize(3);
+ assertThat(dao.selectOverridingDebt(Collections.<String>emptyList())).hasSize(3);
+
+ assertThat(dao.selectOverridingDebt(newArrayList("squid"))).hasSize(2);
+ assertThat(dao.selectOverridingDebt(newArrayList("java"))).hasSize(1);
+ assertThat(dao.selectOverridingDebt(newArrayList("squid", "java"))).hasSize(3);
+ assertThat(dao.selectOverridingDebt(newArrayList("unknown"))).isEmpty();
}
@Test
<dataset>
- <!-- Rule overriding debt and with default debt should be returned -->
+ <!-- Rule overriding debt and with default debt -->
<rules id="1" plugin_rule_key="UselessImportCheck" plugin_name="squid" name="UselessImportCheck" description="Useless imports should be removed" status="READY"
characteristic_id="2" default_characteristic_id="50"
remediation_function="LINEAR_OFFSET" default_remediation_function="LINEAR_OFFSET"
remediation_factor="5d" default_remediation_factor="5d"
remediation_offset="10h" default_remediation_offset="10h" updated_at="2014-02-19"/>
- <!-- Rule only overriding debt should be returned -->
+ <!-- Rule only overriding debt -->
<rules id="2" plugin_rule_key="LeftCurlyBraceStartLineCheck" plugin_name="squid" name="LeftCurlyBraceStartLineCheck" description="Left curly braces should be located at the beginning of lines of code" status="READY"
characteristic_id="3" default_characteristic_id="[null]"
remediation_function="LINEAR_OFFSET" default_remediation_function="[null]"
remediation_factor="5d" default_remediation_factor="[null]"
remediation_offset="10h" default_remediation_offset="[null]" updated_at="2014-02-19"/>
- <!-- Rule with only default debt should be returned -->
+ <!-- Rule with only default debt : never been returned -->
<rules id="3" plugin_rule_key="CallToFileDeleteOnExitMethod" plugin_name="squid" name="CallToFileDeleteOnExitMethod" description="CallToFileDeleteOnExitMethod" status="READY"
characteristic_id="[null]" default_characteristic_id="50"
remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
remediation_factor="[null]" default_remediation_factor="5d"
remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"/>
- <!-- Removed rule overriding debt : should be returned -->
- <rules id="4" plugin_rule_key="ObjectFinalizeOverridenCallsSuperFinalizeCheck" plugin_name="squid" name="ObjectFinalizeOverridenCallsSuperFinalizeCheck" description="super.finalize() should be called at the end of Object.finalize() implementations" status="REMOVED"
+ <!-- Removed rule overriding debt -->
+ <rules id="4" plugin_rule_key="ObjectFinalizeOverridenCallsSuperFinalizeCheck" plugin_name="java" name="ObjectFinalizeOverridenCallsSuperFinalizeCheck" description="super.finalize() should be called at the end of Object.finalize() implementations" status="REMOVED"
characteristic_id="3" default_characteristic_id="50"
remediation_function="LINEAR" default_remediation_function="LINEAR_OFFSET"
remediation_factor="5d" default_remediation_factor="5min"
}
/**
- * Disable characteristic and sub characteristic or only sub characteristic.
+ * Disable characteristic and its sub characteristics or only sub characteristic.
* Will also update every rules linked to sub characteristics by setting characteristic id to -1 and remove function, factor and offset.
*/
- public void delete(int characteristicOrSubCharacteristicId) {
+ public void delete(int characteristicId) {
checkPermission();
Date updateDate = new Date(system2.now());
SqlSession session = mybatis.openBatchSession();
try {
- CharacteristicDto characteristicOrSubCharacteristic = findCharacteristic(characteristicOrSubCharacteristicId, session);
+ CharacteristicDto characteristicOrSubCharacteristic = findCharacteristic(characteristicId, session);
disableDebtRules(
ruleDao.selectByCharacteristicOrSubCharacteristicId(characteristicOrSubCharacteristic.getId(), session),
updateDate,
);
if (characteristicOrSubCharacteristic.getParentId() == null) {
- List<CharacteristicDto> subChracteristics = dao.selectCharacteristicsByParentId(characteristicOrSubCharacteristic.getId(), session);
- for (CharacteristicDto subCharacteristic : subChracteristics) {
+ List<CharacteristicDto> subCharacteristics = dao.selectCharacteristicsByParentId(characteristicOrSubCharacteristic.getId(), session);
+ for (CharacteristicDto subCharacteristic : subCharacteristics) {
disableCharacteristic(subCharacteristic, updateDate, session);
}
}
package org.sonar.server.debt;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import org.apache.commons.io.IOUtils;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.server.rule.RuleRepositories;
import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.io.Reader;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
+import static com.google.common.collect.Lists.newArrayList;
+
public class DebtModelRestore implements ServerComponent {
private final MyBatis mybatis;
private final RuleDao ruleDao;
private final DebtModelOperations debtModelOperations;
private final TechnicalDebtModelRepository debtModelPluginRepository;
+ private final RuleRepositories ruleRepositories;
private final DebtCharacteristicsXMLImporter importer;
private final System2 system2;
public DebtModelRestore(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, DebtModelOperations debtModelOperations, TechnicalDebtModelRepository debtModelPluginRepository,
- DebtCharacteristicsXMLImporter importer) {
- this(mybatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, importer, System2.INSTANCE);
+ RuleRepositories ruleRepositories, DebtCharacteristicsXMLImporter importer) {
+ this(mybatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, ruleRepositories, importer, System2.INSTANCE);
}
@VisibleForTesting
DebtModelRestore(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, DebtModelOperations debtModelOperations, TechnicalDebtModelRepository debtModelPluginRepository,
- DebtCharacteristicsXMLImporter importer,
+ RuleRepositories ruleRepositories, DebtCharacteristicsXMLImporter importer,
System2 system2) {
this.mybatis = mybatis;
this.dao = dao;
this.ruleDao = ruleDao;
this.debtModelOperations = debtModelOperations;
this.debtModelPluginRepository = debtModelPluginRepository;
+ this.ruleRepositories = ruleRepositories;
this.importer = importer;
this.system2 = system2;
}
/**
- * Restore model from all provided plugins
+ * Restore from provided model
+ */
+ public void restore() {
+ restore(Collections.<RuleRepositories.Repository>emptyList());
+ }
+
+ /**
+ * Restore from plugins providing rules for a given language
*/
- public void restoreFromProvidedModel() {
+ public void restore(String languageKey) {
+ restore(ruleRepositories.repositoriesForLang(languageKey));
+ }
+
+ private void restore(Collection<RuleRepositories.Repository> repositories) {
checkPermission();
Date updateDate = new Date(system2.now());
List<CharacteristicDto> persisted = dao.selectEnabledCharacteristics();
DebtModel providedModel = loadModelFromXml(TechnicalDebtModelRepository.DEFAULT_MODEL);
restoreCharacteristics(providedModel, persisted, updateDate, session);
- resetOverridingRuleDebt(updateDate, session);
+ resetOverridingRuleDebt(repositories, updateDate, session);
session.commit();
} finally {
}
}
- private void resetOverridingRuleDebt(Date updateDate, SqlSession session) {
- for (RuleDto rule : ruleDao.selectOverridingDebt(session)) {
+ private void resetOverridingRuleDebt(Collection<RuleRepositories.Repository> repositories, Date updateDate, SqlSession session) {
+ List<String> repositoryKeys = newArrayList(Iterables.transform(repositories, new Function<RuleRepositories.Repository, String>() {
+ @Override
+ public String apply(RuleRepositories.Repository input) {
+ return input.getKey();
+ }
+ }));
+ for (RuleDto rule : ruleDao.selectOverridingDebt(repositoryKeys, session)) {
rule.setCharacteristicId(null);
rule.setRemediationFunction(null);
rule.setRemediationFactor(null);
}
}
- private CharacteristicDto restoreCharacteristic(DebtCharacteristic targetCharacteristic, @Nullable Integer parentId, List<CharacteristicDto> sourceCharacteristics,
+ private CharacteristicDto restoreCharacteristic(DebtCharacteristic targetCharacteristic, @Nullable Integer parentId, List<CharacteristicDto> sourceCharacteristics,
Date updateDate, SqlSession session) {
CharacteristicDto sourceCharacteristic = dtoByKey(sourceCharacteristics, targetCharacteristic.key());
if (sourceCharacteristic == null) {
* Disable characteristic and sub characteristic or only sub characteristic.
* Will also update every rules linked to sub characteristics by setting characteristic id to -1 and remove function, factor and offset.
*/
- public void delete(int characteristicOrSubCharactteristicId) {
- debtModelOperations.delete(characteristicOrSubCharactteristicId);
+ public void delete(int characteristicId) {
+ debtModelOperations.delete(characteristicId);
}
+ /**
+ * Restore from provided model
+ */
public void restore(){
- debtModelRestore.restoreFromProvidedModel();
+ debtModelRestore.restore();
+ }
+
+ /**
+ * Restore from plugins providing rules for a given language
+ */
+ public void restore(String languageKey) {
+ debtModelRestore.restore(languageKey);
}
}
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.server.rule.RuleRepositories;
import org.sonar.server.user.MockUserSession;
import java.io.Reader;
@Mock
DebtCharacteristicsXMLImporter characteristicsXMLImporter;
+ @Mock
+ RuleRepositories ruleRepositories;
+
@Mock
System2 system2;
when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
when(characteristicsXMLImporter.importXML(eq(defaultModelReader))).thenReturn(defaultModel);
- debtModelRestore = new DebtModelRestore(myBatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, characteristicsXMLImporter, system2);
+ debtModelRestore = new DebtModelRestore(myBatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, ruleRepositories, characteristicsXMLImporter, system2);
}
@Test
ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
verify(dao, times(2)).insert(characteristicArgument.capture(), eq(session));
- assertThat(characteristicArgument.getAllValues().get(0).getId()).isEqualTo(10);
- assertThat(characteristicArgument.getAllValues().get(0).getKey()).isEqualTo("PORTABILITY");
- assertThat(characteristicArgument.getAllValues().get(0).getName()).isEqualTo("Portability");
- assertThat(characteristicArgument.getAllValues().get(0).getParentId()).isNull();
- assertThat(characteristicArgument.getAllValues().get(0).getOrder()).isEqualTo(1);
- assertThat(characteristicArgument.getAllValues().get(0).getCreatedAt()).isEqualTo(now);
- assertThat(characteristicArgument.getAllValues().get(0).getUpdatedAt()).isNull();
-
- assertThat(characteristicArgument.getAllValues().get(1).getId()).isEqualTo(11);
- assertThat(characteristicArgument.getAllValues().get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(characteristicArgument.getAllValues().get(1).getName()).isEqualTo("Compiler");
- assertThat(characteristicArgument.getAllValues().get(1).getParentId()).isEqualTo(10);
- assertThat(characteristicArgument.getAllValues().get(1).getOrder()).isNull();
- assertThat(characteristicArgument.getAllValues().get(1).getCreatedAt()).isEqualTo(now);
- assertThat(characteristicArgument.getAllValues().get(1).getUpdatedAt()).isNull();
+
+ CharacteristicDto dto1 = characteristicArgument.getAllValues().get(0);
+ assertThat(dto1.getId()).isEqualTo(10);
+ assertThat(dto1.getKey()).isEqualTo("PORTABILITY");
+ assertThat(dto1.getName()).isEqualTo("Portability");
+ assertThat(dto1.getParentId()).isNull();
+ assertThat(dto1.getOrder()).isEqualTo(1);
+ assertThat(dto1.getCreatedAt()).isEqualTo(now);
+ assertThat(dto1.getUpdatedAt()).isNull();
+
+ CharacteristicDto dto2 = characteristicArgument.getAllValues().get(1);
+ assertThat(dto2.getId()).isEqualTo(11);
+ assertThat(dto2.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(dto2.getName()).isEqualTo("Compiler");
+ assertThat(dto2.getParentId()).isEqualTo(10);
+ assertThat(dto2.getOrder()).isNull();
+ assertThat(dto2.getCreatedAt()).isEqualTo(now);
+ assertThat(dto2.getUpdatedAt()).isNull();
}
@Test
ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
verify(dao, times(2)).update(characteristicArgument.capture(), eq(session));
- assertThat(characteristicArgument.getAllValues().get(0).getId()).isEqualTo(1);
- assertThat(characteristicArgument.getAllValues().get(0).getKey()).isEqualTo("PORTABILITY");
- assertThat(characteristicArgument.getAllValues().get(0).getName()).isEqualTo("Portability");
- assertThat(characteristicArgument.getAllValues().get(0).getParentId()).isNull();
- assertThat(characteristicArgument.getAllValues().get(0).getOrder()).isEqualTo(1);
- assertThat(characteristicArgument.getAllValues().get(0).getCreatedAt()).isEqualTo(oldDate);
- assertThat(characteristicArgument.getAllValues().get(0).getUpdatedAt()).isEqualTo(now);
-
- assertThat(characteristicArgument.getAllValues().get(1).getId()).isEqualTo(2);
- assertThat(characteristicArgument.getAllValues().get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(characteristicArgument.getAllValues().get(1).getName()).isEqualTo("Compiler");
- assertThat(characteristicArgument.getAllValues().get(1).getParentId()).isEqualTo(1);
- assertThat(characteristicArgument.getAllValues().get(1).getOrder()).isNull();
- assertThat(characteristicArgument.getAllValues().get(1).getCreatedAt()).isEqualTo(oldDate);
- assertThat(characteristicArgument.getAllValues().get(1).getUpdatedAt()).isEqualTo(now);
+
+ CharacteristicDto dto1 = characteristicArgument.getAllValues().get(0);
+ assertThat(dto1.getId()).isEqualTo(1);
+ assertThat(dto1.getKey()).isEqualTo("PORTABILITY");
+ assertThat(dto1.getName()).isEqualTo("Portability");
+ assertThat(dto1.getParentId()).isNull();
+ assertThat(dto1.getOrder()).isEqualTo(1);
+ assertThat(dto1.getCreatedAt()).isEqualTo(oldDate);
+ assertThat(dto1.getUpdatedAt()).isEqualTo(now);
+
+ CharacteristicDto dto2 = characteristicArgument.getAllValues().get(1);
+ assertThat(dto2.getId()).isEqualTo(2);
+ assertThat(dto2.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(dto2.getName()).isEqualTo("Compiler");
+ assertThat(dto2.getParentId()).isEqualTo(1);
+ assertThat(dto2.getOrder()).isNull();
+ assertThat(dto2.getCreatedAt()).isEqualTo(oldDate);
+ assertThat(dto2.getUpdatedAt()).isEqualTo(now);
}
@Test
new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate)
));
- when(ruleDao.selectOverridingDebt(session)).thenReturn(newArrayList(
+ when(ruleDao.selectOverridingDebt(Collections.<String>emptyList(), session)).thenReturn(newArrayList(
new RuleDto().setCharacteristicId(10).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("15min")
.setCreatedAt(oldDate).setUpdatedAt(oldDate)
));
- debtModelRestore.restoreFromProvidedModel();
+ debtModelRestore.restore();
verify(dao).selectEnabledCharacteristics();
verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
verifyNoMoreInteractions(dao);
- verify(ruleDao).selectOverridingDebt(session);
+ verify(ruleDao).selectOverridingDebt(Collections.<String>emptyList(), session);
ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
verify(ruleDao).update(ruleArgument.capture(), eq(session));
verifyNoMoreInteractions(ruleDao);
verify(session).commit();
}
+
+ @Test
+ public void restore_from_language() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ defaultModel
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability updated").setOrder(2).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate)
+ ));
+
+ when(ruleDao.selectOverridingDebt(newArrayList("squid"), session)).thenReturn(newArrayList(
+ new RuleDto().setRepositoryKey("squid")
+ .setCharacteristicId(10).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("15min")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ));
+
+ RuleRepositories.Repository squid = mock(RuleRepositories.Repository.class);
+ when(squid.getKey()).thenReturn("squid");
+ when(ruleRepositories.repositoriesForLang("java")).thenReturn(newArrayList(squid));
+
+ debtModelRestore.restore("java");
+
+ verify(dao).selectEnabledCharacteristics();
+ verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
+ verifyNoMoreInteractions(dao);
+
+ verify(ruleDao).selectOverridingDebt(newArrayList("squid"), session);
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(session));
+ verifyNoMoreInteractions(ruleDao);
+
+ verify(session).commit();
+ }
}
@Test
public void restore_provided_model() {
service.restore();
- verify(debtModelRestore).restoreFromProvidedModel();
+ verify(debtModelRestore).restore();
+ }
+
+ @Test
+ public void restore_from_language() {
+ service.restore("xoo");
+ verify(debtModelRestore).restore("xoo");
}
}