import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.utils.Duration;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.issue.IssueCache;
import org.sonar.batch.scan.LastSnapshots;
updater.setPastLine(issue, ref.getLine());
updater.setPastMessage(issue, ref.getMessage(), changeContext);
updater.setPastEffortToFix(issue, ref.getEffortToFix(), changeContext);
- Long previousTechnicalDebt = ref.getDebt();
+ Long debtInMinutes = ref.getDebt();
+ Duration previousTechnicalDebt = debtInMinutes != null ? Duration.create(debtInMinutes) : null;
updater.setPastTechnicalDebt(issue, previousTechnicalDebt, changeContext);
}
}
long debt = 0L;
if (issues != null) {
for (Issue issue : issues) {
- Long currentDebt = ((DefaultIssue) issue).debt();
+ Long currentDebt = ((DefaultIssue) issue).debtInMinutes();
if (currentDebt != null) {
debt += currentDebt;
}
<br/>
<span style="font-weight: bold">
<%= message('widget.rules.removed') -%>
- <span class="varb"><%= Internal.i18n.formatWorkDuration(estimated_cleared_technical_debt) -%></span>
+ <span class="varb"><%= Internal.i18n.formatLongWorkDuration(estimated_cleared_technical_debt) -%></span>
</span>
<% end %>
<% end %>
</a>
</td>
<td class="val value-debt-<%= h(characteristic.key) -%>">
- <a href="<%= drilldown_url -%>" class="link-debt-<%= h(characteristic.key) -%>"><%= Internal.i18n.formatWorkDuration(value.to_i) -%></a>
+ <a href="<%= drilldown_url -%>" class="link-debt-<%= h(characteristic.key) -%>"><%= Internal.i18n.formatLongWorkDuration(value.to_i) -%></a>
<% if should_display_diff_measures %>
<% if diff_by_characteristic_id[characteristic.id] %>
<%= format_variation(measure) -%>
<% end %>
</td>
<td class="val value-total-<%= h(characteristic.key) -%>">
- <%= Internal.i18n.formatWorkDuration(cumulated.to_i) -%>
+ <%= Internal.i18n.formatLongWorkDuration(cumulated.to_i) -%>
<%
if should_display_diff_measures
css_style = 'var'
css_style += 'b' if total_diff < 0
css_style += 'w' if total_diff > 0
- diff_to_display = (total_diff < 0 ? '' : '+') + Internal.i18n.formatWorkDuration(total_diff.to_i)
+ diff_to_display = (total_diff < 0 ? '' : '+') + Internal.i18n.formatLongWorkDuration(total_diff.to_i)
%>
<span class="<%= css_style -%>"><b>(<%= diff_to_display -%>)</b></span>
<%
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.utils.Duration;
import org.sonar.batch.issue.IssueCache;
import org.sonar.batch.scan.LastSnapshots;
import org.sonar.core.issue.IssueUpdater;
verify(updater).setPastLine(eq(issue), eq(10));
verify(updater).setPastMessage(eq(issue), eq("Message"), any(IssueChangeContext.class));
verify(updater).setPastEffortToFix(eq(issue), eq(1.5), any(IssueChangeContext.class));
- verify(updater).setPastTechnicalDebt(eq(issue), eq(1L), any(IssueChangeContext.class));
+ verify(updater).setPastTechnicalDebt(eq(issue), eq(Duration.create(1L)), any(IssueChangeContext.class));
}
@Test
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Resource;
import org.sonar.api.test.IsMeasure;
+import org.sonar.api.utils.Duration;
import org.sonar.batch.components.Period;
import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.batch.debt.IssueChangelogDebtCalculator;
@Test
public void save_on_one_issue_with_one_new_changelog() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(TWO_DAYS_IN_MINUTES).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
newArrayList(
// changelog created at is null because it has just been created on the current analysis
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(null)
@Test
public void save_on_one_issue_with_changelog() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo)
@Test
public void save_on_one_issue_with_changelog_only_in_the_past() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(ONE_DAY_IN_MINUTES).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
newArrayList(
// Change before all periods
new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(elevenDaysAgo)
@Test
public void save_on_one_issue_with_changelog_having_null_value() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
public void save_on_one_issue_with_changelog_and_periods_have_no_dates() {
when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null)));
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
@Test
public void save_on_one_issue_with_changelog_having_not_only_technical_debt_changes() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs()
.setDiff("actionPlan", "1.0", "1.1").setCreationDate(fourDaysAgo)
@Test
public void save_on_issues_with_changelog() {
- Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+ Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
)
);
- Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(TWO_DAYS_IN_MINUTES).setChanges(
+ Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
@Test
public void save_on_one_issue_without_changelog() {
when(issuable.issues()).thenReturn(newArrayList(
- (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES))
+ (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
);
decorator.decorate(resource, context);
when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null)));
when(issuable.issues()).thenReturn(newArrayList(
- (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES))
+ (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
);
decorator.decorate(resource, context);
@Test
public void save_on_issues_without_changelog() {
when(issuable.issues()).thenReturn(newArrayList(
- (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES),
- new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(TWO_DAYS_IN_MINUTES)
+ (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
+ new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
));
decorator.decorate(resource, context);
@Test
public void save_on_issues_with_changelog_and_issues_without_changelog() {
// issue1 and issue2 have changelog
- Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+ Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
)
);
- Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(TWO_DAYS_IN_MINUTES).setChanges(
+ Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
);
// issue3 and issue4 have no changelog
- Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES);
- Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(TWO_DAYS_IN_MINUTES);
+ Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES));
+ Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES));
when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
decorator.decorate(resource, context);
public void not_save_if_measure_already_computed() {
when(context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)).thenReturn(new Measure());
when(issuable.issues()).thenReturn(newArrayList(
- (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES),
- new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(TWO_DAYS_IN_MINUTES)
+ (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
+ new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
));
decorator.decorate(resource, context);
*/
@Test
public void not_return_negative_debt() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(ONE_DAY_IN_MINUTES).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
newArrayList(
// changelog created at is null because it has just been created on the current analysis
new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, ONE_DAY_IN_MINUTES).setCreationDate(null)
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
import org.sonar.api.test.IsMeasure;
+import org.sonar.api.utils.Duration;
import java.util.List;
@Test
public void add_technical_debt_from_one_issue_and_no_parent() throws Exception {
- Issue issue = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
+ Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
when(issuable.issues()).thenReturn(newArrayList(issue));
Requirement requirement = mock(Requirement.class);
@Test
public void add_technical_debt_from_one_issue_and_propagate_to_parents() throws Exception {
- Issue issue = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
+ Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
when(issuable.issues()).thenReturn(newArrayList(issue));
DefaultCharacteristic parentCharacteristic = new DefaultCharacteristic().setKey("parentCharacteristic");
Long technicalDebt1 = ONE_DAY_IN_MINUTES;
Long technicalDebt2 = 2 * ONE_DAY_IN_MINUTES;
- Issue issue1 = createIssue("rule1", "repo1").setDebt(technicalDebt1);
- Issue issue2 = createIssue("rule1", "repo1").setDebt(technicalDebt1);
- Issue issue3 = createIssue("rule2", "repo2").setDebt(technicalDebt2);
- Issue issue4 = createIssue("rule2", "repo2").setDebt(technicalDebt2);
+ Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1));
+ Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1));
+ Issue issue3 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2));
+ Issue issue4 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2));
when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("rootCharacteristic");
@Test
public void add_technical_debt_from_children_measures() throws Exception {
- Issue issue1 = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
- Issue issue2 = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
+ Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
+ Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
when(issuable.issues()).thenReturn(newArrayList(issue1, issue2));
DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("rootCharacteristic");
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+
import java.util.*;
import static com.google.common.collect.Lists.newArrayList;
@CheckForNull
public Long calculateNewTechnicalDebt(Issue issue, @Nullable Date periodDate) {
- Long debt = ((DefaultIssue) issue).debt();
+ Long debt = ((DefaultIssue) issue).debtInMinutes();
Date periodDatePlusOneSecond = periodDate != null ? DateUtils.addSeconds(periodDate, 1) : null;
if (isAfter(issue.creationDate(), periodDatePlusOneSecond)) {
return debt;
return (currentDate != null) && (pastDate == null || (DateUtils.truncatedCompareTo(currentDate, pastDate, Calendar.SECOND) <= 0));
}
-
}
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.Violation;
+import org.sonar.api.utils.Duration;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.debt.RuleDebtCalculator;
import org.sonar.core.issue.DefaultIssueBuilder;
if (issue.severity() == null) {
issue.setSeverity(activeRule.getSeverity().name());
}
- issue.setDebt(technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix()));
+ Long debt = technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix());
+ issue.setDebt(debt != null ? Duration.create(debt) : null);
}
}
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
+import org.sonar.api.utils.Duration;
import org.sonar.core.timemachine.Periods;
import java.util.Collection;
private String alertValue(Alert alert, Metric.Level level){
String value = level.equals(Metric.Level.ERROR) ? alert.getValueError() : alert.getValueWarning();
if (alert.getMetric().getType().equals(Metric.ValueType.WORK_DUR)) {
- return i18n.formatWorkDuration(Locale.ENGLISH, Long.parseLong(value));
+ return i18n.formatWorkDuration(Locale.ENGLISH, Duration.create(Long.parseLong(value)));
} else {
return value;
}
import org.apache.commons.lang.time.DateUtils;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.utils.Duration;
import java.util.Date;
long twoDays = 2 * HOURS_IN_DAY * 60 * 60L;
long fiveDays = 5 * HOURS_IN_DAY * 60 * 60L;
+ Duration oneDayDebt = Duration.create(oneDay);
+ Duration twoDaysDebt = Duration.create(twoDays);
+ Duration fiveDaysDebt = Duration.create(fiveDays);
+
@Before
public void setUp() throws Exception {
- Settings settings = new Settings();
- settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(HOURS_IN_DAY));
-
issueChangelogDebtCalculator = new IssueChangelogDebtCalculator();
}
@Test
public void calculate_new_technical_debt_with_one_diff_in_changelog() throws Exception {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDays).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
newArrayList(
// changelog created at is null because it has just been created on the current analysis
new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
@Test
public void calculate_new_technical_debt_with_many_diffs_in_changelog() throws Exception {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", twoDays, fiveDays).setCreationDate(null),
new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(fourDaysAgo)
@Test
public void changelog_can_be_in_wrong_order() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
newArrayList(
// 3rd
new FieldDiffs().setDiff("technicalDebt", null, oneDay).setCreationDate(nineDaysAgo),
@Test
public void calculate_new_technical_debt_with_null_date() throws Exception {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDays).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
)
@Test
public void not_return_negative_debt() {
- Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDay).setChanges(
+ Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDayDebt).setChanges(
newArrayList(
new FieldDiffs().setDiff("technicalDebt", twoDays, oneDay).setCreationDate(null)
)
@Before
public void before() {
- Settings settings = new Settings();
- settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY);
- calculator = new RuleDebtCalculator(model, settings);
+ calculator = new RuleDebtCalculator(model, new Settings().setProperty(CoreProperties.HOURS_IN_DAY, 8));
}
@Test
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.*;
+import org.sonar.api.utils.Duration;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.debt.RuleDebtCalculator;
Date analysisDate = new Date();
when(project.getAnalysisDate()).thenReturn(analysisDate);
-
DefaultIssue issue = new DefaultIssue()
.setKey("ABCDE")
.setRuleKey(SQUID_RULE_KEY)
ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
verify(cache).put(argument.capture());
- assertThat(argument.getValue().debt()).isEqualTo(debt);
+ assertThat(argument.getValue().debt()).isEqualTo(Duration.create(debt));
}
}
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.test.IsMeasure;
+import org.sonar.api.utils.Duration;
import org.sonar.core.timemachine.Periods;
import java.util.Locale;
// metric name is declared in l10n bundle
when(i18n.message(any(Locale.class), eq("metric.tech_debt.name"), anyString())).thenReturn("The Debt");
- when(i18n.formatWorkDuration(any(Locale.class), eq(3600L))).thenReturn("1h");
+ when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(3600L)))).thenReturn("1h");
when(context.getMeasure(metric)).thenReturn(new Measure(metric, 1800d));
projectAlerts.addAll(Lists.newArrayList(new Alert(null, metric, Alert.OPERATOR_SMALLER, "3600", null)));
import org.sonar.api.i18n.I18n;
import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.platform.PluginRepository;
+import org.sonar.api.utils.Duration;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.System2;
}
@Override
- public String formatWorkDuration(Locale locale, long duration) {
- if (duration == 0) {
+ public String formatWorkDuration(Locale locale, Duration duration) {
+ Long durationInMinutes = duration.toMinutes();
+ if (durationInMinutes == 0) {
return "0";
}
- List<WorkDurationFormatter.Result> results = workDurationFormatter.format(duration);
+ List<WorkDurationFormatter.Result> results = workDurationFormatter.format(durationInMinutes);
StringBuilder message = new StringBuilder();
for (WorkDurationFormatter.Result result : results) {
if (" ".equals(result.key())) {
import org.sonar.api.issue.internal.DefaultIssueComment;
import org.sonar.api.issue.internal.IssueChangeContext;
import org.sonar.api.user.User;
+import org.sonar.api.utils.Duration;
import javax.annotation.Nullable;
+
import java.util.Calendar;
import java.util.Date;
return setEffortToFix(issue, currentEffort, context);
}
- public boolean setTechnicalDebt(DefaultIssue issue, @Nullable Long value, IssueChangeContext context) {
- Long oldValue = issue.debt();
+ public boolean setTechnicalDebt(DefaultIssue issue, @Nullable Duration value, IssueChangeContext context) {
+ Duration oldValue = issue.debt();
if (!Objects.equal(value, oldValue)) {
- issue.setDebt(value);
- issue.setFieldChange(context, TECHNICAL_DEBT, oldValue, value);
+ issue.setDebt(value != null ? value : null);
+ issue.setFieldChange(context, TECHNICAL_DEBT, oldValue != null ? oldValue.toMinutes() : null, value != null ? value.toMinutes() : null);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return true;
return false;
}
- public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable Long previousTechnicalDebt, IssueChangeContext context) {
- Long currentTechnicalDebt = issue.debt();
+ public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable Duration previousTechnicalDebt, IssueChangeContext context) {
+ Duration currentTechnicalDebt = issue.debt();
issue.setDebt(previousTechnicalDebt);
return setTechnicalDebt(issue, currentTechnicalDebt, context);
}
}
return false;
}
+
}
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
import org.sonar.api.utils.KeyValueFormat;
import javax.annotation.CheckForNull;
.setLine(issue.line())
.setMessage(issue.message())
.setEffortToFix(issue.effortToFix())
- .setDebt(issue.debt())
+ .setDebt(issue.debtInMinutes())
.setResolution(issue.resolution())
.setStatus(issue.status())
.setSeverity(issue.severity())
.setLine(issue.line())
.setMessage(issue.message())
.setEffortToFix(issue.effortToFix())
- .setDebt(issue.debt())
+ .setDebt(issue.debtInMinutes())
.setResolution(issue.resolution())
.setStatus(issue.status())
.setSeverity(issue.severity())
issue.setResolution(resolution);
issue.setMessage(message);
issue.setEffortToFix(effortToFix);
- issue.setDebt(debt);
+ issue.setDebt(debt != null ? Duration.create(debt) : null);
issue.setLine(line);
issue.setSeverity(severity);
issue.setReporter(reporter);
import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.platform.PluginRepository;
import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Duration;
import org.sonar.api.utils.System2;
import java.net.URL;
new WorkDurationFormatter.Result(" ", null),
new WorkDurationFormatter.Result("work_duration.x_minutes", 1)
));
- assertThat(manager.formatWorkDuration(Locale.ENGLISH, 10)).isEqualTo("5d 2h 1min");
+ assertThat(manager.formatWorkDuration(Locale.ENGLISH, Duration.create(10))).isEqualTo("5d 2h 1min");
}
@Test
public void format_work_duration_when_0() {
- assertThat(manager.formatWorkDuration(Locale.ENGLISH, 0)).isEqualTo("0");
+ assertThat(manager.formatWorkDuration(Locale.ENGLISH, Duration.create(0))).isEqualTo("0");
}
static URLClassLoader newCoreClassloader() {
import org.sonar.api.issue.internal.FieldDiffs;
import org.sonar.api.issue.internal.IssueChangeContext;
import org.sonar.api.user.User;
+import org.sonar.api.utils.Duration;
import org.sonar.core.user.DefaultUser;
import java.util.Date;
@Test
public void set_past_technical_debt() throws Exception {
- long newDebt = 15 * 8 * 60 * 60;
- long previousDebt = 10 * 8 * 60 * 60;
+ Duration newDebt = Duration.create(15 * 8 * 60);
+ Duration previousDebt = Duration.create(10 * 8 * 60);
issue.setDebt(newDebt);
boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
assertThat(updated).isTrue();
assertThat(issue.mustSendNotifications()).isFalse();
FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
- assertThat(diff.oldValue()).isEqualTo(previousDebt);
- assertThat(diff.newValue()).isEqualTo(newDebt);
+ assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
+ assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
}
@Test
public void set_past_technical_debt_without_previous_value() throws Exception {
- long newDebt = 15 * 8 * 60 * 60;
+ Duration newDebt = Duration.create(15 * 8 * 60);
issue.setDebt(newDebt);
boolean updated = updater.setPastTechnicalDebt(issue, null, context);
assertThat(updated).isTrue();
FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
assertThat(diff.oldValue()).isNull();
- assertThat(diff.newValue()).isEqualTo(newDebt);
+ assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
}
@Test
public void set_past_technical_debt_with_null_new_value() throws Exception {
issue.setDebt(null);
- long previousDebt = 10 * 8 * 60 * 60;
+ Duration previousDebt = Duration.create(10 * 8 * 60);
boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
assertThat(updated).isTrue();
assertThat(issue.debt()).isNull();
assertThat(issue.mustSendNotifications()).isFalse();
FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
- assertThat(diff.oldValue()).isEqualTo(previousDebt);
+ assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
assertThat(diff.newValue()).isNull();
}
import org.junit.rules.ExpectedException;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.utils.Duration;
import java.util.Calendar;
import java.util.Date;
assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FALSE_POSITIVE);
assertThat(issue.effortToFix()).isEqualTo(15.0);
- assertThat(issue.debt()).isEqualTo(10L);
+ assertThat(issue.debt()).isEqualTo(Duration.create(10L));
assertThat(issue.line()).isEqualTo(6);
assertThat(issue.severity()).isEqualTo("BLOCKER");
assertThat(issue.message()).isEqualTo("message");
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RuleQuery;
import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Duration;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.persistence.MyBatis;
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setLine(5000)
- .setDebt(10L)
+ .setDebt(Duration.create(10L))
.setReporter("emmerik")
.setResolution("OPEN")
.setStatus("OPEN")
// updated fields
.setLine(5000)
- .setDebt(10L)
+ .setDebt(Duration.create(10L))
.setChecksum("FFFFF")
.setAuthorLogin("simon")
.setAssignee("loic")
import org.sonar.core.issue.IssueUpdater;
import javax.annotation.Nullable;
+
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import org.sonar.api.BatchComponent;
import org.sonar.api.ServerComponent;
+import org.sonar.api.utils.Duration;
import javax.annotation.Nullable;
/**
* Return the formatted work duration.
* <br>
- * Example : format(Locale.ENGLISH, WorkDuration.create(10, 2, 0, 8)) -> 10d 2h
+ * Example : format(Locale.ENGLISH, Duration.create(10 * 24 * 60 + 2 * 60)) -> 10d 2h
*
* @since 4.3
*/
- String formatWorkDuration(Locale locale, long duration);
+ String formatWorkDuration(Locale locale, Duration duration);
}
import org.sonar.api.issue.IssueComment;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
+import org.sonar.api.utils.Duration;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
private String message;
private Integer line;
private Double effortToFix;
- private Long debt;
+ private Duration debt;
private String status;
private String resolution;
private String reporter;
* Elapsed time to fix the issue
*/
@CheckForNull
- public Long debt() {
+ public Duration debt() {
return debt;
}
- public DefaultIssue setDebt(@Nullable Long t) {
+ @CheckForNull
+ public Long debtInMinutes(){
+ return debt != null ? debt.toMinutes() : null;
+ }
+
+ public DefaultIssue setDebt(@Nullable Duration t) {
this.debt = t;
return this;
}
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueComment;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
import java.text.SimpleDateFormat;
import java.util.List;
.setMessage("a message")
.setLine(7)
.setEffortToFix(1.2d)
- .setDebt(28800L)
+ .setDebt(Duration.create(28800L))
.setActionPlanKey("BCDE")
.setStatus(Issue.STATUS_CLOSED)
.setResolution(Issue.RESOLUTION_FIXED)
assertThat(issue.message()).isEqualTo("a message");
assertThat(issue.line()).isEqualTo(7);
assertThat(issue.effortToFix()).isEqualTo(1.2d);
- assertThat(issue.debt()).isEqualTo(28800L);
+ assertThat(issue.debt()).isEqualTo(Duration.create(28800L));
assertThat(issue.actionPlanKey()).isEqualTo("BCDE");
assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
import org.sonar.api.ServerComponent;
import org.sonar.api.i18n.I18n;
import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.utils.Duration;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
String oldValueString = oldValue != null && !"".equals(oldValue) ? oldValue.toString() : null;
if (IssueUpdater.TECHNICAL_DEBT.equals(key)) {
if (newValueString != null) {
- newValueString = i18n.formatWorkDuration(UserSession.get().locale(), Long.parseLong(newValueString));
+ newValueString = i18n.formatWorkDuration(UserSession.get().locale(), Duration.create(Long.parseLong(newValueString)));
}
if (oldValueString != null) {
- oldValueString = i18n.formatWorkDuration(UserSession.get().locale(), Long.parseLong(oldValueString));
+ oldValueString = i18n.formatWorkDuration(UserSession.get().locale(), Duration.create(Long.parseLong(oldValueString)));
}
}
return new IssueChangelogDiffFormat(oldValueString, newValueString);
import org.sonar.api.technicaldebt.server.Characteristic;
import org.sonar.api.user.User;
import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Duration;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
private void writeIssue(IssueQueryResult result, DefaultIssue issue, JsonWriter json) {
String actionPlanKey = issue.actionPlanKey();
ActionPlan actionPlan = result.actionPlan(issue);
- Long technicalDebt = issue.debt();
+ Duration debt = issue.debt();
Date updateDate = issue.updateDate();
Date closeDate = issue.closeDate();
.prop("author", issue.authorLogin())
.prop("actionPlan", actionPlanKey)
.prop("actionPlanName", actionPlan != null ? actionPlan.name() : null)
- .prop("debt", technicalDebt != null ? i18n.formatWorkDuration(UserSession.get().locale(), technicalDebt) : null)
+ .prop("debt", debt != null ? i18n.formatWorkDuration(UserSession.get().locale(), debt) : null)
.prop("creationDate", DateUtils.formatDateTime(issue.creationDate()))
.prop("fCreationDate", formatDate(issue.creationDate()))
.prop("updateDate", updateDate != null ? DateUtils.formatDateTime(updateDate) : null)
import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
import org.sonar.api.i18n.I18n;
+import org.sonar.api.utils.Duration;
import org.sonar.core.i18n.GwtI18n;
import org.sonar.server.user.UserSession;
return i18n.ageFromNow(UserSession.get().locale(), date);
}
- public String formatWorkDuration(long duration) {
+ public String formatWorkDuration(Duration duration) {
return i18n.formatWorkDuration(UserSession.get().locale(), duration);
}
+ public String formatLongWorkDuration(long duration) {
+ return formatWorkDuration(Duration.create(duration));
+ }
+
}
hash_diff = {}
hash_diff[:key] = key
if key == 'technicalDebt'
- hash_diff[:newValue] = debt_to_hash(diff.newValue()) if diff.newValue.present?
- hash_diff[:oldValue] = debt_to_hash(diff.oldValue()) if diff.oldValue.present?
+ hash_diff[:newValue] = long_debt_to_hash(diff.newValue()) if diff.newValue.present?
+ hash_diff[:oldValue] = long_debt_to_hash(diff.oldValue()) if diff.oldValue.present?
else
hash_diff[:newValue] = diff.newValue() if diff.newValue.present?
hash_diff[:oldValue] = diff.oldValue() if diff.oldValue.present?
private
def self.debt_to_hash(debt)
+ long_debt_to_hash(debt.toMinutes)
+ end
+
+ def self.long_debt_to_hash(debt)
+ # TODO do not use toWorkDuration() but calculate days, hours and minutes from the duration and from hoursInDay property
work_duration = Internal.technical_debt.toWorkDuration(debt.to_i)
{
:days => work_duration.days(),
end
def work_duration_formatted_value(value)
- Internal.i18n.formatWorkDuration(value.to_i)
+ Internal.i18n.formatLongWorkDuration(value.to_i)
end
def color
import org.sonar.api.rules.Rule;
import org.sonar.api.user.User;
import org.sonar.api.user.UserFinder;
+import org.sonar.api.utils.Duration;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.db.IssueChangeDao;
assertThat(results.issues()).hasSize(1);
DefaultIssue result = (DefaultIssue) results.issues().iterator().next();
- assertThat(result.debt()).isEqualTo(10L);
+ assertThat(result.debt()).isEqualTo(Duration.create(10L));
}
}
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.i18n.I18n;
import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.utils.Duration;
import java.util.List;
import java.util.Locale;
FieldDiffs diffs = new FieldDiffs();
diffs.setDiff("technicalDebt", "18000", "28800");
- when(i18n.formatWorkDuration(any(Locale.class), eq(18000L))).thenReturn("5 hours");
- when(i18n.formatWorkDuration(any(Locale.class), eq(28800L))).thenReturn("1 days");
+ when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(18000L)))).thenReturn("5 hours");
+ when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(28800L)))).thenReturn("1 days");
when(i18n.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt");
when(i18n.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days");
FieldDiffs diffs = new FieldDiffs();
diffs.setDiff("technicalDebt", null, "28800");
- when(i18n.formatWorkDuration(any(Locale.class), eq(28800L))).thenReturn("1 days");
+ when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(28800L)))).thenReturn("1 days");
when(i18n.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt");
when(i18n.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days");
import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic;
import org.sonar.api.user.User;
import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Duration;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.DefaultActionPlan;
@Test
public void show_issue_with_technical_debt() throws Exception {
- Long technicalDebt = 7260L;
- Issue issue = createStandardIssue().setDebt(technicalDebt);
+ Duration debt = (Duration.create(7260L));
+ Issue issue = createStandardIssue().setDebt(debt);
issues.add(issue);
- when(i18n.formatWorkDuration(any(Locale.class), eq(technicalDebt))).thenReturn("2 hours 1 minutes");
+ when(i18n.formatWorkDuration(any(Locale.class), eq(debt))).thenReturn("2 hours 1 minutes");
MockUserSession.set();
WsTester.TestRequest request = tester.newRequest("show").setParam("key", issue.key());
@Test
public void show_issue_with_characteristics() throws Exception {
- Issue issue = createStandardIssue().setDebt(7260L);
+ Issue issue = createStandardIssue().setDebt(Duration.create(7260L));
issues.add(issue);
Characteristic requirement = new DefaultCharacteristic().setId(5).setParentId(2).setRootId(1);
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.i18n.I18n;
+import org.sonar.api.utils.Duration;
import org.sonar.core.i18n.GwtI18n;
import java.util.Date;
@Test
public void format_work_duration() throws Exception {
- jRubyI18n.formatWorkDuration(10L);
- verify(i18n).formatWorkDuration(any(Locale.class), eq(10L));
+ jRubyI18n.formatWorkDuration(Duration.create(10L));
+ verify(i18n).formatWorkDuration(any(Locale.class), eq(Duration.create(10L)));
+ }
+
+ @Test
+ public void format_long_work_duration() throws Exception {
+ jRubyI18n.formatLongWorkDuration(10L);
+ verify(i18n).formatWorkDuration(any(Locale.class), eq(Duration.create(10L)));
}
}