@@ -94,7 +94,7 @@ public class MaintainabilityMeasuresVisitor extends PathAwareVisitorAdapter<Main | |||
private long computeDevelopmentCost(Component file) { | |||
Optional<Measure> measure = measureRepository.getRawMeasure(file, nclocMetric); | |||
long ncloc = measure.map(Measure::getIntValue).orElse(0); | |||
return ncloc * ratingSettings.getDevCost(file.getFileAttributes().getLanguageKey()); | |||
return ncloc * ratingSettings.getDevCost(); | |||
} | |||
private void computeAndSaveMeasures(Component component, Path<Counter> path) { |
@@ -22,10 +22,10 @@ package org.sonar.ce.task.projectanalysis.qualitymodel; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.utils.KeyValueFormat; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.utils.KeyValueFormat; | |||
import org.sonar.ce.task.projectanalysis.component.Component; | |||
import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit; | |||
import org.sonar.ce.task.projectanalysis.component.PathAwareVisitorAdapter; | |||
@@ -159,7 +159,7 @@ public class NewMaintainabilityMeasuresVisitor extends PathAwareVisitorAdapter<N | |||
private void initNewDebtRatioCounter(Counter devCostCounter, Component file, Measure nclocDataMeasure, Set<Integer> changedLines) { | |||
boolean hasDevCost = false; | |||
long lineDevCost = ratingSettings.getDevCost(file.getFileAttributes().getLanguageKey()); | |||
long lineDevCost = ratingSettings.getDevCost(); | |||
for (Integer nclocLineIndex : nclocLineIndexes(nclocDataMeasure)) { | |||
if (changedLines.contains(nclocLineIndex)) { | |||
devCostCounter.incrementDevCost(lineDevCost); |
@@ -19,73 +19,31 @@ | |||
*/ | |||
package org.sonar.ce.task.projectanalysis.qualitymodel; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.ce.ComputeEngineSide; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.server.measure.DebtRatingGrid; | |||
import static java.lang.String.format; | |||
import static org.sonar.api.CoreProperties.DEVELOPMENT_COST; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY; | |||
@ComputeEngineSide | |||
public class RatingSettings { | |||
private final DebtRatingGrid ratingGrid; | |||
private final long defaultDevCost; | |||
private final Map<String, LanguageSpecificConfiguration> languageSpecificConfigurationByLanguageKey; | |||
public RatingSettings(Configuration config) { | |||
ratingGrid = new DebtRatingGrid(config); | |||
defaultDevCost = initDefaultDevelopmentCost(config); | |||
languageSpecificConfigurationByLanguageKey = initLanguageSpecificConfigurationByLanguageKey(config); | |||
} | |||
public DebtRatingGrid getDebtRatingGrid() { | |||
return ratingGrid; | |||
} | |||
public long getDevCost(@Nullable String languageKey) { | |||
if (languageKey != null) { | |||
try { | |||
LanguageSpecificConfiguration languageSpecificConfig = getSpecificParametersForLanguage(languageKey); | |||
if (languageSpecificConfig != null && languageSpecificConfig.getManDays() != null) { | |||
return Long.parseLong(languageSpecificConfig.getManDays()); | |||
} | |||
} catch (NumberFormatException e) { | |||
throw new IllegalArgumentException(format("The manDays for language %s is not a valid long number", languageKey), e); | |||
} | |||
} | |||
public long getDevCost() { | |||
return defaultDevCost; | |||
} | |||
@CheckForNull | |||
private LanguageSpecificConfiguration getSpecificParametersForLanguage(String languageKey) { | |||
return languageSpecificConfigurationByLanguageKey.get(languageKey); | |||
} | |||
private static Map<String, LanguageSpecificConfiguration> initLanguageSpecificConfigurationByLanguageKey(Configuration config) { | |||
ImmutableMap.Builder<String, LanguageSpecificConfiguration> builder = ImmutableMap.builder(); | |||
String[] languageConfigIndexes = config.getStringArray(LANGUAGE_SPECIFIC_PARAMETERS); | |||
for (String languageConfigIndex : languageConfigIndexes) { | |||
String languagePropertyKey = LANGUAGE_SPECIFIC_PARAMETERS + "." + languageConfigIndex + "." + LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY; | |||
String languageKey = config.get(languagePropertyKey) | |||
.orElseThrow(() -> MessageException.of("Technical debt configuration is corrupted. At least one language specific parameter has no Language key. " + | |||
"Contact your administrator to update this configuration in the global administration section of SonarQube.")); | |||
builder.put(languageKey, LanguageSpecificConfiguration.create(config, languageConfigIndex)); | |||
} | |||
return builder.build(); | |||
} | |||
private static long initDefaultDevelopmentCost(Configuration config) { | |||
try { | |||
return Long.parseLong(config.get(DEVELOPMENT_COST).get()); | |||
@@ -95,39 +53,4 @@ public class RatingSettings { | |||
} | |||
} | |||
@Immutable | |||
private static class LanguageSpecificConfiguration { | |||
private final String language; | |||
private final String manDays; | |||
private final String metricKey; | |||
private LanguageSpecificConfiguration(String language, String manDays, String metricKey) { | |||
this.language = language; | |||
this.manDays = manDays; | |||
this.metricKey = metricKey; | |||
} | |||
static LanguageSpecificConfiguration create(Configuration config, String configurationId) { | |||
String configurationPrefix = LANGUAGE_SPECIFIC_PARAMETERS + "." + configurationId + "."; | |||
String language = config.get(configurationPrefix + LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY).orElse(null); | |||
String manDays = config.get(configurationPrefix + LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY).orElse(null); | |||
String metric = config.get(configurationPrefix + LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY).orElse(null); | |||
return new LanguageSpecificConfiguration(language, manDays, metric); | |||
} | |||
String getLanguage() { | |||
return language; | |||
} | |||
String getManDays() { | |||
return manDays; | |||
} | |||
String getMetricKey() { | |||
return metricKey; | |||
} | |||
} | |||
} |
@@ -68,8 +68,7 @@ public class MaintainabilityMeasuresVisitorTest { | |||
static final double[] RATING_GRID = new double[] {0.1, 0.2, 0.5, 1}; | |||
static final long DEV_COST_LANGUAGE_1 = 30; | |||
static final long DEV_COST_LANGUAGE_2 = 42; | |||
static final long DEV_COST = 30; | |||
static final int PROJECT_REF = 1; | |||
static final int DIRECTORY_REF = 123; | |||
@@ -111,8 +110,7 @@ public class MaintainabilityMeasuresVisitorTest { | |||
public void setUp() { | |||
// assumes rating configuration is consistent | |||
when(ratingSettings.getDebtRatingGrid()).thenReturn(new DebtRatingGrid(RATING_GRID)); | |||
when(ratingSettings.getDevCost(LANGUAGE_KEY_1)).thenReturn(DEV_COST_LANGUAGE_1); | |||
when(ratingSettings.getDevCost(LANGUAGE_KEY_2)).thenReturn(DEV_COST_LANGUAGE_2); | |||
when(ratingSettings.getDevCost()).thenReturn(DEV_COST); | |||
underTest = new VisitorsCrawler(singletonList(new MaintainabilityMeasuresVisitor(metricRepository, measureRepository, ratingSettings))); | |||
} | |||
@@ -167,26 +165,26 @@ public class MaintainabilityMeasuresVisitorTest { | |||
underTest.visit(root); | |||
// verify measures on files | |||
verifyAddedRawMeasure(1112, DEVELOPMENT_COST_KEY, Long.toString(ncloc1112 * DEV_COST_LANGUAGE_2)); | |||
verifyAddedRawMeasure(1113, DEVELOPMENT_COST_KEY, Long.toString(ncloc1113 * DEV_COST_LANGUAGE_1)); | |||
verifyAddedRawMeasure(1121, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST_LANGUAGE_2)); | |||
verifyAddedRawMeasure(1211, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1)); | |||
verifyAddedRawMeasure(1112, DEVELOPMENT_COST_KEY, Long.toString(ncloc1112 * DEV_COST)); | |||
verifyAddedRawMeasure(1113, DEVELOPMENT_COST_KEY, Long.toString(ncloc1113 * DEV_COST)); | |||
verifyAddedRawMeasure(1121, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST)); | |||
verifyAddedRawMeasure(1211, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST)); | |||
// directory has no children => no file => 0 everywhere and A rating | |||
verifyAddedRawMeasure(122, DEVELOPMENT_COST_KEY, "0"); | |||
// directory has children => dev cost is aggregated | |||
verifyAddedRawMeasure(111, DEVELOPMENT_COST_KEY, Long.toString( | |||
ncloc1112 * DEV_COST_LANGUAGE_2 + | |||
ncloc1113 * DEV_COST_LANGUAGE_1)); | |||
verifyAddedRawMeasure(112, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST_LANGUAGE_2)); | |||
verifyAddedRawMeasure(121, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1)); | |||
ncloc1112 * DEV_COST + | |||
ncloc1113 * DEV_COST)); | |||
verifyAddedRawMeasure(112, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST)); | |||
verifyAddedRawMeasure(121, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST)); | |||
verifyAddedRawMeasure(1, DEVELOPMENT_COST_KEY, Long.toString( | |||
ncloc1112 * DEV_COST_LANGUAGE_2 + | |||
ncloc1113 * DEV_COST_LANGUAGE_1 + | |||
nclocValue1121 * DEV_COST_LANGUAGE_2 + | |||
ncloc1211 * DEV_COST_LANGUAGE_1)); | |||
ncloc1112 * DEV_COST + | |||
ncloc1113 * DEV_COST + | |||
nclocValue1121 * DEV_COST + | |||
ncloc1211 * DEV_COST)); | |||
} | |||
@Test | |||
@@ -211,10 +209,10 @@ public class MaintainabilityMeasuresVisitorTest { | |||
underTest.visit(ROOT_PROJECT); | |||
verifyAddedRawMeasure(FILE_1_REF, SQALE_DEBT_RATIO_KEY, file1MaintainabilityCost * 1d / (file1Ncloc * DEV_COST_LANGUAGE_1) * 100); | |||
verifyAddedRawMeasure(FILE_2_REF, SQALE_DEBT_RATIO_KEY, file2MaintainabilityCost * 1d / (file2Ncloc * DEV_COST_LANGUAGE_1) * 100); | |||
verifyAddedRawMeasure(DIRECTORY_REF, SQALE_DEBT_RATIO_KEY, directoryMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100); | |||
verifyAddedRawMeasure(PROJECT_REF, SQALE_DEBT_RATIO_KEY, projectMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100); | |||
verifyAddedRawMeasure(FILE_1_REF, SQALE_DEBT_RATIO_KEY, file1MaintainabilityCost * 1d / (file1Ncloc * DEV_COST) * 100); | |||
verifyAddedRawMeasure(FILE_2_REF, SQALE_DEBT_RATIO_KEY, file2MaintainabilityCost * 1d / (file2Ncloc * DEV_COST) * 100); | |||
verifyAddedRawMeasure(DIRECTORY_REF, SQALE_DEBT_RATIO_KEY, directoryMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST) * 100); | |||
verifyAddedRawMeasure(PROJECT_REF, SQALE_DEBT_RATIO_KEY, projectMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST) * 100); | |||
} | |||
@Test | |||
@@ -261,13 +259,13 @@ public class MaintainabilityMeasuresVisitorTest { | |||
underTest.visit(ROOT_PROJECT); | |||
verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, | |||
(long) (file1Effort - RATING_GRID[0] * file1Ncloc * DEV_COST_LANGUAGE_1)); | |||
(long) (file1Effort - RATING_GRID[0] * file1Ncloc * DEV_COST)); | |||
verifyAddedRawMeasure(FILE_2_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, | |||
(long) (file2Effort - RATING_GRID[0] * file2Ncloc * DEV_COST_LANGUAGE_1)); | |||
(long) (file2Effort - RATING_GRID[0] * file2Ncloc * DEV_COST)); | |||
verifyAddedRawMeasure(DIRECTORY_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, | |||
(long) (dirEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1)); | |||
(long) (dirEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST)); | |||
verifyAddedRawMeasure(PROJECT_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, | |||
(long) (projectEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1)); | |||
(long) (projectEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST)); | |||
} | |||
@Test |
@@ -64,12 +64,12 @@ import static org.sonar.ce.task.projectanalysis.measure.MeasureAssert.assertThat | |||
import static org.sonar.server.measure.Rating.A; | |||
import static org.sonar.server.measure.Rating.D; | |||
public class NewMaintainabilityMeasuresVisitorTest { | |||
public class NewMaintainabilityMeasuresVisitorTest { | |||
private static final double[] RATING_GRID = new double[] {0.1, 0.2, 0.5, 1}; | |||
private static final double[] RATING_GRID = new double[]{0.1, 0.2, 0.5, 1}; | |||
private static final String LANGUAGE_1_KEY = "language 1 key"; | |||
private static final long LANGUAGE_1_DEV_COST = 30L; | |||
private static final long DEV_COST = 30L; | |||
private static final int ROOT_REF = 1; | |||
private static final int LANGUAGE_1_FILE_REF = 11111; | |||
private static final Offset<Double> VALUE_COMPARISON_OFFSET = Offset.offset(0.01); | |||
@@ -94,6 +94,7 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Before | |||
public void setUp() { | |||
when(ratingSettings.getDebtRatingGrid()).thenReturn(new DebtRatingGrid(RATING_GRID)); | |||
when(ratingSettings.getDevCost()).thenReturn(DEV_COST); | |||
underTest = new VisitorsCrawler(Arrays.asList(new NewMaintainabilityMeasuresVisitor(metricRepository, measureRepository, newLinesRepository, ratingSettings))); | |||
} | |||
@@ -122,7 +123,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void file_has_no_new_debt_ratio_variation_if_new_lines_not_available() { | |||
when(newLinesRepository.newLinesAvailable()).thenReturn(false); | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.NO_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50)); | |||
@@ -152,7 +152,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void file_has_new_debt_ratio_if_some_lines_are_new() { | |||
when(newLinesRepository.newLinesAvailable()).thenReturn(true); | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50)); | |||
@@ -164,7 +163,7 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_changes_with_language_cost() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST * 10); | |||
when(ratingSettings.getDevCost()).thenReturn(DEV_COST * 10); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50)); | |||
@@ -176,7 +175,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_changes_with_new_technical_debt() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(500, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(500)); | |||
@@ -188,7 +186,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_on_non_file_level_is_based_on_new_technical_debt_of_that_level() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(500, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(1200)); | |||
@@ -200,7 +197,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_when_file_is_unit_test() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(500, Flag.UT_FILE, Flag.WITH_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(1200)); | |||
@@ -213,7 +209,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_is_0_when_file_has_no_new_lines() { | |||
when(newLinesRepository.newLinesAvailable()).thenReturn(true); | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.NO_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50)); | |||
@@ -226,7 +221,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_is_0_on_non_file_level_when_no_file_has_new_lines() { | |||
when(newLinesRepository.newLinesAvailable()).thenReturn(true); | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.NO_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(200)); | |||
@@ -238,7 +232,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_is_0_when_there_is_no_ncloc_in_file() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.NO_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50)); | |||
@@ -250,7 +243,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_is_0_on_non_file_level_when_one_file_has_zero_new_debt_because_of_no_changeset() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.NO_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(200)); | |||
@@ -262,7 +254,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void new_debt_ratio_is_0_when_ncloc_measure_is_missing() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.MISSING_MEASURE_NCLOC, Flag.WITH_NEW_LINES); | |||
measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50)); | |||
@@ -274,7 +265,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void leaf_components_always_have_a_measure_when_at_least_one_period_exist_and_ratio_is_computed_from_current_level_new_debt() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
Component file = builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 1)).build(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, ROOT_REF) | |||
@@ -301,7 +291,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
@Test | |||
public void compute_new_maintainability_rating() { | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
ReportComponent file = builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 1)).build(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, ROOT_REF) | |||
@@ -332,7 +321,6 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
public void compute_new_development_cost() { | |||
ReportComponent file1 = builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 4)).build(); | |||
ReportComponent file2 = builder(FILE, 22_222).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 6)).build(); | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, ROOT_REF) | |||
.addChildren( | |||
@@ -353,15 +341,14 @@ public class NewMaintainabilityMeasuresVisitorTest { | |||
underTest.visit(treeRootHolder.getRoot()); | |||
assertNewDevelopmentCostValues(ROOT_REF, 5 * LANGUAGE_1_DEV_COST); | |||
assertNewDevelopmentCostValues(LANGUAGE_1_FILE_REF, 2 * LANGUAGE_1_DEV_COST); | |||
assertNewDevelopmentCostValues(22_222, 3 * LANGUAGE_1_DEV_COST); | |||
assertNewDevelopmentCostValues(ROOT_REF, 5 * DEV_COST); | |||
assertNewDevelopmentCostValues(LANGUAGE_1_FILE_REF, 2 * DEV_COST); | |||
assertNewDevelopmentCostValues(22_222, 3 * DEV_COST); | |||
} | |||
@Test | |||
public void compute_new_maintainability_rating_to_A_when_no_debt() { | |||
when(newLinesRepository.newLinesAvailable()).thenReturn(true); | |||
when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, ROOT_REF) | |||
.addChildren( |
@@ -23,23 +23,17 @@ import org.junit.Test; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.config.CorePropertyDefinitions; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.sonar.api.CoreProperties.DEVELOPMENT_COST; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY; | |||
public class RatingSettingsTest { | |||
private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all())); | |||
@Test | |||
public void load_rating_grid() { | |||
settings.setProperty(CoreProperties.RATING_GRID, "1,3.4,8,50"); | |||
@@ -54,31 +48,11 @@ public class RatingSettingsTest { | |||
} | |||
@Test | |||
public void load_work_units_for_language() { | |||
public void load_dev_cost() { | |||
settings.setProperty(DEVELOPMENT_COST, "50"); | |||
RatingSettings configurationLoader = new RatingSettings(settings.asConfig()); | |||
assertThat(configurationLoader.getDevCost("defaultLanguage")).isEqualTo(50L); | |||
} | |||
@Test | |||
public void load_overridden_values_for_language() { | |||
String aLanguage = "aLanguage"; | |||
String anotherLanguage = "anotherLanguage"; | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS, "0,1"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, aLanguage); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "30"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY, CoreMetrics.NCLOC_KEY); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, anotherLanguage); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "40"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY, CoreMetrics.COMPLEXITY_KEY); | |||
RatingSettings configurationLoader = new RatingSettings(settings.asConfig()); | |||
assertThat(configurationLoader.getDevCost(aLanguage)).isEqualTo(30L); | |||
assertThat(configurationLoader.getDevCost(anotherLanguage)).isEqualTo(40L); | |||
assertThat(configurationLoader.getDevCost()).isEqualTo(50L); | |||
} | |||
@Test | |||
@@ -91,29 +65,4 @@ public class RatingSettingsTest { | |||
} | |||
@Test | |||
public void use_generic_value_when_specific_setting_is_missing() { | |||
String aLanguage = "aLanguage"; | |||
settings.setProperty(DEVELOPMENT_COST, "30"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS, "0"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, aLanguage); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "40"); | |||
RatingSettings configurationLoader = new RatingSettings(settings.asConfig()); | |||
assertThat(configurationLoader.getDevCost(aLanguage)).isEqualTo(40L); | |||
} | |||
@Test | |||
public void constructor_fails_with_ME_if_language_specific_parameter_language_is_missing() { | |||
settings.setProperty(DEVELOPMENT_COST, "30"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS, "0"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "40"); | |||
assertThatThrownBy(() -> new RatingSettings(settings.asConfig())) | |||
.isInstanceOf(MessageException.class) | |||
.hasMessage("Technical debt configuration is corrupted. At least one language specific parameter has no Language key. " + | |||
"Contact your administrator to update this configuration in the global administration section of SonarQube."); | |||
} | |||
} |
@@ -0,0 +1,86 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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.platform.db.migration.version.v105; | |||
import java.sql.SQLException; | |||
import org.assertj.core.api.Assertions; | |||
import org.junit.jupiter.api.Test; | |||
import org.junit.jupiter.api.extension.RegisterExtension; | |||
import org.sonar.db.MigrationDbTester; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
class DeleteLanguageSpecificParametersPropertySetIT { | |||
@RegisterExtension | |||
public final MigrationDbTester db = MigrationDbTester.createForMigrationStep(DeleteLanguageSpecificParametersPropertySet.class); | |||
private final DataChange underTest = new DeleteLanguageSpecificParametersPropertySet(db.database()); | |||
@Test | |||
void migration_should_remove_root_property_and_children() throws SQLException { | |||
insertLanguageSpecificParametersPropertySet(db); | |||
underTest.execute(); | |||
Assertions.assertThat(db.select("select * from properties")).isEmpty(); | |||
} | |||
@Test | |||
void migration_is_reentrant() throws SQLException { | |||
insertLanguageSpecificParametersPropertySet(db); | |||
underTest.execute(); | |||
underTest.execute(); | |||
Assertions.assertThat(db.select("select * from properties")).isEmpty(); | |||
} | |||
private void insertLanguageSpecificParametersPropertySet(MigrationDbTester db) { | |||
db.executeInsert("properties ", | |||
"prop_key", "languageSpecificParameters", | |||
"is_empty", false, | |||
"text_value", "0,1", | |||
"created_at", 100_000L, | |||
"uuid", "some-random-uuid1"); | |||
db.executeInsert("properties ", | |||
"prop_key", "languageSpecificParameters.0.language", | |||
"is_empty", false, | |||
"text_value", "java", | |||
"created_at", 100_000L, | |||
"uuid", "some-random-uuid2"); | |||
db.executeInsert("properties ", | |||
"prop_key", "languageSpecificParameters.0.man_days", | |||
"is_empty", false, | |||
"text_value", "10", | |||
"created_at", 100_000L, | |||
"uuid", "some-random-uuid3"); | |||
db.executeInsert("properties ", | |||
"prop_key", "languageSpecificParameters.1.language", | |||
"is_empty", false, | |||
"text_value", "php", | |||
"created_at", 100_000L, | |||
"uuid", "some-random-uuid4"); | |||
db.executeInsert("properties ", | |||
"prop_key", "languageSpecificParameters.1.man_days", | |||
"is_empty", false, | |||
"text_value", "20", | |||
"created_at", 100_000L, | |||
"uuid", "some-random-uuid5"); | |||
} | |||
} |
@@ -46,6 +46,7 @@ public class DbVersion105 implements DbVersion { | |||
.add(10_5_002, "Drop column 'uuid' from 'issues_impacts' table", DropUuidColumnInIssuesImpactsTable.class) | |||
.add(10_5_003, "Drop column 'uuid' from 'rules_default_impacts' table", DropUuidColumnInRulesDefaultImpactsTable.class) | |||
.add(10_5_004, "Create primary key on 'issues_impacts' table", CreatePrimaryKeyOnIssuesImpactsTable.class) | |||
.add(10_5_005, "Create primary key on 'rules_default_impacts' table", CreatePrimaryKeyOnRulesDefaultImpactsTable.class); | |||
.add(10_5_005, "Create primary key on 'rules_default_impacts' table", CreatePrimaryKeyOnRulesDefaultImpactsTable.class) | |||
.add(10_5_006, "Delete 'languageSpecificParameters' property set from 'properties' table", DeleteLanguageSpecificParametersPropertySet.class); | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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.platform.db.migration.version.v105; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
public class DeleteLanguageSpecificParametersPropertySet extends DataChange { | |||
public DeleteLanguageSpecificParametersPropertySet(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
context.prepareUpsert("delete from properties where prop_key like ?") | |||
.setString(1, "languageSpecificParameters%") | |||
.execute() | |||
.commit(); | |||
} | |||
} |
@@ -2321,32 +2321,6 @@ export const definitions: ExtendedSettingDefinition[] = [ | |||
fields: [], | |||
deprecatedKey: 'workUnitsBySizePoint', | |||
}, | |||
{ | |||
key: 'languageSpecificParameters', | |||
name: 'Language specific parameters', | |||
description: | |||
'DEPRECATED - The parameters specified here for a given language will override the general parameters defined in this section.', | |||
type: SettingType.PROPERTY_SET, | |||
category: 'technicalDebt', | |||
subCategory: 'technicalDebt', | |||
options: [], | |||
fields: [ | |||
{ | |||
key: 'language', | |||
name: 'Language Key', | |||
description: 'Ex: java, cs, cpp...', | |||
options: [], | |||
}, | |||
{ | |||
key: 'man_days', | |||
name: 'Development cost', | |||
description: 'If left blank, the generic value defined in this section will be used.', | |||
type: SettingType.FLOAT, | |||
options: [], | |||
}, | |||
], | |||
deprecatedKey: 'languageSpecificParameters', | |||
}, | |||
{ | |||
key: 'sonar.technicalDebt.ratingGrid', | |||
name: 'Maintainability rating grid', |
@@ -1,57 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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.platform.db; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.config.Configuration; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS; | |||
/** | |||
* Checks if there are any language specific parameters set for calculating technical debt as functionality is deprecated from 9.9. | |||
* If found, it is logged as a warning. This requires to be defined in platform level 4 ({@link org.sonar.server.platform.platformlevel.PlatformLevel4}). | |||
*/ | |||
public class CheckLanguageSpecificParamsAtStartup implements Startable { | |||
private static final Logger LOG = LoggerFactory.getLogger(CheckLanguageSpecificParamsAtStartup.class); | |||
private final Configuration config; | |||
public CheckLanguageSpecificParamsAtStartup(Configuration config) { | |||
this.config = config; | |||
} | |||
@Override | |||
public void start() { | |||
String[] languageSpecificParams = config.getStringArray(LANGUAGE_SPECIFIC_PARAMETERS); | |||
if (languageSpecificParams.length > 0) { | |||
LOG.warn("The development cost used for calculating the technical debt is currently configured with {} language specific parameters [Key: languageSpecificParameters]. " + | |||
"Please be aware that this functionality is deprecated, and will be removed in a future version.", languageSpecificParams.length); | |||
} | |||
} | |||
@Override | |||
public void stop() { | |||
// do nothing | |||
} | |||
} |
@@ -1,81 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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.platform.db; | |||
import org.junit.After; | |||
import org.junit.ClassRule; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.slf4j.event.Level; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.testfixtures.log.LogTester; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.log.LoggerLevel; | |||
import org.sonar.db.DbTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY; | |||
import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY; | |||
public class CheckLanguageSpecificParamsAtStartupTest { | |||
@ClassRule | |||
public static LogTester logTester = new LogTester().setLevel(LoggerLevel.WARN); | |||
@Rule | |||
public final DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
private final MapSettings settings = new MapSettings(); | |||
private final CheckLanguageSpecificParamsAtStartup underTest = new CheckLanguageSpecificParamsAtStartup(settings.asConfig()); | |||
@After | |||
public void tearDown() { | |||
logTester.clear(); | |||
underTest.stop(); | |||
} | |||
@Test | |||
public void log_shows_when_language_specific_params_used() { | |||
String aLanguage = "aLanguage"; | |||
String anotherLanguage = "anotherLanguage"; | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS, "0,1"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, aLanguage); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "30"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY, CoreMetrics.NCLOC_KEY); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, anotherLanguage); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "40"); | |||
settings.setProperty(LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY, CoreMetrics.COMPLEXITY_KEY); | |||
underTest.start(); | |||
assertThat(logTester.logs(Level.WARN)) | |||
.contains("The development cost used for calculating the technical debt is currently configured with 2 language specific parameters [Key: languageSpecificParameters]. " + | |||
"Please be aware that this functionality is deprecated, and will be removed in a future version."); | |||
} | |||
@Test | |||
public void log_does_not_show_when_language_specific_params_used() { | |||
underTest.start(); | |||
boolean noneMatch = logTester.logs(Level.WARN).stream() | |||
.noneMatch(s -> s.startsWith("The development cost used for calculating the technical debt is currently configured with")); | |||
assertThat(noneMatch).isTrue(); | |||
} | |||
} |
@@ -179,7 +179,6 @@ import org.sonar.server.platform.PersistentSettings; | |||
import org.sonar.server.platform.SystemInfoWriterModule; | |||
import org.sonar.server.platform.WebCoreExtensionsInstaller; | |||
import org.sonar.server.platform.db.CheckAnyonePermissionsAtStartup; | |||
import org.sonar.server.platform.db.CheckLanguageSpecificParamsAtStartup; | |||
import org.sonar.server.platform.web.ActionDeprecationLoggerInterceptor; | |||
import org.sonar.server.platform.web.SonarLintConnectionFilter; | |||
import org.sonar.server.platform.web.WebServiceFilter; | |||
@@ -435,7 +434,6 @@ public class PlatformLevel4 extends PlatformLevel { | |||
UserPermissionChanger.class, | |||
GroupPermissionChanger.class, | |||
CheckAnyonePermissionsAtStartup.class, | |||
CheckLanguageSpecificParamsAtStartup.class, | |||
VisibilityService.class, | |||
// components |
@@ -34,7 +34,7 @@ class DebtProperties { | |||
static List<PropertyDefinition> all() { | |||
return List.of( | |||
PropertyDefinition.builder(CoreProperties.DEVELOPMENT_COST) | |||
.defaultValue("" + CoreProperties.DEVELOPMENT_COST_DEF_VALUE) | |||
.defaultValue(CoreProperties.DEVELOPMENT_COST_DEF_VALUE) | |||
.name("Development cost") | |||
.description("Cost to develop one line of code (LOC). Example: if the cost to develop 1 LOC has been estimated " + | |||
"at 30 minutes, then the value of this property would be 30.") | |||
@@ -43,7 +43,7 @@ class DebtProperties { | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.RATING_GRID) | |||
.defaultValue("" + CoreProperties.RATING_GRID_DEF_VALUES) | |||
.defaultValue(CoreProperties.RATING_GRID_DEF_VALUES) | |||
.name("Maintainability rating grid") | |||
.description("Maintainability ratings range from A (very good) to E (very bad). The rating is determined by the value of " + | |||
"the Technical Debt Ratio, which compares the technical debt on a project to the cost it would take to rewrite " + | |||
@@ -52,24 +52,6 @@ class DebtProperties { | |||
"2,500 LOC will have a technical debt ratio of 24000/(30 * 2,500) = 0.32. That yields a maintainability rating of D.") | |||
.category(CoreProperties.CATEGORY_TECHNICAL_DEBT) | |||
.deprecatedKey("ratingGrid") | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS) | |||
.name("Language specific parameters") | |||
.description("DEPRECATED - The parameters specified here for a given language will override the general parameters defined in this section.") | |||
.category(CoreProperties.CATEGORY_TECHNICAL_DEBT) | |||
.deprecatedKey("languageSpecificParameters") | |||
.fields( | |||
PropertyFieldDefinition.build(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY) | |||
.name("Language Key") | |||
.description("Ex: java, cs, cpp...") | |||
.type(PropertyType.STRING) | |||
.build(), | |||
PropertyFieldDefinition.build(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY) | |||
.name("Development cost") | |||
.description("If left blank, the generic value defined in this section will be used.") | |||
.type(PropertyType.FLOAT) | |||
.build()) | |||
.build()); | |||
} | |||
} |
@@ -26,9 +26,6 @@ public class QModelTester { | |||
private static final String DEV_COST_PROPERTY = "sonar.technicalDebt.developmentCost"; | |||
private static final String RATING_GRID_PROPERTY = "sonar.technicalDebt.ratingGrid"; | |||
private static final String DEV_COST_LANGUAGE_PROPERTY = "languageSpecificParameters"; | |||
private static final String DEV_COST_LANGUAGE_NAME_PROPERTY = DEV_COST_LANGUAGE_PROPERTY + ".0.language"; | |||
private static final String DEV_COST_LANGUAGE_COST_PROPERTY = DEV_COST_LANGUAGE_PROPERTY + ".0.man_days"; | |||
private static final Joiner COMMA_JOINER = Joiner.on(","); | |||
private final TesterSession session; | |||
@@ -41,18 +38,12 @@ public class QModelTester { | |||
session.settings().setGlobalSettings(DEV_COST_PROPERTY, Integer.toString(developmentCost)); | |||
} | |||
public void updateLanguageDevelopmentCost(String language, int developmentCost) { | |||
session.settings().setGlobalSettings(DEV_COST_LANGUAGE_PROPERTY, "0"); | |||
session.settings().setGlobalSettings(DEV_COST_LANGUAGE_NAME_PROPERTY, language); | |||
session.settings().setGlobalSettings(DEV_COST_LANGUAGE_COST_PROPERTY, Integer.toString(developmentCost)); | |||
} | |||
public void updateRatingGrid(Double... ratingGrid) { | |||
Preconditions.checkState(ratingGrid.length == 4, "Rating grid must contains 4 values"); | |||
session.settings().setGlobalSettings(RATING_GRID_PROPERTY, COMMA_JOINER.join(ratingGrid)); | |||
} | |||
public void reset() { | |||
session.settings().resetSettings(DEV_COST_LANGUAGE_PROPERTY, DEV_COST_LANGUAGE_NAME_PROPERTY, DEV_COST_LANGUAGE_COST_PROPERTY, RATING_GRID_PROPERTY, DEV_COST_PROPERTY); | |||
session.settings().resetSettings(RATING_GRID_PROPERTY, DEV_COST_PROPERTY); | |||
} | |||
} |