*/
public class DebtConfigurationRule extends ExternalResource {
- private static final String HOURS_IN_DAY_PROPERTY = "sonar.technicalDebt.hoursInDay";
private static final String DEV_COST_PROPERTY = "sonar.technicalDebt.developmentCost";
private static final String RATING_GRID_PROPERTY = "sonar.technicalDebt.ratingGrid";
}
public void reset() {
- resetHoursInDay();
resetDevelopmentCost();
resetRatingGrid();
}
- public DebtConfigurationRule updateHoursInDay(int hoursInDay) {
- setProperty(HOURS_IN_DAY_PROPERTY, Integer.toString(hoursInDay));
- return this;
- }
-
- public DebtConfigurationRule resetHoursInDay() {
- resetProperty(HOURS_IN_DAY_PROPERTY);
- return this;
- }
-
public DebtConfigurationRule updateDevelopmentCost(int developmentCost) {
setProperty(DEV_COST_PROPERTY, Integer.toString(developmentCost));
return this;
@Before
public void deleteAnalysisData() {
orchestrator.resetData();
-
- // Set hours in day property to 8
- debtConfiguration.updateHoursInDay(8);
}
@Test
import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
-import org.sonar.wsclient.issue.IssueClient;
import org.sonar.wsclient.issue.IssueQuery;
import static org.assertj.core.api.Assertions.assertThat;
@Before
public void deleteAnalysisData() {
orchestrator.resetData();
-
- // Set hours in day property to 8
- debtConfiguration.updateHoursInDay(8);
}
/**
}
}
- @Test
- public void use_hours_in_day_property_to_display_debt() throws Exception {
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/qualityModel/one-issue-per-file.xml"));
- orchestrator.getServer().provisionProject("sample", "sample");
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-file");
-
- // One day -> 10 hours
- debtConfiguration.updateHoursInDay(10);
-
- orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))
- // As OneIssuePerFile has a debt of 10 minutes, we multiply it by 72 to have 1 day and 2 hours of technical debt
- .setProperties("sonar.oneIssuePerFile.effortToFix", "72")
- );
-
- IssueClient issueClient = orchestrator.getServer().wsClient().issueClient();
- Issue issue = issueClient.find(IssueQuery.create()).list().get(0);
-
- assertThat(issue.debt()).isEqualTo("1d2h");
- }
-
- @Test
- public void use_hours_in_day_property_during_analysis_to_convert_debt() throws Exception {
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/qualityModel/one-day-debt-per-file.xml"));
- orchestrator.getServer().provisionProject("sample", "sample");
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-day-debt-per-file");
-
- // One day -> 10 hours : debt will be stored as 360.000 seconds (1 day * 10 hours per day * 60 * 60)
- debtConfiguration.updateHoursInDay(10);
-
- orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample")));
-
- // Issue debt was 1 day during analysis but will be displayed as 1 day and 2 hours (hours in day property was set
- // to 10 during analysis but is now 8)
- debtConfiguration.updateHoursInDay(8);
-
- IssueClient issueClient = orchestrator.getServer().wsClient().issueClient();
- Issue issue = issueClient.find(IssueQuery.create()).list().get(0);
- assertThat(issue.debt()).isEqualTo("1d2h");
- }
-
}
+ 25 // level 1
+ 47 // content of DaoModule
+ 3 // content of EsSearchModule
- + 63 // content of CorePropertyDefinitions
+ + 62 // content of CorePropertyDefinitions
+ 1 // content of CePropertyDefinitions
);
assertThat(picoContainer.getParent().getParent().getParent().getParent()).isNull();
}
private String formatDuration(String value) {
- return durations.format(Locale.ENGLISH, Duration.create(Long.parseLong(value)), Durations.DurationFormat.SHORT);
+ return durations.format(Duration.create(Long.parseLong(value)));
}
}
import com.google.common.collect.Multiset;
import java.util.Date;
import java.util.List;
-import java.util.Locale;
import org.sonar.api.notifications.Notification;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
}
public NewIssuesNotification setDebt(Duration debt) {
- setFieldValue(Metric.DEBT + COUNT, durations.format(Locale.ENGLISH, debt));
+ setFieldValue(Metric.DEBT + COUNT, durations.format(debt));
return this;
}
.setHandler(this);
action.createParam(PARAM_ID)
.setDescription("Setting key")
- .setExampleValue("sonar.technicalDebt.hoursInDay");
+ .setExampleValue("sonar.test.inclusions");
action.createParam(PARAM_COMPONENT)
.setDescription("Component key or database id")
.setExampleValue(KEY_PROJECT_EXAMPLE_001);
.setExampleValue(KEY_PROJECT_EXAMPLE_001);
action.createParam(PARAM_KEYS)
.setDescription("List of setting keys")
- .setExampleValue("sonar.technicalDebt.hoursInDay,sonar.dbcleaner.cleanDirectory");
+ .setExampleValue("sonar.test.inclusions,sonar.dbcleaner.cleanDirectory");
}
@Override
import org.sonar.db.dialect.H2;
import org.sonar.server.ui.PageRepository;
-import static org.sonar.api.CoreProperties.HOURS_IN_DAY;
import static org.sonar.api.CoreProperties.RATING_GRID;
import static org.sonar.core.config.WebConstants.SONAR_LF_ENABLE_GRAVATAR;
import static org.sonar.core.config.WebConstants.SONAR_LF_GRAVATAR_SERVER_URL;
SONAR_LF_ENABLE_GRAVATAR,
SONAR_LF_GRAVATAR_SERVER_URL,
SONAR_UPDATECENTER_ACTIVATE,
- HOURS_IN_DAY,
RATING_GRID);
private final PageRepository pageRepository;
"sonar.lf.enableGravatar": "true",
"sonar.lf.gravatarServerUrl": "http://some-server.tld/logo.png",
"sonar.updatecenter.activate": "false",
- "sonar.technicalDebt.hoursInDay": "10",
"sonar.technicalDebt.ratingGrid": "0.05,0.1,0.2,0.5"
},
"logoUrl": "http://example.com/my-custom-logo.png",
package org.sonar.server.computation.task.projectanalysis.issue;
import org.junit.Test;
-import org.sonar.api.config.MapSettings;
-import org.sonar.api.i18n.I18n;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
import org.sonar.api.utils.Durations;
import org.sonar.db.rule.RuleTesting;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
public class DebtCalculatorTest {
@org.junit.Rule
public RuleRepositoryRule ruleRepository = new RuleRepositoryRule().add(rule);
- DebtCalculator underTest = new DebtCalculator(ruleRepository, new Durations(new MapSettings(), mock(I18n.class)));
+ DebtCalculator underTest = new DebtCalculator(ruleRepository, new Durations());
@Test
public void no_debt_if_function_is_not_defined() {
import com.google.common.collect.Lists;
import java.util.Date;
-import java.util.Locale;
import org.junit.Test;
import org.mockito.Mockito;
import org.sonar.api.rule.RuleKey;
@Test
public void set_debt() {
- when(durations.format(any(Locale.class), any(Duration.class))).thenReturn("55 min");
+ when(durations.format(any(Duration.class))).thenReturn("55 min");
underTest.setDebt(Duration.create(55));
settings.setProperty("sonar.lf.gravatarServerUrl", "https://secure.gravatar.com/avatar/{EMAIL_MD5}.jpg?s={SIZE}&d=identicon");
settings.setProperty("sonar.lf.enableGravatar", true);
settings.setProperty("sonar.updatecenter.activate", false);
- settings.setProperty("sonar.technicalDebt.hoursInDay", "10");
settings.setProperty("sonar.technicalDebt.ratingGrid", "0.05,0.1,0.2,0.5");
// This setting should be ignored as it's not needed
settings.setProperty("sonar.defaultGroup", "sonar-users");
settings.setProperty("sonar.lf.gravatarServerUrl", "http://some-server.tld/logo.png");
settings.setProperty("sonar.lf.enableGravatar", true);
settings.setProperty("sonar.updatecenter.activate", false);
- settings.setProperty("sonar.technicalDebt.hoursInDay", "10");
settings.setProperty("sonar.technicalDebt.ratingGrid", "0.05,0.1,0.2,0.5");
settings.setProperty("sonar.allowUsersToSignUp", true);
when(server.getVersion()).thenReturn("6.2");
"sonar.lf.gravatarServerUrl": "https://secure.gravatar.com/avatar/{EMAIL_MD5}.jpg?s={SIZE}&d=identicon",
"sonar.lf.enableGravatar": "true",
"sonar.updatecenter.activate": "false",
- "sonar.technicalDebt.hoursInDay": "10",
"sonar.technicalDebt.ratingGrid": "0.05,0.1,0.2,0.5"
}
}
}
function getHoursInDay () {
- // workaround cyclic dependencies
- const getStore = require('../app/utils/getStore').default;
- const { getSettingValue } = require('../store/rootReducer');
-
- const store = getStore();
- const settingValue = getSettingValue(store.getState(), 'sonar.technicalDebt.hoursInDay');
- return settingValue ? settingValue.value : 8;
+ return 8;
}
function durationFormatter (value) {
static List<PropertyDefinition> all() {
return ImmutableList.of(
- PropertyDefinition.builder(CoreProperties.HOURS_IN_DAY)
- .name("Number of working hours in a day")
- .type(PropertyType.INTEGER)
- .defaultValue("8")
- .category(CoreProperties.CATEGORY_TECHNICAL_DEBT)
- .deprecatedKey("sqale.hoursInDay")
- .build(),
-
PropertyDefinition.builder(CoreProperties.DEVELOPMENT_COST)
.defaultValue("" + CoreProperties.DEVELOPMENT_COST_DEF_VALUE)
.name("Development cost")
.name("Development cost")
.description("If left blank, the generic value defined in this section will be used.")
.type(PropertyType.FLOAT)
- .build()
- )
- .build()
- );
+ .build())
+ .build());
}
}
@Test
public void all() {
List<PropertyDefinition> defs = CorePropertyDefinitions.all();
- assertThat(defs).hasSize(65);
+ assertThat(defs).hasSize(64);
}
@Test
/**
* @since 4.0
+ * @deprecated no more used since 6.3. See https://jira.sonarsource.com/browse/SONAR-8610
*/
+ @Deprecated
String HOURS_IN_DAY = "sonar.technicalDebt.hoursInDay";
/**
package org.sonar.api.utils;
import java.util.Locale;
-import javax.annotation.CheckForNull;
-import org.sonar.api.CoreProperties;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.config.Settings;
-import org.sonar.api.i18n.I18n;
import org.sonar.api.server.ServerSide;
/**
@ComputeEngineSide
public class Durations {
+ private static final String MINUTES_FORMAT = "%smin";
+ private static final String HOURS_FORMAT = "%sh";
+ private static final String DAYS_FORMAT = "%sd";
+
+ private static final int HOURS_IN_DAY = 8;
+
+ /**
+ * @deprecated since 6.3, only one format is available
+ */
+ @Deprecated
public enum DurationFormat {
/**
* Display duration with only one or two members.
SHORT
}
- private final Settings settings;
- private final I18n i18n;
-
- public Durations(Settings settings, I18n i18n) {
- this.settings = settings;
- this.i18n = i18n;
- }
-
/**
* Create a Duration object from a number of minutes
*/
/**
* Convert the text to a Duration
* <br>
- * Example : decode("9d 10 h") -> Duration.encode("10d2h") (if sonar.technicalDebt.hoursInDay property is set to 8)
+ * Example : decode("9d 10 h") -> Duration.encode("10d2h")
* <br>
* @throws IllegalArgumentException
*/
public Duration decode(String duration) {
- return Duration.decode(duration, hoursInDay());
+ return Duration.decode(duration, HOURS_IN_DAY);
}
/**
* Return the string value of the Duration.
* <br>
- * Example : encode(Duration.encode("9d 10h")) -> "10d2h" (if sonar.technicalDebt.hoursInDay property is set to 8)
+ * Example : encode(Duration.encode("9d 10h")) -> "10d2h"
*/
public String encode(Duration duration) {
- return duration.encode(hoursInDay());
+ return duration.encode(HOURS_IN_DAY);
}
/**
* Return the formatted work duration.
- * <br>
- * Example : format(Locale.FRENCH, Duration.encode("9d 10h"), DurationFormat.SHORT) -> 10j 2h (if sonar.technicalDebt.hoursInDay property is set to 8)
*
+ * @deprecated since 6.3 as the {@link Locale#ENGLISH} is always used. Use {@link #format(Duration)} instead
*/
+ @Deprecated
public String format(Locale locale, Duration duration, DurationFormat format) {
- return format(locale, duration);
+ return format(duration);
}
/**
* Return the formatted work duration.
* <br>
- * Example : format(Locale.FRENCH, Duration.encode("9d 10h"), DurationFormat.SHORT) -> 10j 2h (if sonar.technicalDebt.hoursInDay property is set to 8)
+ * Example : format(Locale.FRENCH, Duration.encode("9d 10h"), DurationFormat.SHORT) -> 10d 2d
*
+ * @deprecated since 6.3 as the {@link Locale#ENGLISH} is always used. Use {@link #format(Duration)} instead
*/
+ @Deprecated
public String format(Locale locale, Duration duration) {
+ return format(duration);
+ }
+
+ /**
+ * Return the formatted work duration using the english bundles.
+ * <br>
+ * Example : format(Duration.encode("9d 10h")) -> 10d 2h
+ *
+ */
+ public String format(Duration duration) {
Long durationInMinutes = duration.toMinutes();
if (durationInMinutes == 0) {
return "0";
boolean isNegative = durationInMinutes < 0;
Long absDuration = Math.abs(durationInMinutes);
- int days = ((Double) ((double) absDuration / hoursInDay() / 60)).intValue();
- Long remainingDuration = absDuration - (days * hoursInDay() * 60);
+ int days = ((Double) ((double) absDuration / HOURS_IN_DAY / 60)).intValue();
+ Long remainingDuration = absDuration - (days * HOURS_IN_DAY * 60);
int hours = ((Double) (remainingDuration.doubleValue() / 60)).intValue();
remainingDuration = remainingDuration - (hours * 60);
int minutes = remainingDuration.intValue();
- return format(locale, days, hours, minutes, isNegative);
+ return format(days, hours, minutes, isNegative);
}
- private String format(Locale locale, int days, int hours, int minutes, boolean isNegative) {
+ private static String format(int days, int hours, int minutes, boolean isNegative) {
StringBuilder message = new StringBuilder();
if (days > 0) {
- message.append(message(locale, "work_duration.x_days", isNegative ? (-1 * days) : days));
+ message.append(String.format(DAYS_FORMAT, isNegative ? (-1 * days) : days));
}
if (displayHours(days, hours)) {
addSpaceIfNeeded(message);
- message.append(message(locale, "work_duration.x_hours", isNegative && message.length() == 0 ? (-1 * hours) : hours));
+ message.append(String.format(HOURS_FORMAT, isNegative && message.length() == 0 ? (-1 * hours) : hours));
}
if (displayMinutes(days, hours, minutes)) {
addSpaceIfNeeded(message);
- message.append(message(locale, "work_duration.x_minutes", isNegative && message.length() == 0 ? (-1 * minutes) : minutes));
+ message.append(String.format(MINUTES_FORMAT, isNegative && message.length() == 0 ? (-1 * minutes) : minutes));
}
return message.toString();
}
- private String message(Locale locale, String key, @CheckForNull Object parameter) {
- return i18n.message(locale, key, null, parameter);
- }
-
private static boolean displayHours(int days, int hours) {
return hours > 0 && days < 10;
}
}
}
- private int hoursInDay() {
- return settings.getInt(CoreProperties.HOURS_IN_DAY);
- }
-
}
*/
package org.sonar.api.utils;
-import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.MapSettings;
-import org.sonar.api.i18n.I18n;
-
-import java.util.Locale;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.when;
-@RunWith(MockitoJUnitRunner.class)
public class DurationsTest {
- static final int HOURS_IN_DAY = 8;
-
- static final long ONE_MINUTE = 1L;
- static final long ONE_HOUR = ONE_MINUTE * 60;
- static final long ONE_DAY = HOURS_IN_DAY * ONE_HOUR;
-
- @Mock
- I18n i18n;
-
- Locale locale = Locale.ENGLISH;
-
- Settings settings;
+ private static final int HOURS_IN_DAY = 8;
- Durations durations;
+ private static final long ONE_MINUTE = 1L;
+ private static final long ONE_HOUR = ONE_MINUTE * 60;
+ private static final long ONE_DAY = HOURS_IN_DAY * ONE_HOUR;
- @Before
- public void setUp() {
- settings = new MapSettings();
- settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY);
- durations = new Durations(settings, i18n);
- }
+ private Durations underTest = new Durations();
@Test
public void create_from_minutes() {
- assertThat(durations.create(10L).toMinutes()).isEqualTo(10L);
+ assertThat(underTest.create(10L).toMinutes()).isEqualTo(10L);
}
@Test
public void decode() {
// 1 working day -> 8 hours
- assertThat(durations.decode("1d").toMinutes()).isEqualTo(8L * ONE_HOUR);
+ assertThat(underTest.decode("1d").toMinutes()).isEqualTo(8L * ONE_HOUR);
// 8 hours
- assertThat(durations.decode("8h").toMinutes()).isEqualTo(8L * ONE_HOUR);
+ assertThat(underTest.decode("8h").toMinutes()).isEqualTo(8L * ONE_HOUR);
}
@Test
public void format() {
- when(i18n.message(eq(locale), eq("work_duration.x_days"), eq((String) null), eq(5))).thenReturn("5d");
- when(i18n.message(eq(locale), eq("work_duration.x_hours"), eq((String) null), eq(2))).thenReturn("2h");
- when(i18n.message(eq(locale), eq("work_duration.x_minutes"), eq((String) null), eq(1))).thenReturn("1min");
-
- assertThat(durations.format(locale, Duration.create(5 * ONE_DAY), Durations.DurationFormat.SHORT)).isEqualTo("5d");
- assertThat(durations.format(locale, Duration.create(2 * ONE_HOUR), Durations.DurationFormat.SHORT)).isEqualTo("2h");
- assertThat(durations.format(locale, Duration.create(ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("1min");
+ assertThat(underTest.format(Duration.create(5 * ONE_DAY))).isEqualTo("5d");
+ assertThat(underTest.format(Duration.create(2 * ONE_HOUR))).isEqualTo("2h");
+ assertThat(underTest.format(Duration.create(ONE_MINUTE))).isEqualTo("1min");
- assertThat(durations.format(locale, Duration.create(5 * ONE_DAY + 2 * ONE_HOUR), Durations.DurationFormat.SHORT)).isEqualTo("5d 2h");
- assertThat(durations.format(locale, Duration.create(2 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("2h 1min");
- assertThat(durations.format(locale, Duration.create(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("5d 2h");
+ assertThat(underTest.format(Duration.create(5 * ONE_DAY + 2 * ONE_HOUR))).isEqualTo("5d 2h");
+ assertThat(underTest.format(Duration.create(2 * ONE_HOUR + ONE_MINUTE))).isEqualTo("2h 1min");
+ assertThat(underTest.format(Duration.create(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE))).isEqualTo("5d 2h");
}
@Test
public void not_display_following_element_when_bigger_than_ten() {
- int hoursInDay = 15;
- settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(hoursInDay));
-
- when(i18n.message(eq(locale), eq("work_duration.x_days"), eq((String) null), eq(15))).thenReturn("15d");
- when(i18n.message(eq(locale), eq("work_duration.x_hours"), eq((String) null), eq(12))).thenReturn("12h");
-
- assertThat(durations.format(locale, Duration.create(15 * hoursInDay * ONE_HOUR + 2 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("15d");
- assertThat(durations.format(locale, Duration.create(12 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("12h");
+ assertThat(underTest.format(Duration.create(15 * ONE_DAY + 7 * ONE_HOUR + ONE_MINUTE))).isEqualTo("15d");
}
@Test
public void display_zero_without_unit() {
- assertThat(durations.format(locale, Duration.create(0), Durations.DurationFormat.SHORT)).isEqualTo("0");
+ assertThat(underTest.format(Duration.create(0))).isEqualTo("0");
}
@Test
public void display_negative_duration() {
- when(i18n.message(eq(locale), eq("work_duration.x_days"), eq((String) null), eq(-5))).thenReturn("-5d");
- when(i18n.message(eq(locale), eq("work_duration.x_hours"), eq((String) null), eq(-2))).thenReturn("-2h");
- when(i18n.message(eq(locale), eq("work_duration.x_minutes"), eq((String) null), eq(-1))).thenReturn("-1min");
-
- assertThat(durations.format(locale, Duration.create(-5 * ONE_DAY), Durations.DurationFormat.SHORT)).isEqualTo("-5d");
- assertThat(durations.format(locale, Duration.create(-2 * ONE_HOUR), Durations.DurationFormat.SHORT)).isEqualTo("-2h");
- assertThat(durations.format(locale, Duration.create(-1 * ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("-1min");
+ assertThat(underTest.format(Duration.create(-5 * ONE_DAY))).isEqualTo("-5d");
+ assertThat(underTest.format(Duration.create(-2 * ONE_HOUR))).isEqualTo("-2h");
+ assertThat(underTest.format(Duration.create(-1 * ONE_MINUTE))).isEqualTo("-1min");
}
}