import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.check.Cardinality;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
public final class RuleDto {
- public static final Integer DISABLED_CHARACTERISTIC_ID = -1;
-
private Integer id;
private String repositoryKey;
private String ruleKey;
}
public boolean hasCharacteristic(){
- return (characteristicId != null && !DISABLED_CHARACTERISTIC_ID.equals(characteristicId)) || defaultCharacteristicId != null;
+ return (characteristicId != null && !CharacteristicDto.DISABLED_CHARACTERISTIC_ID.equals(characteristicId)) || defaultCharacteristicId != null;
}
@Override
import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
import javax.annotation.CheckForNull;
import javax.xml.stream.XMLInputFactory;
if ("linear_threshold".equals(functionKey)) {
function.setTextValue(DefaultRequirement.FUNCTION_LINEAR);
offset.setValue(0);
- offset.setTextValue(CharacteristicDto.DAYS);
+ offset.setTextValue("d");
messages.addWarningText(String.format("Linear with threshold function is no longer used, function of the requirement '%s' is replaced by linear.", requirement.ruleKey()));
} else if ("constant_resource".equals(functionKey)) {
messages.addWarningText(String.format("Constant/file function is no longer used, requirements '%s' are ignored.", requirement.ruleKey()));
}
/**
- * @return enabled root characteristics, characteristics and requirements
+ * @return enabled root characteristics and characteristics
*
*/
public List<CharacteristicDto> selectEnabledCharacteristics() {
public class CharacteristicDto implements Serializable {
- public static final String DAYS = "d";
- public static final String MINUTES = "mn";
- public static final String HOURS = "h";
+ public static final Integer DISABLED_CHARACTERISTIC_ID = -1;
private Integer id;
private String kee;
return this;
}
- @CheckForNull
public String getKey() {
return kee;
}
- public CharacteristicDto setKey(@Nullable String s) {
+ public CharacteristicDto setKey(String s) {
this.kee = s;
return this;
}
- @CheckForNull
public String getName() {
return name;
}
- public CharacteristicDto setName(@Nullable String s) {
+ public CharacteristicDto setName(String s) {
this.name = s;
return this;
}
import org.sonar.server.startup.RegisterDebtModel;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import java.util.*;
.setUpdatedAt(buffer.now())
.setStatus(ruleDef.status().name());
- CharacteristicDto characteristic = findCharacteristic(characteristicDtos, ruleDef);
- ruleDto.setDefaultCharacteristicId(characteristic != null ? characteristic.getId() : null)
- .setEffortToFixL10nKey(ruleDef.effortToFixL10nKey());
-
+ CharacteristicDto characteristic = findCharacteristic(ruleDef, null, characteristicDtos);
DebtRemediationFunction remediationFunction = ruleDef.debtRemediationFunction();
- if (remediationFunction != null) {
- ruleDto.setDefaultRemediationFunction(remediationFunction.type().name());
- ruleDto.setDefaultRemediationFactor(remediationFunction.factor());
- ruleDto.setDefaultRemediationOffset(remediationFunction.offset());
+ if (characteristic != null && remediationFunction != null) {
+ ruleDto.setDefaultCharacteristicId(characteristic.getId())
+ .setDefaultRemediationFunction(remediationFunction.type().name())
+ .setDefaultRemediationFactor(remediationFunction.factor())
+ .setDefaultRemediationOffset(remediationFunction.offset())
+ .setEffortToFixL10nKey(ruleDef.effortToFixL10nKey());
}
ruleDao.insert(ruleDto, sqlSession);
private boolean mergeDebtDefinitions(RulesDefinition.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) {
boolean changed = false;
- CharacteristicDto characteristic = findCharacteristic(characteristicDtos, def);
+ CharacteristicDto characteristic = findCharacteristic(def, dto.getCharacteristicId(), characteristicDtos);
// Debt definitions are set to null if the characteristic is null or unknown
+ boolean hasCharacteristic = characteristic != null;
+ DebtRemediationFunction debtRemediationFunction = characteristic != null ? def.debtRemediationFunction() : null;
Integer characteristicId = characteristic != null ? characteristic.getId() : null;
- DebtRemediationFunction debtRemediationFunction = def.debtRemediationFunction();
- String remediationFactor = debtRemediationFunction != null ? debtRemediationFunction.factor() : null;
- String remediationOffset = debtRemediationFunction != null ? debtRemediationFunction.offset() : null;
- String effortToFixL10nKey = def.effortToFixL10nKey();
+ String remediationFactor = hasCharacteristic ? debtRemediationFunction.factor() : null;
+ String remediationOffset = hasCharacteristic ? debtRemediationFunction.offset() : null;
+ String effortToFixL10nKey = hasCharacteristic ? def.effortToFixL10nKey() : null;
if (!ObjectUtils.equals(dto.getDefaultCharacteristicId(), characteristicId)) {
dto.setDefaultCharacteristicId(characteristicId);
}
@CheckForNull
- private CharacteristicDto findCharacteristic(List<CharacteristicDto> characteristicDtos, RulesDefinition.Rule ruleDef) {
- final String key = ruleDef.debtCharacteristic();
+ private CharacteristicDto findCharacteristic(RulesDefinition.Rule ruleDef, @Nullable Integer overridingCharacteristicId, List<CharacteristicDto> characteristicDtos) {
+ String key = ruleDef.debtCharacteristic();
+ // Rule is not linked to a default characteristic or characteristic has been disabled by user, nothing to do
if (key == null) {
- // Rule is not linked to a characteristic, nothing to do
return null;
}
- CharacteristicDto characteristicDto = Iterables.find(characteristicDtos, new Predicate<CharacteristicDto>() {
- @Override
- public boolean apply(CharacteristicDto input) {
- String characteristicKey = input.getKey();
- return characteristicKey != null && characteristicKey.equals(key);
- }
- }, null);
-
+ CharacteristicDto characteristicDto = findCharacteristic(key, characteristicDtos);
if (characteristicDto == null) {
- LOG.warn(String.format("Characteristic '%s' has not been found on rule '%s:%s'",
- key, ruleDef.repository().name(), ruleDef.key()));
+ // Log a warning only if rule has not been overridden by user
+ if (overridingCharacteristicId == null) {
+ LOG.warn(String.format("Characteristic '%s' has not been found on rule '%s:%s'", key, ruleDef.repository().key(), ruleDef.key()));
+ }
} else if (characteristicDto.getParentId() == null) {
- throw MessageException.of(String.format("Rule '%s:%s' cannot be linked on the root characteristic '%s'",
- ruleDef.repository().name(), ruleDef.key(), key));
+ throw MessageException.of(String.format("Rule '%s:%s' cannot be linked on the root characteristic '%s'", ruleDef.repository().key(), ruleDef.key(), key));
}
return characteristicDto;
}
+
+ @CheckForNull
+ private CharacteristicDto findCharacteristic(final String key, List<CharacteristicDto> characteristicDtos) {
+ return Iterables.find(characteristicDtos, new Predicate<CharacteristicDto>() {
+ @Override
+ public boolean apply(CharacteristicDto input) {
+ return key.equals(input.getKey());
+ }
+ }, null);
+ }
}
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.Database;
-import org.sonar.core.rule.RuleDto;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
import org.sonar.core.technicaldebt.db.RequirementDao;
import org.sonar.core.technicaldebt.db.RequirementDto;
import org.sonar.server.db.migrations.MassUpdater;
if (enabledRequirement == null && !Rule.STATUS_REMOVED.equals(ruleRow.getStatus())) {
// If no requirements are enable, it means that the requirement has been disabled for this rule
- updateStatement.setInt(1, RuleDto.DISABLED_CHARACTERISTIC_ID);
+ updateStatement.setInt(1, CharacteristicDto.DISABLED_CHARACTERISTIC_ID);
updateStatement.setNull(2, Types.VARCHAR);
updateStatement.setNull(3, Types.VARCHAR);
updateStatement.setNull(4, Types.VARCHAR);
}
@Test
- public void set_no_characteristic_when_characteristic_not_found() {
+ public void set_no_default_characteristic_when_characteristic_not_found() {
setupData("set_no_characteristic_when_characteristic_not_found");
+
task.start();
+ // Warning log should be displayed
checkTables("set_no_characteristic_when_characteristic_not_found", EXCLUDED_COLUMN_NAMES, "rules");
}
+ @Test
+ public void set_no_default_characteristic_when_default_characteristic_not_found_and_overriding_characteristic_disabled() {
+ setupData("set_no_characteristic_when_default_characteristic_not_found_and_overriding_characteristic_disabled");
+
+ task.start();
+ // No log should be displayed
+
+ checkTables("set_no_characteristic_when_default_characteristic_not_found_and_overriding_characteristic_disabled", EXCLUDED_COLUMN_NAMES, "rules");
+ }
+
+ @Test
+ public void set_no_default_characteristic_when_default_characteristic_not_found_but_characteristic_has_been_overridden() {
+ setupData("set_no_default_characteristic_when_default_characteristic_not_found_but_characteristic_has_been_overridden");
+
+ task.start();
+ // No log should be displayed
+
+ checkTables("set_no_default_characteristic_when_default_characteristic_not_found_but_characteristic_has_been_overridden", EXCLUDED_COLUMN_NAMES, "rules");
+ }
+
@Test
public void fail_when_rule_is_linked_on_root_characteristic() {
setupData("ignore_rule_debt_definitions_if_rule_is_linked_on_root_characteristic");
<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="LINEAR_OFFSET"
- remediation_factor="[null]" default_remediation_factor="5d"
- remediation_offset="[null]" default_remediation_offset="10h"
- effort_to_fix_l10n_key="squid.S115.effortToFix"/>
+ 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"
--- /dev/null
+<dataset>
+
+ <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="-1" 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>
--- /dev/null
+<dataset>
+
+ <characteristics id="999" kee="NEW" name="New" parent_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="-1" 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="old_config_key2" name="old name2" description="old description2"
+ status="READY" priority="1" cardinality="SINGLE" parent_id="[null]"
+ 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>
--- /dev/null
+<dataset>
+
+ <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="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]"
+ 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>
--- /dev/null
+<dataset>
+
+ <!-- User has removed the default characteristic used by rule1 and linked it to a a new characteristic-->
+ <characteristics id="2" kee="MEMORY_EFFICIENCY" name="Memory Efficiency" parent_id="1" characteristic_order="1" enabled="[false]"/>
+ <characteristics id="3" kee="COMPILER" name="Compiler" parent_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="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]"
+ 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]"
+ 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>