@@ -39,7 +39,6 @@ import org.sonar.api.rules.ActiveRule; | |||
import org.sonar.api.rules.Rule; | |||
import org.sonar.api.rules.RuleFinder; | |||
import org.sonar.api.utils.KeyValueFormat; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.batch.issue.IssueCache; | |||
import org.sonar.batch.scan.LastSnapshots; | |||
@@ -180,16 +179,14 @@ public class IssueTrackingDecorator implements Decorator { | |||
updater.setPastLine(issue, ref.getLine()); | |||
updater.setPastMessage(issue, ref.getMessage(), changeContext); | |||
updater.setPastEffortToFix(issue, ref.getEffortToFix(), changeContext); | |||
Long technicalDebt = ref.getTechnicalDebt(); | |||
WorkDuration previousTechnicalDebt = technicalDebt != null ? workDurationFactory.createFromWorkingLong(technicalDebt) : null; | |||
Long previousTechnicalDebt = ref.getDebt(); | |||
updater.setPastTechnicalDebt(issue, previousTechnicalDebt, changeContext); | |||
} | |||
} | |||
private void addUnmatched(Collection<IssueDto> unmatchedIssues, SourceHashHolder sourceHashHolder, Collection<DefaultIssue> issues) { | |||
for (IssueDto unmatchedDto : unmatchedIssues) { | |||
Long debt = unmatchedDto.getTechnicalDebt(); | |||
DefaultIssue unmatched = unmatchedDto.toDefaultIssue(debt != null ? workDurationFactory.createFromWorkingLong(debt) : null); | |||
DefaultIssue unmatched = unmatchedDto.toDefaultIssue(); | |||
if (StringUtils.isNotBlank(unmatchedDto.getReporter()) && !Issue.STATUS_CLOSED.equals(unmatchedDto.getStatus())) { | |||
relocateManualIssue(unmatched, unmatchedDto, sourceHashHolder); | |||
} | |||
@@ -200,8 +197,7 @@ public class IssueTrackingDecorator implements Decorator { | |||
private void addIssuesOnDeletedComponents(Collection<DefaultIssue> issues) { | |||
for (IssueDto deadDto : initialOpenIssues.selectAllIssues()) { | |||
Long debt = deadDto.getTechnicalDebt(); | |||
DefaultIssue dead = deadDto.toDefaultIssue(debt != null ? workDurationFactory.createFromWorkingLong(debt) : null); | |||
DefaultIssue dead = deadDto.toDefaultIssue(); | |||
updateUnmatchedIssue(dead, true); | |||
issues.add(dead); | |||
} |
@@ -40,7 +40,6 @@ import org.sonar.api.resources.ResourceUtils; | |||
import org.sonar.api.technicaldebt.batch.Characteristic; | |||
import org.sonar.api.technicaldebt.batch.Requirement; | |||
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import java.util.Arrays; | |||
@@ -167,21 +166,24 @@ public final class TechnicalDebtDecorator implements Decorator { | |||
} | |||
private double computeTechnicalDebt(Metric metric, DecoratorContext context, Requirement requirement, Collection<Issue> issues) { | |||
WorkDuration debt = workDurationFactory.createFromWorkingValue(0, WorkDuration.UNIT.MINUTES); | |||
long debt = 0L; | |||
if (issues != null) { | |||
for (Issue issue : issues) { | |||
debt = debt.add(((DefaultIssue) issue).technicalDebt()); | |||
Long currentDebt = ((DefaultIssue) issue).debt(); | |||
if (currentDebt != null) { | |||
debt += currentDebt; | |||
} | |||
} | |||
} | |||
double value = debt.toWorkingDays(); | |||
double debtInDays = workDurationFactory.createFromSeconds(debt).toWorkingDays(); | |||
for (Measure measure : context.getChildrenMeasures(MeasuresFilters.requirement(metric, requirement))) { | |||
Requirement measureRequirement = measure.getRequirement(); | |||
if (measureRequirement != null && measureRequirement.equals(requirement) && measure.getValue() != null) { | |||
value += measure.getValue(); | |||
debtInDays += measure.getValue(); | |||
} | |||
} | |||
return value; | |||
return debtInDays; | |||
} | |||
private void propagateTechnicalDebtInParents(Characteristic characteristic, double value, Map<Characteristic, Double> characteristicCosts) { |
@@ -38,7 +38,6 @@ import org.sonar.api.resources.Resource; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rules.Rule; | |||
import org.sonar.api.rules.RuleFinder; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.batch.issue.IssueCache; | |||
import org.sonar.batch.scan.LastSnapshots; | |||
@@ -514,7 +513,7 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase { | |||
@Test | |||
public void merge_matched_issue() throws Exception { | |||
IssueDto previousIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey_unit_test_only("squid", "AvoidCycle") | |||
.setLine(10).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setTechnicalDebt(1L); | |||
.setLine(10).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L); | |||
DefaultIssue issue = new DefaultIssue(); | |||
IssueTrackingResult trackingResult = mock(IssueTrackingResult.class); | |||
@@ -526,13 +525,13 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase { | |||
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(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.MINUTES, 8)), any(IssueChangeContext.class)); | |||
verify(updater).setPastTechnicalDebt(eq(issue), eq(1L), any(IssueChangeContext.class)); | |||
} | |||
@Test | |||
public void merge_matched_issue_on_manual_severity() throws Exception { | |||
IssueDto previousIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey_unit_test_only("squid", "AvoidCycle") | |||
.setLine(10).setManualSeverity(true).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setTechnicalDebt(1L); | |||
.setLine(10).setManualSeverity(true).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L); | |||
DefaultIssue issue = new DefaultIssue(); | |||
IssueTrackingResult trackingResult = mock(IssueTrackingResult.class); | |||
@@ -550,7 +549,7 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase { | |||
when(initialOpenIssues.selectChangelog("ABCDE")).thenReturn(newArrayList(new IssueChangeDto().setIssueKey("ABCD"))); | |||
IssueDto previousIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey_unit_test_only("squid", "AvoidCycle") | |||
.setLine(10).setMessage("Message").setEffortToFix(1.5).setTechnicalDebt(1L); | |||
.setLine(10).setMessage("Message").setEffortToFix(1.5).setDebt(1L); | |||
DefaultIssue issue = new DefaultIssue(); | |||
IssueTrackingResult trackingResult = mock(IssueTrackingResult.class); |
@@ -78,9 +78,13 @@ public class NewTechnicalDebtDecoratorTest { | |||
Date fiveDaysAgo; | |||
Date fourDaysAgo; | |||
WorkDuration oneDaysDebt = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8); | |||
WorkDuration twoDaysDebt = WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, 8); | |||
WorkDuration fiveDaysDebt = WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.DAYS, 8); | |||
WorkDuration oneDaysWorkDuration = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8); | |||
WorkDuration twoDaysWorkDuration = WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, 8); | |||
WorkDuration fiveDaysWorkDuration = WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.DAYS, 8); | |||
long oneDays = 1 * 8 * 60 * 60; | |||
long twoDays = 2 * 8 * 60 * 60; | |||
long fiveDays = 5 * 8 * 60 * 60; | |||
@Before | |||
public void setup() { | |||
@@ -115,10 +119,10 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_one_issue_with_one_new_changelog() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDays).setChanges( | |||
newArrayList( | |||
// changelog created at is null because it has just been created on the current analysis | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(null) | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), fromWorkDayDuration(twoDaysWorkDuration)).setCreationDate(null) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
@@ -131,10 +135,10 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_one_issue_with_changelog() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(fiveDaysDebt)).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysWorkDuration), fromWorkDayDuration(fiveDaysWorkDuration)).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), fromWorkDayDuration(twoDaysWorkDuration)).setCreationDate(fourDaysAgo) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
@@ -147,10 +151,10 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_one_issue_with_changelog_only_in_the_past() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(oneDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDays).setChanges( | |||
newArrayList( | |||
// Change before all periods | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(elevenDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(elevenDaysAgo) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
@@ -163,11 +167,11 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_one_issue_with_changelog_having_null_value() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(fiveDaysDebt)).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), null).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(fiveDaysWorkDuration)).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), null).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(nineDaysAgo) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
@@ -182,11 +186,11 @@ public class NewTechnicalDebtDecoratorTest { | |||
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).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(fiveDaysDebt)).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), null).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(fiveDaysWorkDuration)).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), null).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(nineDaysAgo) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
@@ -199,11 +203,11 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_one_issue_with_changelog_having_not_only_technical_debt_changes() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs() | |||
.setDiff("actionPlan", "1.0", "1.1").setCreationDate(fourDaysAgo) | |||
.setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo) | |||
.setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), fromWorkDayDuration(twoDaysWorkDuration)).setCreationDate(fourDaysAgo) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
@@ -216,17 +220,17 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_issues_with_changelog() { | |||
Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(fiveDaysDebt)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysWorkDuration), fromWorkDayDuration(fiveDaysWorkDuration)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), fromWorkDayDuration(twoDaysWorkDuration)).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(nineDaysAgo) | |||
) | |||
); | |||
Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges( | |||
Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(twoDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), fromWorkDayDuration(twoDaysWorkDuration)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(nineDaysAgo) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue1, issue2)); | |||
@@ -240,7 +244,7 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_one_issue_without_changelog() { | |||
when(issuable.issues()).thenReturn(newArrayList( | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt)) | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(fiveDays)) | |||
); | |||
decorator.decorate(resource, context); | |||
@@ -252,7 +256,7 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_one_issue_without_technical_debt_and_without_changelog() { | |||
when(issuable.issues()).thenReturn(newArrayList( | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(null)) | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(null)) | |||
); | |||
decorator.decorate(resource, context); | |||
@@ -266,7 +270,7 @@ public class NewTechnicalDebtDecoratorTest { | |||
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).setTechnicalDebt(fiveDaysDebt)) | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(fiveDays)) | |||
); | |||
decorator.decorate(resource, context); | |||
@@ -278,8 +282,8 @@ public class NewTechnicalDebtDecoratorTest { | |||
@Test | |||
public void save_on_issues_without_changelog() { | |||
when(issuable.issues()).thenReturn(newArrayList( | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt), | |||
new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setTechnicalDebt(twoDaysDebt) | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(fiveDays), | |||
new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(twoDays) | |||
)); | |||
decorator.decorate(resource, context); | |||
@@ -291,23 +295,23 @@ public class NewTechnicalDebtDecoratorTest { | |||
@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).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(fiveDaysDebt)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysWorkDuration), fromWorkDayDuration(fiveDaysWorkDuration)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), fromWorkDayDuration(twoDaysWorkDuration)).setCreationDate(fourDaysAgo), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(nineDaysAgo) | |||
) | |||
); | |||
Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges( | |||
Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(twoDays).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo) | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysWorkDuration), fromWorkDayDuration(twoDaysWorkDuration)).setCreationDate(rightNow), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(nineDaysAgo) | |||
) | |||
); | |||
// issue3 and issue4 have no changelog | |||
Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt); | |||
Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setTechnicalDebt(twoDaysDebt); | |||
Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(fiveDays); | |||
Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(twoDays); | |||
when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4)); | |||
decorator.decorate(resource, context); | |||
@@ -320,8 +324,8 @@ public class NewTechnicalDebtDecoratorTest { | |||
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).setTechnicalDebt(fiveDaysDebt), | |||
new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setTechnicalDebt(twoDaysDebt) | |||
(Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(fiveDays), | |||
new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(twoDays) | |||
)); | |||
decorator.decorate(resource, context); | |||
@@ -334,10 +338,10 @@ public class NewTechnicalDebtDecoratorTest { | |||
*/ | |||
@Test | |||
public void not_return_negative_debt() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(oneDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDays).setChanges( | |||
newArrayList( | |||
// changelog created at is null because it has just been created on the current analysis | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(oneDaysDebt)).setCreationDate(null) | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysWorkDuration), fromWorkDayDuration(oneDaysWorkDuration)).setCreationDate(null) | |||
) | |||
); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); |
@@ -49,7 +49,6 @@ import org.sonar.api.technicaldebt.batch.TechnicalDebtModel; | |||
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.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import java.util.List; | |||
@@ -130,9 +129,7 @@ public class TechnicalDebtDecoratorTest { | |||
@Test | |||
public void add_technical_debt_from_one_issue_and_no_parent() throws Exception { | |||
WorkDuration technicalDebt = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8); | |||
Issue issue = createIssue("rule1", "repo1").setTechnicalDebt(technicalDebt); | |||
Issue issue = createIssue("rule1", "repo1").setDebt(1 * 8 * 60 * 60L); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
Requirement requirement = mock(Requirement.class); | |||
@@ -147,7 +144,7 @@ public class TechnicalDebtDecoratorTest { | |||
@Test | |||
public void add_technical_debt_from_one_issue_without_debt() throws Exception { | |||
Issue issue = createIssue("rule1", "repo1").setTechnicalDebt(null); | |||
Issue issue = createIssue("rule1", "repo1").setDebt(null); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
Requirement requirement = mock(Requirement.class); | |||
@@ -161,9 +158,7 @@ public class TechnicalDebtDecoratorTest { | |||
@Test | |||
public void add_technical_debt_from_one_issue_and_propagate_to_parents() throws Exception { | |||
WorkDuration technicalDebt = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8); | |||
Issue issue = createIssue("rule1", "repo1").setTechnicalDebt(technicalDebt); | |||
Issue issue = createIssue("rule1", "repo1").setDebt(1 * 8 * 60 * 60L); | |||
when(issuable.issues()).thenReturn(newArrayList(issue)); | |||
DefaultCharacteristic parentCharacteristic = new DefaultCharacteristic().setKey("parentCharacteristic"); | |||
@@ -184,13 +179,13 @@ public class TechnicalDebtDecoratorTest { | |||
@Test | |||
public void add_technical_debt_from_issues() throws Exception { | |||
WorkDuration technicalDebt1 = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8); | |||
WorkDuration technicalDebt2 = WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, 8); | |||
long technicalDebt1 = 1 * 8 * 60 * 60; | |||
long technicalDebt2 = 2 * 8 * 60 * 60L; | |||
Issue issue1 = createIssue("rule1", "repo1").setTechnicalDebt(technicalDebt1); | |||
Issue issue2 = createIssue("rule1", "repo1").setTechnicalDebt(technicalDebt1); | |||
Issue issue3 = createIssue("rule2", "repo2").setTechnicalDebt(technicalDebt2); | |||
Issue issue4 = createIssue("rule2", "repo2").setTechnicalDebt(technicalDebt2); | |||
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); | |||
when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4)); | |||
DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("rootCharacteristic"); | |||
@@ -213,10 +208,10 @@ public class TechnicalDebtDecoratorTest { | |||
@Test | |||
public void add_technical_debt_from_children_measures() throws Exception { | |||
WorkDuration technicalDebt = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8); | |||
long technicalDebt = 1 * 8 * 60 * 60L; | |||
Issue issue1 = createIssue("rule1", "repo1").setTechnicalDebt(technicalDebt); | |||
Issue issue2 = createIssue("rule1", "repo1").setTechnicalDebt(technicalDebt); | |||
Issue issue1 = createIssue("rule1", "repo1").setDebt(technicalDebt); | |||
Issue issue2 = createIssue("rule1", "repo1").setDebt(technicalDebt); | |||
when(issuable.issues()).thenReturn(newArrayList(issue1, issue2)); | |||
DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("rootCharacteristic"); |
@@ -33,7 +33,6 @@ import org.sonar.core.issue.IssueUpdater; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import java.util.*; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
@@ -48,7 +47,8 @@ public class IssueChangelogDebtCalculator implements BatchComponent { | |||
@CheckForNull | |||
public WorkDuration calculateNewTechnicalDebt(Issue issue, @Nullable Date periodDate) { | |||
WorkDuration currentTechnicalDebt = ((DefaultIssue) issue).technicalDebt(); | |||
Long debt = ((DefaultIssue) issue).debt(); | |||
WorkDuration currentTechnicalDebt = debt != null ? workDurationFactory.createFromSeconds(debt) : null; | |||
Date periodDatePlusOneSecond = periodDate != null ? DateUtils.addSeconds(periodDate, 1) : null; | |||
if (isAfter(issue.creationDate(), periodDatePlusOneSecond)) { | |||
return currentTechnicalDebt; | |||
@@ -82,7 +82,7 @@ public class IssueChangelogDebtCalculator implements BatchComponent { | |||
* SONAR-5059 | |||
*/ | |||
@CheckForNull | |||
private WorkDuration subtractNeverNegative(@Nullable WorkDuration workDuration, WorkDuration toSubtractWith){ | |||
private WorkDuration subtractNeverNegative(@Nullable WorkDuration workDuration, WorkDuration toSubtractWith) { | |||
if (workDuration != null) { | |||
WorkDuration result = workDuration.subtract(toSubtractWith); | |||
if (result.toSeconds() > 0) { |
@@ -21,12 +21,13 @@ package org.sonar.batch.debt; | |||
import com.google.common.base.Objects; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.technicaldebt.batch.Requirement; | |||
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel; | |||
import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
@@ -36,19 +37,19 @@ import javax.annotation.Nullable; | |||
*/ | |||
public class RuleDebtCalculator implements BatchExtension { | |||
private TechnicalDebtModel model; | |||
private final WorkDurationFactory workDurationFactory; | |||
private final TechnicalDebtModel model; | |||
private final int hoursInDay; | |||
public RuleDebtCalculator(TechnicalDebtModel model, WorkDurationFactory workDurationFactory) { | |||
public RuleDebtCalculator(TechnicalDebtModel model, Settings settings) { | |||
this.model = model; | |||
this.workDurationFactory = workDurationFactory; | |||
this.hoursInDay = settings.getInt(CoreProperties.HOURS_IN_DAY); | |||
} | |||
/** | |||
* Calculate the technical debt from a requirement | |||
*/ | |||
@CheckForNull | |||
public WorkDuration calculateTechnicalDebt(RuleKey ruleKey, @Nullable Double effortToFix) { | |||
public Long calculateTechnicalDebt(RuleKey ruleKey, @Nullable Double effortToFix) { | |||
Requirement requirement = model.requirementsByRule(ruleKey); | |||
if (requirement != null) { | |||
if (requirement.function().equals(DefaultRequirement.CONSTANT_ISSUE) && effortToFix != null) { | |||
@@ -60,20 +61,31 @@ public class RuleDebtCalculator implements BatchExtension { | |||
return null; | |||
} | |||
private WorkDuration calculateTechnicalDebt(Requirement requirement, @Nullable Double effortToFix) { | |||
WorkDuration result = workDurationFactory.createFromWorkingValue(0, WorkDuration.UNIT.DAYS); | |||
private long calculateTechnicalDebt(Requirement requirement, @Nullable Double effortToFix) { | |||
long result = 0L; | |||
int factorValue = requirement.factorValue(); | |||
if (factorValue > 0) { | |||
int effortToFixValue = Objects.firstNonNull(effortToFix, 1).intValue(); | |||
result = workDurationFactory.createFromWorkingValue(factorValue, requirement.factorUnit()).multiply(effortToFixValue); | |||
result = convertValueAndUnitToSeconds(factorValue, requirement.factorUnit()) * effortToFixValue; | |||
} | |||
int offsetValue = requirement.offsetValue(); | |||
if (offsetValue > 0) { | |||
result = result.add(workDurationFactory.createFromWorkingValue(offsetValue, requirement.offsetUnit())); | |||
result += convertValueAndUnitToSeconds(offsetValue, requirement.offsetUnit()); | |||
} | |||
return result; | |||
} | |||
private int convertValueAndUnitToSeconds(int value, WorkDuration.UNIT unit){ | |||
if (WorkDuration.UNIT.DAYS.equals(unit)) { | |||
return value * hoursInDay * 60 * 60; | |||
} else if (WorkDuration.UNIT.HOURS.equals(unit)) { | |||
return value * 60 * 60; | |||
} else if (WorkDuration.UNIT.MINUTES.equals(unit)) { | |||
return value * 60; | |||
} | |||
throw new IllegalStateException("Invalid unit : " + unit); | |||
} | |||
} |
@@ -111,7 +111,7 @@ public class ModuleIssues { | |||
if (issue.severity() == null) { | |||
issue.setSeverity(activeRule.getSeverity().name()); | |||
} | |||
issue.setTechnicalDebt(technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())); | |||
issue.setDebt(technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())); | |||
} | |||
} |
@@ -52,6 +52,10 @@ public class IssueChangelogDebtCalculatorTest { | |||
WorkDuration twoDaysDebt = WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, HOURS_IN_DAY); | |||
WorkDuration fiveDaysDebt = WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.DAYS, HOURS_IN_DAY); | |||
Long oneDaysDebtInSec = 1 * HOURS_IN_DAY * 60 * 60L; | |||
Long twoDaysDebtInSec = 2 * HOURS_IN_DAY * 60 * 60L; | |||
Long fiveDaysDebtInSec = 5 * HOURS_IN_DAY * 60 * 60L; | |||
@Before | |||
public void setUp() throws Exception { | |||
Settings settings = new Settings(); | |||
@@ -62,7 +66,7 @@ public class IssueChangelogDebtCalculatorTest { | |||
@Test | |||
public void calculate_new_technical_debt_with_one_diff_in_changelog() throws Exception { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebtInSec).setChanges( | |||
newArrayList( | |||
// changelog created at is null because it has just been created on the current analysis | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(null) | |||
@@ -80,7 +84,7 @@ public class IssueChangelogDebtCalculatorTest { | |||
@Test | |||
public void calculate_new_technical_debt_with_many_diffs_in_changelog() throws Exception { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebtInSec).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(fiveDaysDebt)).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo) | |||
@@ -97,7 +101,7 @@ public class IssueChangelogDebtCalculatorTest { | |||
@Test | |||
public void changelog_can_be_in_wrong_order() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebtInSec).setChanges( | |||
newArrayList( | |||
// 3rd | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo), | |||
@@ -116,7 +120,7 @@ public class IssueChangelogDebtCalculatorTest { | |||
@Test | |||
public void calculate_new_technical_debt_with_null_date() throws Exception { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebtInSec).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(null) | |||
) | |||
@@ -128,7 +132,7 @@ public class IssueChangelogDebtCalculatorTest { | |||
@Test | |||
public void calculate_new_technical_debt_when_new_debt_is_null() throws Exception { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(null).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(null).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), null).setCreationDate(null), | |||
new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo) | |||
@@ -147,7 +151,7 @@ public class IssueChangelogDebtCalculatorTest { | |||
@Test | |||
public void not_return_negative_debt() { | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(oneDaysDebt).setChanges( | |||
Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDaysDebtInSec).setChanges( | |||
newArrayList( | |||
new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(oneDaysDebt)).setCreationDate(null) | |||
) |
@@ -31,7 +31,6 @@ import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel; | |||
import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
import static org.fest.assertions.Fail.fail; | |||
@@ -51,7 +50,7 @@ public class RuleDebtCalculatorTest { | |||
public void before() { | |||
Settings settings = new Settings(); | |||
settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY); | |||
calculator = new RuleDebtCalculator(model, new WorkDurationFactory(settings)); | |||
calculator = new RuleDebtCalculator(model, settings); | |||
} | |||
@Test | |||
@@ -67,8 +66,7 @@ public class RuleDebtCalculatorTest { | |||
.setOffsetUnit(WorkDuration.UNIT.MINUTES); | |||
when(model.requirementsByRule(ruleKey)).thenReturn(requirement); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo( | |||
WorkDuration.createFromValueAndUnit(15, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(15 * 60); | |||
} | |||
@Test | |||
@@ -84,8 +82,7 @@ public class RuleDebtCalculatorTest { | |||
.setOffsetUnit(WorkDuration.UNIT.MINUTES); | |||
when(model.requirementsByRule(ruleKey)).thenReturn(requirement); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo( | |||
WorkDuration.createFromValueAndUnit((10 * 2) + 5, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(((10 * 2) + 5) * 60); | |||
} | |||
@Test | |||
@@ -96,11 +93,10 @@ public class RuleDebtCalculatorTest { | |||
DefaultRequirement requirement = new DefaultRequirement() | |||
.setFunction("linear") | |||
.setFactorValue(10) | |||
.setFactorUnit(WorkDuration.UNIT.MINUTES); | |||
.setFactorUnit(WorkDuration.UNIT.HOURS); | |||
when(model.requirementsByRule(ruleKey)).thenReturn(requirement); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo( | |||
WorkDuration.createFromValueAndUnit((10 * 2), WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo((10 * 2) * 60 * 60); | |||
} | |||
@Test | |||
@@ -111,12 +107,11 @@ public class RuleDebtCalculatorTest { | |||
DefaultRequirement requirement = new DefaultRequirement() | |||
.setFunction("constant_issue") | |||
.setOffsetValue(5) | |||
.setOffsetUnit(WorkDuration.UNIT.MINUTES); | |||
.setOffsetUnit(WorkDuration.UNIT.DAYS); | |||
when(model.requirementsByRule(ruleKey)).thenReturn(requirement); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo( | |||
WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(5 * HOURS_IN_DAY * 60 * 60); | |||
} | |||
@Test | |||
@@ -140,8 +135,7 @@ public class RuleDebtCalculatorTest { | |||
when(model.requirementsByRule(ruleKey)).thenReturn(requirement); | |||
try { | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo( | |||
WorkDuration.createFromValueAndUnit(15, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)); | |||
assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(15 * 60); | |||
fail(); | |||
} catch (Exception e) { | |||
assertThat(e).isInstanceOf(IllegalArgumentException.class) |
@@ -35,7 +35,6 @@ import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.rules.*; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.batch.debt.RuleDebtCalculator; | |||
import java.util.Calendar; | |||
@@ -284,7 +283,7 @@ public class ModuleIssuesTest { | |||
.setRuleKey(SQUID_RULE_KEY) | |||
.setSeverity(Severity.CRITICAL); | |||
WorkDuration debt = WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.DAYS, 8); | |||
Long debt = 10L; | |||
when(technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).thenReturn(debt); | |||
when(filters.accept(issue, null)).thenReturn(true); | |||
@@ -292,7 +291,7 @@ public class ModuleIssuesTest { | |||
ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class); | |||
verify(cache).put(argument.capture()); | |||
assertThat(argument.getValue().technicalDebt()).isEqualTo(debt); | |||
assertThat(argument.getValue().debt()).isEqualTo(debt); | |||
} | |||
} |
@@ -29,10 +29,8 @@ import org.sonar.api.issue.internal.DefaultIssue; | |||
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.WorkDuration; | |||
import javax.annotation.Nullable; | |||
import java.util.Calendar; | |||
import java.util.Date; | |||
@@ -200,11 +198,11 @@ public class IssueUpdater implements BatchComponent, ServerComponent { | |||
return setEffortToFix(issue, currentEffort, context); | |||
} | |||
public boolean setTechnicalDebt(DefaultIssue issue, @Nullable WorkDuration value, IssueChangeContext context) { | |||
WorkDuration oldValue = issue.technicalDebt(); | |||
public boolean setTechnicalDebt(DefaultIssue issue, @Nullable Long value, IssueChangeContext context) { | |||
Long oldValue = issue.debt(); | |||
if (!Objects.equal(value, oldValue)) { | |||
issue.setTechnicalDebt(value); | |||
issue.setFieldChange(context, TECHNICAL_DEBT, oldValue != null ? oldValue.toLong() : null, value != null ? value.toLong() : null); | |||
issue.setDebt(value); | |||
issue.setFieldChange(context, TECHNICAL_DEBT, oldValue, value); | |||
issue.setUpdateDate(context.date()); | |||
issue.setChanged(true); | |||
return true; | |||
@@ -212,9 +210,9 @@ public class IssueUpdater implements BatchComponent, ServerComponent { | |||
return false; | |||
} | |||
public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable WorkDuration previousTechnicalDebt, IssueChangeContext context) { | |||
WorkDuration currentTechnicalDebt = issue.technicalDebt(); | |||
issue.setTechnicalDebt(previousTechnicalDebt); | |||
public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable Long previousTechnicalDebt, IssueChangeContext context) { | |||
Long currentTechnicalDebt = issue.debt(); | |||
issue.setDebt(previousTechnicalDebt); | |||
return setTechnicalDebt(issue, currentTechnicalDebt, context); | |||
} | |||
@@ -26,11 +26,9 @@ 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.KeyValueFormat; | |||
import org.sonar.api.utils.WorkDuration; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import java.io.Serializable; | |||
import java.util.Date; | |||
@@ -49,7 +47,7 @@ public final class IssueDto implements Serializable { | |||
private String message; | |||
private Integer line; | |||
private Double effortToFix; | |||
private Long technicalDebt; | |||
private Long debt; | |||
private String status; | |||
private String resolution; | |||
private String checksum; | |||
@@ -184,12 +182,12 @@ public final class IssueDto implements Serializable { | |||
} | |||
@CheckForNull | |||
public Long getTechnicalDebt() { | |||
return technicalDebt; | |||
public Long getDebt() { | |||
return debt; | |||
} | |||
public IssueDto setTechnicalDebt(@Nullable Long technicalDebt) { | |||
this.technicalDebt = technicalDebt; | |||
public IssueDto setDebt(@Nullable Long debt) { | |||
this.debt = debt; | |||
return this; | |||
} | |||
@@ -363,13 +361,12 @@ public final class IssueDto implements Serializable { | |||
} | |||
public static IssueDto toDtoForInsert(DefaultIssue issue, Long componentId, Long rootComponentId, Integer ruleId, Date now) { | |||
WorkDuration debt = issue.technicalDebt(); | |||
return new IssueDto() | |||
.setKee(issue.key()) | |||
.setLine(issue.line()) | |||
.setMessage(issue.message()) | |||
.setEffortToFix(issue.effortToFix()) | |||
.setTechnicalDebt(debt != null ? debt.toLong() : null) | |||
.setDebt(issue.debt()) | |||
.setResolution(issue.resolution()) | |||
.setStatus(issue.status()) | |||
.setSeverity(issue.severity()) | |||
@@ -393,13 +390,12 @@ public final class IssueDto implements Serializable { | |||
public static IssueDto toDtoForUpdate(DefaultIssue issue, Date now) { | |||
// Invariant fields, like key and rule, can't be updated | |||
WorkDuration debt = issue.technicalDebt(); | |||
return new IssueDto() | |||
.setKee(issue.key()) | |||
.setLine(issue.line()) | |||
.setMessage(issue.message()) | |||
.setEffortToFix(issue.effortToFix()) | |||
.setTechnicalDebt(debt != null ? debt.toLong() : null) | |||
.setDebt(issue.debt()) | |||
.setResolution(issue.resolution()) | |||
.setStatus(issue.status()) | |||
.setSeverity(issue.severity()) | |||
@@ -417,14 +413,14 @@ public final class IssueDto implements Serializable { | |||
.setUpdatedAt(now); | |||
} | |||
public DefaultIssue toDefaultIssue(@Nullable WorkDuration debt) { | |||
public DefaultIssue toDefaultIssue() { | |||
DefaultIssue issue = new DefaultIssue(); | |||
issue.setKey(kee); | |||
issue.setStatus(status); | |||
issue.setResolution(resolution); | |||
issue.setMessage(message); | |||
issue.setEffortToFix(effortToFix); | |||
issue.setTechnicalDebt(debt); | |||
issue.setDebt(debt); | |||
issue.setLine(line); | |||
issue.setSeverity(severity); | |||
issue.setReporter(reporter); |
@@ -16,7 +16,7 @@ | |||
i.message as message, | |||
i.line as line, | |||
i.effort_to_fix as effortToFix, | |||
i.technical_debt as technicalDebt, | |||
i.technical_debt as debt, | |||
i.status as status, | |||
i.resolution as resolution, | |||
i.checksum as checksum, | |||
@@ -66,7 +66,7 @@ | |||
resolution, checksum, reporter, assignee, author_login, issue_attributes, issue_creation_date, issue_update_date, | |||
issue_close_date, created_at, updated_at) | |||
VALUES (#{kee}, #{componentId}, #{rootComponentId}, #{ruleId}, #{actionPlanKey}, #{severity}, #{manualSeverity}, | |||
#{message}, #{line}, #{effortToFix}, #{technicalDebt}, #{status}, | |||
#{message}, #{line}, #{effortToFix}, #{debt}, #{status}, | |||
#{resolution}, #{checksum}, #{reporter}, #{assignee}, #{authorLogin}, #{issueAttributes}, #{issueCreationDate}, | |||
#{issueUpdateDate}, #{issueCloseDate}, #{createdAt}, #{updatedAt}) | |||
</insert> | |||
@@ -82,7 +82,7 @@ | |||
message=#{message}, | |||
line=#{line}, | |||
effort_to_fix=#{effortToFix}, | |||
technical_debt=#{technicalDebt}, | |||
technical_debt=#{debt}, | |||
status=#{status}, | |||
resolution=#{resolution}, | |||
checksum=#{checksum}, | |||
@@ -108,7 +108,7 @@ | |||
message=#{message}, | |||
line=#{line}, | |||
effort_to_fix=#{effortToFix}, | |||
technical_debt=#{technicalDebt}, | |||
technical_debt=#{debt}, | |||
status=#{status}, | |||
resolution=#{resolution}, | |||
checksum=#{checksum}, | |||
@@ -148,7 +148,7 @@ | |||
i.message as message, | |||
i.line as line, | |||
i.effort_to_fix as effortToFix, | |||
i.technical_debt as technicalDebt, | |||
i.technical_debt as debt, | |||
i.status as status, | |||
i.resolution as resolution, | |||
i.checksum as checksum, |
@@ -25,7 +25,6 @@ import org.sonar.api.issue.internal.DefaultIssue; | |||
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.WorkDuration; | |||
import org.sonar.core.user.DefaultUser; | |||
import java.util.Date; | |||
@@ -366,44 +365,44 @@ public class IssueUpdaterTest { | |||
@Test | |||
public void set_past_technical_debt() throws Exception { | |||
WorkDuration newDebt = WorkDuration.createFromValueAndUnit(15, WorkDuration.UNIT.DAYS, 8); | |||
WorkDuration previousDebt = WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.DAYS, 8); | |||
issue.setTechnicalDebt(newDebt); | |||
long newDebt = 15; | |||
long previousDebt = 10; | |||
issue.setDebt(newDebt); | |||
boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context); | |||
assertThat(updated).isTrue(); | |||
assertThat(issue.technicalDebt()).isEqualTo(newDebt); | |||
assertThat(issue.debt()).isEqualTo(newDebt); | |||
assertThat(issue.mustSendNotifications()).isFalse(); | |||
FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT); | |||
assertThat(diff.oldValue()).isEqualTo(previousDebt.toLong()); | |||
assertThat(diff.newValue()).isEqualTo(newDebt.toLong()); | |||
assertThat(diff.oldValue()).isEqualTo(previousDebt); | |||
assertThat(diff.newValue()).isEqualTo(newDebt); | |||
} | |||
@Test | |||
public void set_past_technical_debt_without_previous_value() throws Exception { | |||
WorkDuration newDebt = WorkDuration.createFromValueAndUnit(15, WorkDuration.UNIT.DAYS, 8); | |||
issue.setTechnicalDebt(newDebt); | |||
long newDebt = 15; | |||
issue.setDebt(newDebt); | |||
boolean updated = updater.setPastTechnicalDebt(issue, null, context); | |||
assertThat(updated).isTrue(); | |||
assertThat(issue.technicalDebt()).isEqualTo(newDebt); | |||
assertThat(issue.debt()).isEqualTo(newDebt); | |||
assertThat(issue.mustSendNotifications()).isFalse(); | |||
FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT); | |||
assertThat(diff.oldValue()).isNull(); | |||
assertThat(diff.newValue()).isEqualTo(newDebt.toLong()); | |||
assertThat(diff.newValue()).isEqualTo(newDebt); | |||
} | |||
@Test | |||
public void set_past_technical_debt_with_null_new_value() throws Exception { | |||
issue.setTechnicalDebt(null); | |||
WorkDuration previousDebt = WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.DAYS, 8); | |||
issue.setDebt(null); | |||
long previousDebt = 10; | |||
boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context); | |||
assertThat(updated).isTrue(); | |||
assertThat(issue.technicalDebt()).isNull(); | |||
assertThat(issue.debt()).isNull(); | |||
assertThat(issue.mustSendNotifications()).isFalse(); | |||
FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT); | |||
assertThat(diff.oldValue()).isEqualTo(previousDebt.toLong()); | |||
assertThat(diff.oldValue()).isEqualTo(previousDebt); | |||
assertThat(diff.newValue()).isNull(); | |||
} | |||
@@ -25,7 +25,6 @@ import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.internal.DefaultIssue; | |||
import org.sonar.api.utils.WorkDuration; | |||
import java.util.Calendar; | |||
import java.util.Date; | |||
@@ -66,7 +65,7 @@ public class IssueDtoTest { | |||
.setStatus(Issue.STATUS_CLOSED) | |||
.setResolution(Issue.RESOLUTION_FALSE_POSITIVE) | |||
.setEffortToFix(15.0) | |||
.setTechnicalDebt(101010L) | |||
.setDebt(10L) | |||
.setLine(6) | |||
.setSeverity("BLOCKER") | |||
.setMessage("message") | |||
@@ -79,7 +78,7 @@ public class IssueDtoTest { | |||
.setIssueUpdateDate(updatedAt) | |||
.setIssueCloseDate(closedAt); | |||
DefaultIssue issue = dto.toDefaultIssue(WorkDuration.create(10, 10, 10, 8)); | |||
DefaultIssue issue = dto.toDefaultIssue(); | |||
assertThat(issue.key()).isEqualTo("100"); | |||
assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle"); | |||
assertThat(issue.componentKey()).isEqualTo("org.sonar.sample:Sample"); | |||
@@ -87,7 +86,7 @@ public class IssueDtoTest { | |||
assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED); | |||
assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FALSE_POSITIVE); | |||
assertThat(issue.effortToFix()).isEqualTo(15.0); | |||
assertThat(issue.technicalDebt()).isNotNull(); | |||
assertThat(issue.debt()).isEqualTo(10L); | |||
assertThat(issue.line()).isEqualTo(6); | |||
assertThat(issue.severity()).isEqualTo("BLOCKER"); | |||
assertThat(issue.message()).isEqualTo("message"); |
@@ -54,7 +54,7 @@ public class IssueMapperTest extends AbstractDaoTestCase { | |||
dto.setKee("ABCDE"); | |||
dto.setLine(500); | |||
dto.setEffortToFix(3.14); | |||
dto.setTechnicalDebt(10L); | |||
dto.setDebt(10L); | |||
dto.setResolution("FIXED"); | |||
dto.setStatus("RESOLVED"); | |||
dto.setSeverity("BLOCKER"); | |||
@@ -89,7 +89,7 @@ public class IssueMapperTest extends AbstractDaoTestCase { | |||
dto.setKee("ABCDE"); | |||
dto.setLine(500); | |||
dto.setEffortToFix(3.14); | |||
dto.setTechnicalDebt(10L); | |||
dto.setDebt(10L); | |||
dto.setResolution("FIXED"); | |||
dto.setStatus("RESOLVED"); | |||
dto.setSeverity("BLOCKER"); | |||
@@ -124,7 +124,7 @@ public class IssueMapperTest extends AbstractDaoTestCase { | |||
dto.setKee("ABCDE"); | |||
dto.setLine(500); | |||
dto.setEffortToFix(3.14); | |||
dto.setTechnicalDebt(10L); | |||
dto.setDebt(10L); | |||
dto.setResolution("FIXED"); | |||
dto.setStatus("RESOLVED"); | |||
dto.setSeverity("BLOCKER"); | |||
@@ -162,7 +162,7 @@ public class IssueMapperTest extends AbstractDaoTestCase { | |||
dto.setKee("ABCDE"); | |||
dto.setLine(500); | |||
dto.setEffortToFix(3.14); | |||
dto.setTechnicalDebt(10L); | |||
dto.setDebt(10L); | |||
dto.setResolution("FIXED"); | |||
dto.setStatus("RESOLVED"); | |||
dto.setSeverity("BLOCKER"); |
@@ -28,7 +28,6 @@ import org.sonar.api.rules.Rule; | |||
import org.sonar.api.rules.RuleFinder; | |||
import org.sonar.api.rules.RuleQuery; | |||
import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.core.persistence.AbstractDaoTestCase; | |||
import org.sonar.core.persistence.MyBatis; | |||
@@ -54,7 +53,7 @@ public class IssueStorageTest extends AbstractDaoTestCase { | |||
.setRuleKey(RuleKey.of("squid", "AvoidCycle")) | |||
.setLine(5000) | |||
.setTechnicalDebt(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, 8)) | |||
.setDebt(10L) | |||
.setReporter("emmerik") | |||
.setResolution("OPEN") | |||
.setStatus("OPEN") | |||
@@ -88,7 +87,7 @@ public class IssueStorageTest extends AbstractDaoTestCase { | |||
// updated fields | |||
.setLine(5000) | |||
.setTechnicalDebt(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, 8)) | |||
.setDebt(10L) | |||
.setChecksum("FFFFF") | |||
.setAuthorLogin("simon") | |||
.setAssignee("loic") |
@@ -33,11 +33,9 @@ import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.IssueComment; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.utils.WorkDuration; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import java.io.Serializable; | |||
import java.util.*; | |||
@@ -59,7 +57,7 @@ public class DefaultIssue implements Issue { | |||
private String message; | |||
private Integer line; | |||
private Double effortToFix; | |||
private WorkDuration technicalDebt; | |||
private Long debt; | |||
private String status; | |||
private String resolution; | |||
private String reporter; | |||
@@ -196,12 +194,12 @@ public class DefaultIssue implements Issue { | |||
* Elapsed time to fix the issue | |||
*/ | |||
@CheckForNull | |||
public WorkDuration technicalDebt() { | |||
return technicalDebt; | |||
public Long debt() { | |||
return debt; | |||
} | |||
public DefaultIssue setTechnicalDebt(@Nullable WorkDuration t) { | |||
this.technicalDebt = t; | |||
public DefaultIssue setDebt(@Nullable Long t) { | |||
this.debt = t; | |||
return this; | |||
} | |||
@@ -48,4 +48,11 @@ public final class WorkDurationFactory implements BatchComponent, ServerComponen | |||
return settings.getInt(CoreProperties.HOURS_IN_DAY); | |||
} | |||
/** | |||
* @since 4.3 | |||
*/ | |||
public WorkDuration createFromSeconds(long durationInSeconds) { | |||
return WorkDuration.createFromSeconds(durationInSeconds, hoursInDay); | |||
} | |||
} |
@@ -25,7 +25,6 @@ import org.junit.Test; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.IssueComment; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.utils.WorkDuration; | |||
import java.text.SimpleDateFormat; | |||
import java.util.List; | |||
@@ -50,7 +49,7 @@ public class DefaultIssueTest { | |||
.setMessage("a message") | |||
.setLine(7) | |||
.setEffortToFix(1.2d) | |||
.setTechnicalDebt(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8)) | |||
.setDebt(28800L) | |||
.setActionPlanKey("BCDE") | |||
.setStatus(Issue.STATUS_CLOSED) | |||
.setResolution(Issue.RESOLUTION_FIXED) | |||
@@ -78,7 +77,7 @@ public class DefaultIssueTest { | |||
assertThat(issue.message()).isEqualTo("a message"); | |||
assertThat(issue.line()).isEqualTo(7); | |||
assertThat(issue.effortToFix()).isEqualTo(1.2d); | |||
assertThat(issue.technicalDebt()).isEqualTo(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8)); | |||
assertThat(issue.debt()).isEqualTo(28800L); | |||
assertThat(issue.actionPlanKey()).isEqualTo("BCDE"); | |||
assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED); | |||
assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED); |
@@ -41,9 +41,9 @@ public class WorkDurationFactoryTest { | |||
@Test | |||
public void create_from_working_value() throws Exception { | |||
// 1 working day -> 8 hours | |||
assertThat(factory.createFromWorkingValue(1, WorkDuration.UNIT.DAYS).toSeconds()).isEqualTo(8*60*60); | |||
assertThat(factory.createFromWorkingValue(1, WorkDuration.UNIT.DAYS).toSeconds()).isEqualTo(8 * 60 * 60); | |||
// 8 hours | |||
assertThat(factory.createFromWorkingValue(8, WorkDuration.UNIT.HOURS).toSeconds()).isEqualTo(8*60*60); | |||
assertThat(factory.createFromWorkingValue(8, WorkDuration.UNIT.HOURS).toSeconds()).isEqualTo(8 * 60 * 60); | |||
} | |||
@Test | |||
@@ -53,4 +53,12 @@ public class WorkDurationFactoryTest { | |||
assertThat(workDuration.hours()).isEqualTo(0); | |||
assertThat(workDuration.minutes()).isEqualTo(1); | |||
} | |||
@Test | |||
public void create_from_seconds() throws Exception { | |||
WorkDuration workDuration = factory.createFromSeconds(8 * 60 * 60L); | |||
assertThat(workDuration.days()).isEqualTo(1); | |||
assertThat(workDuration.hours()).isEqualTo(0); | |||
assertThat(workDuration.minutes()).isEqualTo(0); | |||
} | |||
} |
@@ -27,7 +27,6 @@ import org.sonar.api.issue.ActionPlan; | |||
import org.sonar.api.issue.IssueQuery; | |||
import org.sonar.api.issue.internal.DefaultIssue; | |||
import org.sonar.api.issue.internal.IssueChangeContext; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.issue.ActionPlanDeadlineComparator; | |||
import org.sonar.core.issue.ActionPlanStats; | |||
@@ -41,7 +40,6 @@ import org.sonar.core.user.AuthorizationDao; | |||
import org.sonar.server.user.UserSession; | |||
import javax.annotation.CheckForNull; | |||
import java.util.*; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
@@ -58,10 +56,9 @@ public class ActionPlanService implements ServerComponent { | |||
private final IssueDao issueDao; | |||
private final IssueUpdater issueUpdater; | |||
private final IssueStorage issueStorage; | |||
private final WorkDurationFactory workDurationFactory; | |||
public ActionPlanService(ActionPlanDao actionPlanDao, ActionPlanStatsDao actionPlanStatsDao, ResourceDao resourceDao, AuthorizationDao authorizationDao, | |||
IssueDao issueDao, IssueUpdater issueUpdater, IssueStorage issueStorage, WorkDurationFactory workDurationFactory) { | |||
IssueDao issueDao, IssueUpdater issueUpdater, IssueStorage issueStorage) { | |||
this.actionPlanDao = actionPlanDao; | |||
this.actionPlanStatsDao = actionPlanStatsDao; | |||
this.resourceDao = resourceDao; | |||
@@ -69,7 +66,6 @@ public class ActionPlanService implements ServerComponent { | |||
this.issueDao = issueDao; | |||
this.issueUpdater = issueUpdater; | |||
this.issueStorage = issueStorage; | |||
this.workDurationFactory = workDurationFactory; | |||
} | |||
public ActionPlan create(ActionPlan actionPlan, UserSession userSession) { | |||
@@ -103,8 +99,7 @@ public class ActionPlanService implements ServerComponent { | |||
IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.login()); | |||
List<DefaultIssue> issues = newArrayList(); | |||
for (IssueDto issueDto : dtos) { | |||
Long debt = issueDto.getTechnicalDebt(); | |||
DefaultIssue issue = issueDto.toDefaultIssue(debt != null ? workDurationFactory.createFromWorkingLong(debt) : null); | |||
DefaultIssue issue = issueDto.toDefaultIssue(); | |||
// Unplan issue | |||
if (issueUpdater.plan(issue, null, context)) { | |||
issues.add(issue); |
@@ -32,7 +32,6 @@ import org.sonar.api.rules.Rule; | |||
import org.sonar.api.user.User; | |||
import org.sonar.api.user.UserFinder; | |||
import org.sonar.api.utils.Paging; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.core.issue.DefaultIssueQueryResult; | |||
import org.sonar.core.issue.db.IssueChangeDao; | |||
import org.sonar.core.issue.db.IssueDao; | |||
@@ -43,7 +42,6 @@ import org.sonar.core.rule.DefaultRuleFinder; | |||
import org.sonar.server.user.UserSession; | |||
import javax.annotation.CheckForNull; | |||
import java.util.*; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
@@ -62,14 +60,13 @@ public class DefaultIssueFinder implements IssueFinder { | |||
private final UserFinder userFinder; | |||
private final ResourceDao resourceDao; | |||
private final ActionPlanService actionPlanService; | |||
private final WorkDurationFactory workDurationFactory; | |||
public DefaultIssueFinder(MyBatis myBatis, | |||
IssueDao issueDao, IssueChangeDao issueChangeDao, | |||
DefaultRuleFinder ruleFinder, | |||
UserFinder userFinder, | |||
ResourceDao resourceDao, | |||
ActionPlanService actionPlanService, WorkDurationFactory workDurationFactory) { | |||
ActionPlanService actionPlanService) { | |||
this.myBatis = myBatis; | |||
this.issueDao = issueDao; | |||
this.issueChangeDao = issueChangeDao; | |||
@@ -77,7 +74,6 @@ public class DefaultIssueFinder implements IssueFinder { | |||
this.userFinder = userFinder; | |||
this.resourceDao = resourceDao; | |||
this.actionPlanService = actionPlanService; | |||
this.workDurationFactory = workDurationFactory; | |||
} | |||
DefaultIssue findByKey(String issueKey, String requiredRole) { | |||
@@ -89,8 +85,7 @@ public class DefaultIssueFinder implements IssueFinder { | |||
throw new IllegalStateException("User does not have the required role required to change the issue: " + issueKey); | |||
} | |||
Long debt = dto.getTechnicalDebt(); | |||
return dto.toDefaultIssue(debt != null ? workDurationFactory.createFromWorkingLong(debt) : null); | |||
return dto.toDefaultIssue(); | |||
} | |||
@Override | |||
@@ -121,8 +116,7 @@ public class DefaultIssueFinder implements IssueFinder { | |||
Set<String> actionPlanKeys = Sets.newHashSet(); | |||
Set<String> users = Sets.newHashSet(); | |||
for (IssueDto dto : pagedSortedIssues) { | |||
Long debt = dto.getTechnicalDebt(); | |||
DefaultIssue defaultIssue = dto.toDefaultIssue(debt != null ? workDurationFactory.createFromWorkingLong(debt) : null); | |||
DefaultIssue defaultIssue = dto.toDefaultIssue(); | |||
issuesByKey.put(dto.getKee(), defaultIssue); | |||
issues.add(defaultIssue); | |||
ruleIds.add(dto.getRuleId()); | |||
@@ -205,11 +199,7 @@ public class DefaultIssueFinder implements IssueFinder { | |||
@CheckForNull | |||
public Issue findByKey(String key) { | |||
IssueDto dto = issueDao.selectByKey(key); | |||
if (dto == null) { | |||
return null; | |||
} | |||
Long debt = dto.getTechnicalDebt(); | |||
return dto.toDefaultIssue(debt != null ? workDurationFactory.createFromWorkingLong(debt) : null); | |||
return dto != null ? dto.toDefaultIssue() : null; | |||
} | |||
} |
@@ -76,10 +76,10 @@ public class IssueChangelogFormatter implements ServerComponent { | |||
String oldValueString = oldValue != null && !"".equals(oldValue) ? oldValue.toString() : null; | |||
if (IssueUpdater.TECHNICAL_DEBT.equals(key)) { | |||
if (newValueString != null) { | |||
newValueString = debtFormatter.format(locale, workDurationFactory.createFromWorkingLong(Long.parseLong(newValueString))); | |||
newValueString = debtFormatter.formatWorkDuration(locale, workDurationFactory.createFromWorkingLong(Long.parseLong(newValueString))); | |||
} | |||
if (oldValueString != null) { | |||
oldValueString = debtFormatter.format(locale, workDurationFactory.createFromWorkingLong(Long.parseLong(oldValueString))); | |||
oldValueString = debtFormatter.formatWorkDuration(locale, workDurationFactory.createFromWorkingLong(Long.parseLong(oldValueString))); | |||
} | |||
} | |||
return new IssueChangelogDiffFormat(oldValueString, newValueString); |
@@ -31,7 +31,6 @@ import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.technicaldebt.server.Characteristic; | |||
import org.sonar.api.user.User; | |||
import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.text.JsonWriter; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.issue.workflow.Transition; | |||
@@ -47,7 +46,6 @@ import org.sonar.server.user.UserSession; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import java.util.Arrays; | |||
import java.util.Date; | |||
import java.util.List; | |||
@@ -101,7 +99,7 @@ public class IssueShowWsHandler implements RequestHandler { | |||
Component project = result.project(issue); | |||
String actionPlanKey = issue.actionPlanKey(); | |||
ActionPlan actionPlan = result.actionPlan(issue); | |||
WorkDuration technicalDebt = issue.technicalDebt(); | |||
Long technicalDebt = issue.debt(); | |||
Date updateDate = issue.updateDate(); | |||
Date closeDate = issue.closeDate(); | |||
@@ -22,6 +22,7 @@ package org.sonar.server.technicaldebt; | |||
import org.sonar.api.ServerComponent; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.core.i18n.DefaultI18n; | |||
import java.util.Locale; | |||
@@ -29,12 +30,18 @@ import java.util.Locale; | |||
public class DebtFormatter implements ServerComponent { | |||
private final DefaultI18n defaultI18n; | |||
private final WorkDurationFactory workDurationFactory; | |||
public DebtFormatter(DefaultI18n defaultI18n) { | |||
public DebtFormatter(DefaultI18n defaultI18n, WorkDurationFactory workDurationFactory) { | |||
this.defaultI18n = defaultI18n; | |||
this.workDurationFactory = workDurationFactory; | |||
} | |||
public String format(Locale locale, WorkDuration debt) { | |||
public String format(Locale locale, long debt) { | |||
return formatWorkDuration(locale, workDurationFactory.createFromSeconds(debt)); | |||
} | |||
public String formatWorkDuration(Locale locale, WorkDuration debt) { | |||
StringBuilder message = new StringBuilder(); | |||
if (debt.days() > 0) { | |||
message.append(defaultI18n.message(locale, "issue.technical_debt.x_days", null, debt.days())); |
@@ -28,7 +28,6 @@ import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager; | |||
import org.sonar.server.user.UserSession; | |||
import javax.annotation.CheckForNull; | |||
import java.util.List; | |||
public class DebtService implements ServerComponent { | |||
@@ -43,8 +42,8 @@ public class DebtService implements ServerComponent { | |||
this.workDurationFactory = workDurationFactory; | |||
} | |||
public String format(WorkDuration technicalDebt) { | |||
return debtFormatter.format(UserSession.get().locale(), technicalDebt); | |||
public String format(long debt) { | |||
return debtFormatter.format(UserSession.get().locale(), debt); | |||
} | |||
public WorkDuration toTechnicalDebt(String technicalDebtInLong) { |
@@ -33,7 +33,7 @@ class Issue | |||
hash[:message] = issue.message if issue.message | |||
hash[:line] = issue.line.to_i if issue.line | |||
hash[:effortToFix] = issue.effortToFix.to_f if issue.effortToFix | |||
hash[:technicalDebt] = technical_debt_to_hash(issue.technicalDebt) if issue.technicalDebt | |||
hash[:technicalDebt] = technical_debt_to_hash(issue.debt) if issue.debt | |||
hash[:reporter] = issue.reporter if issue.reporter | |||
hash[:assignee] = issue.assignee if issue.assignee | |||
hash[:author] = issue.authorLogin if issue.authorLogin |
@@ -95,8 +95,8 @@ | |||
</li> | |||
<% end %> | |||
<% end %> | |||
<% if issue.technicalDebt %> | |||
<li><%= message('issue.debt') -%> <%= Internal.technical_debt.format(issue.technicalDebt) -%></li> | |||
<% if issue.debt %> | |||
<li><%= message('issue.debt') -%> <%= Internal.technical_debt.format(issue.debt) -%></li> | |||
<% end %> | |||
<% if issue.authorLogin %> | |||
<li><%= message('issue.authorLogin') -%> <%= issue.authorLogin -%></li> |
@@ -23,14 +23,11 @@ package org.sonar.server.issue; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.issue.ActionPlan; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.IssueQuery; | |||
import org.sonar.api.issue.internal.DefaultIssue; | |||
import org.sonar.api.issue.internal.IssueChangeContext; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.issue.ActionPlanStats; | |||
import org.sonar.core.issue.DefaultActionPlan; | |||
@@ -72,10 +69,7 @@ public class ActionPlanServiceTest { | |||
when(userSession.userId()).thenReturn(10); | |||
when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(true); | |||
Settings settings = new Settings(); | |||
settings.setProperty(CoreProperties.HOURS_IN_DAY, 8); | |||
actionPlanService = new ActionPlanService(actionPlanDao, actionPlanStatsDao, resourceDao, authorizationDao, issueDao, issueUpdater, issueStorage, | |||
new WorkDurationFactory(settings)); | |||
actionPlanService = new ActionPlanService(actionPlanDao, actionPlanStatsDao, resourceDao, authorizationDao, issueDao, issueUpdater, issueStorage); | |||
} | |||
@Test |
@@ -34,8 +34,6 @@ import org.sonar.api.issue.internal.DefaultIssue; | |||
import org.sonar.api.rules.Rule; | |||
import org.sonar.api.user.User; | |||
import org.sonar.api.user.UserFinder; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.core.component.ComponentDto; | |||
import org.sonar.core.issue.DefaultActionPlan; | |||
import org.sonar.core.issue.db.IssueChangeDao; | |||
@@ -76,7 +74,7 @@ public class DefaultIssueFinderTest { | |||
public void setUp() throws Exception { | |||
Settings settings = new Settings(); | |||
settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY); | |||
finder = new DefaultIssueFinder(mybatis, issueDao, issueChangeDao, ruleFinder, userFinder, resourceDao, actionPlanService, new WorkDurationFactory(settings)); | |||
finder = new DefaultIssueFinder(mybatis, issueDao, issueChangeDao, ruleFinder, userFinder, resourceDao, actionPlanService); | |||
} | |||
@Test | |||
@@ -326,7 +324,7 @@ public class DefaultIssueFinderTest { | |||
.setRootComponentKey_unit_test_only("struts") | |||
.setRuleKey_unit_test_only("squid", "AvoidCycle") | |||
.setStatus("OPEN").setResolution("OPEN") | |||
.setTechnicalDebt(10L); | |||
.setDebt(10L); | |||
List<IssueDto> dtoList = newArrayList(issue); | |||
when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList); | |||
@@ -335,7 +333,7 @@ public class DefaultIssueFinderTest { | |||
assertThat(results.issues()).hasSize(1); | |||
DefaultIssue result = (DefaultIssue) results.issues().iterator().next(); | |||
assertThat(result.technicalDebt()).isEqualTo(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)); | |||
assertThat(result.debt()).isEqualTo(10L); | |||
} | |||
} |
@@ -137,8 +137,8 @@ public class IssueChangelogFormatterTest { | |||
FieldDiffs diffs = new FieldDiffs(); | |||
diffs.setDiff("technicalDebt", "500", "10000"); | |||
when(debtFormatter.format(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY))).thenReturn("5 hours"); | |||
when(debtFormatter.format(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, HOURS_IN_DAY))).thenReturn("1 days"); | |||
when(debtFormatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY))).thenReturn("5 hours"); | |||
when(debtFormatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, HOURS_IN_DAY))).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"); | |||
@@ -155,7 +155,7 @@ public class IssueChangelogFormatterTest { | |||
FieldDiffs diffs = new FieldDiffs(); | |||
diffs.setDiff("technicalDebt", null, "10000"); | |||
when(debtFormatter.format(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8))).thenReturn("1 days"); | |||
when(debtFormatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, 8))).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"); |
@@ -42,7 +42,6 @@ import org.sonar.api.technicaldebt.server.Characteristic; | |||
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.WorkDuration; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.issue.DefaultActionPlan; | |||
import org.sonar.core.issue.DefaultIssueQueryResult; | |||
@@ -209,8 +208,8 @@ public class IssueShowWsHandlerTest { | |||
@Test | |||
public void show_issue_with_technical_debt() throws Exception { | |||
WorkDuration technicalDebt = WorkDuration.create(0, 2, 1, 8); | |||
Issue issue = createStandardIssue().setTechnicalDebt(technicalDebt); | |||
Long technicalDebt = 7260L; | |||
Issue issue = createStandardIssue().setDebt(technicalDebt); | |||
issues.add(issue); | |||
when(debtFormatter.format(any(Locale.class), eq(technicalDebt))).thenReturn("2 hours 1 minutes"); | |||
@@ -222,8 +221,7 @@ public class IssueShowWsHandlerTest { | |||
@Test | |||
public void show_issue_with_characteristics() throws Exception { | |||
WorkDuration technicalDebt = WorkDuration.create(0, 2, 1, 8); | |||
Issue issue = createStandardIssue().setTechnicalDebt(technicalDebt); | |||
Issue issue = createStandardIssue().setDebt(7260L); | |||
issues.add(issue); | |||
Characteristic requirement = new DefaultCharacteristic().setId(5).setParentId(2).setRootId(1); |
@@ -20,8 +20,12 @@ | |||
package org.sonar.server.technicaldebt; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.WorkDuration; | |||
import org.sonar.api.utils.WorkDurationFactory; | |||
import org.sonar.core.i18n.DefaultI18n; | |||
import java.util.Locale; | |||
@@ -33,23 +37,51 @@ import static org.mockito.Mockito.when; | |||
public class DebtFormatterTest { | |||
private static final Locale DEFAULT_LOCALE = Locale.getDefault(); | |||
private static final int HOURS_IN_DAY = 8; | |||
private static final long ONE_MINUTE = 60; | |||
private static final long ONE_HOUR = 60 * ONE_MINUTE; | |||
private static final long ONE_DAY = HOURS_IN_DAY * ONE_HOUR; | |||
DefaultI18n i18n = mock(DefaultI18n.class); | |||
DebtFormatter formatter = new DebtFormatter(i18n); | |||
DebtFormatter formatter; | |||
@Before | |||
public void setUp() throws Exception { | |||
Settings settings = new Settings(); | |||
settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(HOURS_IN_DAY)); | |||
formatter = new DebtFormatter(i18n, new WorkDurationFactory(settings)); | |||
@Test | |||
public void format() { | |||
when(i18n.message(DEFAULT_LOCALE, "issue.technical_debt.x_days", null, 5)).thenReturn("5 days"); | |||
when(i18n.message(DEFAULT_LOCALE, "issue.technical_debt.x_hours", null, 2)).thenReturn("2 hours"); | |||
when(i18n.message(DEFAULT_LOCALE, "issue.technical_debt.x_minutes", null, 1)).thenReturn("1 minutes"); | |||
} | |||
@Test | |||
public void format_from_seconds() { | |||
assertThat(formatter.format(DEFAULT_LOCALE, 5 * ONE_DAY)).isEqualTo("5 days"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, 2 * ONE_HOUR)).isEqualTo("2 hours"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, ONE_MINUTE)).isEqualTo("1 minutes"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.DAYS, 8))).isEqualTo("5 days"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.HOURS, 8))).isEqualTo("2 hours"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.MINUTES, 8))).isEqualTo("1 minutes"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, 5 * ONE_DAY + 2 * ONE_HOUR)).isEqualTo("5 days 2 hours"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, 2 * ONE_HOUR + ONE_MINUTE)).isEqualTo("2 hours 1 minutes"); | |||
} | |||
@Test | |||
public void format_from_seconds_not_display_minutes_if_hours_exists() { | |||
// 5 days 2 hours 1 minute -> 1 minute is not displayed | |||
assertThat(formatter.format(DEFAULT_LOCALE, 5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE)).isEqualTo("5 days 2 hours"); | |||
} | |||
@Test | |||
public void format_work_duration() { | |||
assertThat(formatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.DAYS, HOURS_IN_DAY))).isEqualTo("5 days"); | |||
assertThat(formatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.HOURS, HOURS_IN_DAY))).isEqualTo("2 hours"); | |||
assertThat(formatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY))).isEqualTo("1 minutes"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, WorkDuration.create(5, 2, 0, 8))).isEqualTo("5 days 2 hours"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, WorkDuration.create(0, 2, 1, 8))).isEqualTo("2 hours 1 minutes"); | |||
assertThat(formatter.format(DEFAULT_LOCALE, WorkDuration.create(5, 2, 10, 8))).isEqualTo("5 days 2 hours"); | |||
assertThat(formatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.create(5, 2, 0, HOURS_IN_DAY))).isEqualTo("5 days 2 hours"); | |||
assertThat(formatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.create(0, 2, 1, HOURS_IN_DAY))).isEqualTo("2 hours 1 minutes"); | |||
assertThat(formatter.formatWorkDuration(DEFAULT_LOCALE, WorkDuration.create(5, 2, 10, HOURS_IN_DAY))).isEqualTo("5 days 2 hours"); | |||
} | |||
} |
@@ -55,9 +55,8 @@ public class DebtServiceTest { | |||
@Test | |||
public void format() { | |||
WorkDuration technicalDebt = WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY); | |||
service.format(technicalDebt); | |||
verify(debtFormatter).format(any(Locale.class), eq(technicalDebt)); | |||
service.format(10L); | |||
verify(debtFormatter).format(any(Locale.class), eq(10L)); | |||
} | |||
@Test |