Selaa lähdekoodia

SONAR-4996 Update issue debt to seconds (backend + display)

tags/4.3
Julien Lancelot 10 vuotta sitten
vanhempi
commit
23124a1815
36 muutettua tiedostoa jossa 266 lisäystä ja 248 poistoa
  1. 3
    7
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
  2. 8
    6
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/TechnicalDebtDecorator.java
  3. 4
    5
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
  4. 49
    45
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/NewTechnicalDebtDecoratorTest.java
  5. 12
    17
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/TechnicalDebtDecoratorTest.java
  6. 3
    3
      sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java
  7. 22
    10
      sonar-batch/src/main/java/org/sonar/batch/debt/RuleDebtCalculator.java
  8. 1
    1
      sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
  9. 10
    6
      sonar-batch/src/test/java/org/sonar/batch/debt/IssueChangelogDebtCalculatorTest.java
  10. 8
    14
      sonar-batch/src/test/java/org/sonar/batch/debt/RuleDebtCalculatorTest.java
  11. 2
    3
      sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
  12. 7
    9
      sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java
  13. 9
    13
      sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
  14. 5
    5
      sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml
  15. 14
    15
      sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java
  16. 3
    4
      sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java
  17. 4
    4
      sonar-core/src/test/java/org/sonar/core/issue/db/IssueMapperTest.java
  18. 2
    3
      sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java
  19. 5
    7
      sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java
  20. 7
    0
      sonar-plugin-api/src/main/java/org/sonar/api/utils/WorkDurationFactory.java
  21. 2
    3
      sonar-plugin-api/src/test/java/org/sonar/api/issue/internal/DefaultIssueTest.java
  22. 10
    2
      sonar-plugin-api/src/test/java/org/sonar/api/utils/WorkDurationFactoryTest.java
  23. 2
    7
      sonar-server/src/main/java/org/sonar/server/issue/ActionPlanService.java
  24. 4
    14
      sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java
  25. 2
    2
      sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java
  26. 1
    3
      sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java
  27. 9
    2
      sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtFormatter.java
  28. 2
    3
      sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java
  29. 1
    1
      sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb
  30. 2
    2
      sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb
  31. 1
    7
      sonar-server/src/test/java/org/sonar/server/issue/ActionPlanServiceTest.java
  32. 3
    5
      sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java
  33. 3
    3
      sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java
  34. 3
    5
      sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java
  35. 41
    9
      sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtFormatterTest.java
  36. 2
    3
      sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java

+ 3
- 7
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java Näytä tiedosto

@@ -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);
}

+ 8
- 6
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/TechnicalDebtDecorator.java Näytä tiedosto

@@ -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) {

+ 4
- 5
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java Näytä tiedosto

@@ -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);

+ 49
- 45
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/NewTechnicalDebtDecoratorTest.java Näytä tiedosto

@@ -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));

+ 12
- 17
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/TechnicalDebtDecoratorTest.java Näytä tiedosto

@@ -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");

+ 3
- 3
sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java Näytä tiedosto

@@ -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) {

+ 22
- 10
sonar-batch/src/main/java/org/sonar/batch/debt/RuleDebtCalculator.java Näytä tiedosto

@@ -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);
}

}

+ 1
- 1
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java Näytä tiedosto

@@ -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()));
}

}

+ 10
- 6
sonar-batch/src/test/java/org/sonar/batch/debt/IssueChangelogDebtCalculatorTest.java Näytä tiedosto

@@ -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)
)

+ 8
- 14
sonar-batch/src/test/java/org/sonar/batch/debt/RuleDebtCalculatorTest.java Näytä tiedosto

@@ -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)

+ 2
- 3
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java Näytä tiedosto

@@ -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);
}

}

+ 7
- 9
sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java Näytä tiedosto

@@ -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);
}


+ 9
- 13
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java Näytä tiedosto

@@ -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);

+ 5
- 5
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml Näytä tiedosto

@@ -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,

+ 14
- 15
sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java Näytä tiedosto

@@ -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();
}


+ 3
- 4
sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java Näytä tiedosto

@@ -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");

+ 4
- 4
sonar-core/src/test/java/org/sonar/core/issue/db/IssueMapperTest.java Näytä tiedosto

@@ -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");

+ 2
- 3
sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java Näytä tiedosto

@@ -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")

+ 5
- 7
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java Näytä tiedosto

@@ -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;
}


+ 7
- 0
sonar-plugin-api/src/main/java/org/sonar/api/utils/WorkDurationFactory.java Näytä tiedosto

@@ -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);
}

}

+ 2
- 3
sonar-plugin-api/src/test/java/org/sonar/api/issue/internal/DefaultIssueTest.java Näytä tiedosto

@@ -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);

+ 10
- 2
sonar-plugin-api/src/test/java/org/sonar/api/utils/WorkDurationFactoryTest.java Näytä tiedosto

@@ -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);
}
}

+ 2
- 7
sonar-server/src/main/java/org/sonar/server/issue/ActionPlanService.java Näytä tiedosto

@@ -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);

+ 4
- 14
sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java Näytä tiedosto

@@ -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;
}

}

+ 2
- 2
sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java Näytä tiedosto

@@ -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);

+ 1
- 3
sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java Näytä tiedosto

@@ -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();


+ 9
- 2
sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtFormatter.java Näytä tiedosto

@@ -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()));

+ 2
- 3
sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java Näytä tiedosto

@@ -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) {

+ 1
- 1
sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb Näytä tiedosto

@@ -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

+ 2
- 2
sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb Näytä tiedosto

@@ -95,8 +95,8 @@
</li>
<% end %>
<% end %>
<% if issue.technicalDebt %>
<li><%= message('issue.debt') -%>&nbsp;<%= Internal.technical_debt.format(issue.technicalDebt) -%></li>
<% if issue.debt %>
<li><%= message('issue.debt') -%>&nbsp;<%= Internal.technical_debt.format(issue.debt) -%></li>
<% end %>
<% if issue.authorLogin %>
<li><%= message('issue.authorLogin') -%>&nbsp;<%= issue.authorLogin -%></li>

+ 1
- 7
sonar-server/src/test/java/org/sonar/server/issue/ActionPlanServiceTest.java Näytä tiedosto

@@ -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

+ 3
- 5
sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java Näytä tiedosto

@@ -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);
}

}

+ 3
- 3
sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java Näytä tiedosto

@@ -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");

+ 3
- 5
sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java Näytä tiedosto

@@ -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);

+ 41
- 9
sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtFormatterTest.java Näytä tiedosto

@@ -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");
}

}

+ 2
- 3
sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java Näytä tiedosto

@@ -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

Loading…
Peruuta
Tallenna