]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5056 Update Issue.debt from Long to Duration
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 5 Mar 2014 18:22:20 +0000 (19:22 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 5 Mar 2014 18:22:20 +0000 (19:22 +0100)
34 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/TechnicalDebtDecorator.java
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/NewTechnicalDebtDecoratorTest.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/TechnicalDebtDecoratorTest.java
sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java
sonar-batch/src/test/java/org/sonar/batch/debt/IssueChangelogDebtCalculatorTest.java
sonar-batch/src/test/java/org/sonar/batch/debt/RuleDebtCalculatorTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java
sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java
sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java
sonar-core/src/test/java/org/sonar/core/issue/workflow/IssueWorkflowTest.java
sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/internal/DefaultIssueTest.java
sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java
sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java
sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java
sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb
sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb
sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java
sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java
sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java
sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java

index ce9be7292fd42ce71a40ed069d982d28190c33e9..789ef022ebd5df0e23b0fd13b7b4b5934f5ff3f2 100644 (file)
@@ -38,6 +38,7 @@ import org.sonar.api.resources.ResourceUtils;
 import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.KeyValueFormat;
 import org.sonar.batch.issue.IssueCache;
 import org.sonar.batch.scan.LastSnapshots;
@@ -176,7 +177,8 @@ public class IssueTrackingDecorator implements Decorator {
       updater.setPastLine(issue, ref.getLine());
       updater.setPastMessage(issue, ref.getMessage(), changeContext);
       updater.setPastEffortToFix(issue, ref.getEffortToFix(), changeContext);
-      Long previousTechnicalDebt = ref.getDebt();
+      Long debtInMinutes = ref.getDebt();
+      Duration previousTechnicalDebt = debtInMinutes != null ? Duration.create(debtInMinutes) : null;
       updater.setPastTechnicalDebt(issue, previousTechnicalDebt, changeContext);
     }
   }
index 324678a7b5a5b94de1f9c3e182ea5cb3d89616ac..8d4c893f436b6d37ff3185c0fac08cd572000850 100644 (file)
@@ -164,7 +164,7 @@ public final class TechnicalDebtDecorator implements Decorator {
     long debt = 0L;
     if (issues != null) {
       for (Issue issue : issues) {
-        Long currentDebt = ((DefaultIssue) issue).debt();
+        Long currentDebt = ((DefaultIssue) issue).debtInMinutes();
         if (currentDebt != null) {
           debt += currentDebt;
         }
index db627c8cdd8d67ce47f676849adba3770ee5feb0..660d6236804b6d5bd21c79152b5c5bfdbdb9c3db 100644 (file)
@@ -71,7 +71,7 @@
                 <br/>
                 <span style="font-weight: bold">
                   <%= message('widget.rules.removed') -%>&nbsp;
-                  <span class="varb"><%= Internal.i18n.formatWorkDuration(estimated_cleared_technical_debt) -%></span>
+                  <span class="varb"><%= Internal.i18n.formatLongWorkDuration(estimated_cleared_technical_debt) -%></span>
                 </span>
               <% end %>
             <% end %>
index 6ee8536cdfcbd696f8414358a5d7a693b6c86c84..93c3cfd1e2b4fde096be91b6712b6c3bcf40f5ec 100644 (file)
           </a>
         </td>
         <td class="val value-debt-<%= h(characteristic.key) -%>">
-          <a href="<%= drilldown_url -%>" class="link-debt-<%= h(characteristic.key) -%>"><%= Internal.i18n.formatWorkDuration(value.to_i) -%></a>
+          <a href="<%= drilldown_url -%>" class="link-debt-<%= h(characteristic.key) -%>"><%= Internal.i18n.formatLongWorkDuration(value.to_i) -%></a>
           <% if should_display_diff_measures %>
             <% if diff_by_characteristic_id[characteristic.id] %>
               <%= format_variation(measure) -%>
           <% end %>
         </td>
         <td class="val value-total-<%= h(characteristic.key) -%>">
-          <%= Internal.i18n.formatWorkDuration(cumulated.to_i) -%>
+          <%= Internal.i18n.formatLongWorkDuration(cumulated.to_i) -%>
           <%
              if should_display_diff_measures
                css_style = 'var'
                css_style += 'b' if total_diff < 0
                css_style += 'w' if total_diff > 0
-               diff_to_display = (total_diff < 0 ? '' : '+') + Internal.i18n.formatWorkDuration(total_diff.to_i)
+               diff_to_display = (total_diff < 0 ? '' : '+') + Internal.i18n.formatLongWorkDuration(total_diff.to_i)
           %>
             <span class="<%= css_style -%>"><b>(<%= diff_to_display -%>)</b></span>
           <%
index 912fcf8aac7aeeece5ed5e9f5732b0a46a901476..248934f99124ad4b0895ec47ae9b4ee495a355b9 100644 (file)
@@ -36,6 +36,7 @@ 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.Duration;
 import org.sonar.batch.issue.IssueCache;
 import org.sonar.batch.scan.LastSnapshots;
 import org.sonar.core.issue.IssueUpdater;
@@ -519,7 +520,7 @@ 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(1L), any(IssueChangeContext.class));
+    verify(updater).setPastTechnicalDebt(eq(issue), eq(Duration.create(1L)), any(IssueChangeContext.class));
   }
 
   @Test
index d3c5cb76b444be08e69d058ee08ff55bae471bb2..86e2e4843ccb68d1c6d40391d4a6f207c51ccf13 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.test.IsMeasure;
+import org.sonar.api.utils.Duration;
 import org.sonar.batch.components.Period;
 import org.sonar.batch.components.TimeMachineConfiguration;
 import org.sonar.batch.debt.IssueChangelogDebtCalculator;
@@ -114,7 +115,7 @@ public class NewTechnicalDebtDecoratorTest {
 
   @Test
   public void save_on_one_issue_with_one_new_changelog() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(TWO_DAYS_IN_MINUTES).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         // changelog created at is null because it has just been created on the current analysis
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(null)
@@ -130,7 +131,7 @@ public class NewTechnicalDebtDecoratorTest {
 
   @Test
   public void save_on_one_issue_with_changelog() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo)
@@ -146,7 +147,7 @@ public class NewTechnicalDebtDecoratorTest {
 
   @Test
   public void save_on_one_issue_with_changelog_only_in_the_past() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(ONE_DAY_IN_MINUTES).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
       newArrayList(
         // Change before all periods
         new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(elevenDaysAgo)
@@ -162,7 +163,7 @@ public class NewTechnicalDebtDecoratorTest {
 
   @Test
   public void save_on_one_issue_with_changelog_having_null_value() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
@@ -181,7 +182,7 @@ 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).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
@@ -198,7 +199,7 @@ 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).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs()
           .setDiff("actionPlan", "1.0", "1.1").setCreationDate(fourDaysAgo)
@@ -215,14 +216,14 @@ public class NewTechnicalDebtDecoratorTest {
 
   @Test
   public void save_on_issues_with_changelog() {
-    Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+    Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
         new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
       )
     );
-    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(TWO_DAYS_IN_MINUTES).setChanges(
+    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
         new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
@@ -239,7 +240,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).setDebt(FIVE_DAYS_IN_MINUTES))
+      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
     );
 
     decorator.decorate(resource, context);
@@ -265,7 +266,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).setDebt(FIVE_DAYS_IN_MINUTES))
+      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
     );
 
     decorator.decorate(resource, context);
@@ -277,8 +278,8 @@ public class NewTechnicalDebtDecoratorTest {
   @Test
   public void save_on_issues_without_changelog() {
     when(issuable.issues()).thenReturn(newArrayList(
-      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES),
-      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(TWO_DAYS_IN_MINUTES)
+      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
+      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
     ));
 
     decorator.decorate(resource, context);
@@ -290,14 +291,14 @@ 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).setDebt(FIVE_DAYS_IN_MINUTES).setChanges(
+    Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
         new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
       )
     );
-    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(TWO_DAYS_IN_MINUTES).setChanges(
+    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
         new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
@@ -305,8 +306,8 @@ public class NewTechnicalDebtDecoratorTest {
     );
 
     // issue3 and issue4 have no changelog
-    Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(FIVE_DAYS_IN_MINUTES);
-    Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(TWO_DAYS_IN_MINUTES);
+    Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES));
+    Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES));
     when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
 
     decorator.decorate(resource, context);
@@ -319,8 +320,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).setDebt(FIVE_DAYS_IN_MINUTES),
-      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(TWO_DAYS_IN_MINUTES)
+      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
+      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
     ));
 
     decorator.decorate(resource, context);
@@ -333,7 +334,7 @@ public class NewTechnicalDebtDecoratorTest {
    */
   @Test
   public void not_return_negative_debt() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(ONE_DAY_IN_MINUTES).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
       newArrayList(
         // changelog created at is null because it has just been created on the current analysis
         new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, ONE_DAY_IN_MINUTES).setCreationDate(null)
index 9690d6a888a579feb0f9566f6c3127edf165936f..248e29211928279f3d4aaca145857b7c53c6956d 100644 (file)
@@ -50,6 +50,7 @@ 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.Duration;
 
 import java.util.List;
 
@@ -130,7 +131,7 @@ public class TechnicalDebtDecoratorTest {
 
   @Test
   public void add_technical_debt_from_one_issue_and_no_parent() throws Exception {
-    Issue issue = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
+    Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
     when(issuable.issues()).thenReturn(newArrayList(issue));
 
     Requirement requirement = mock(Requirement.class);
@@ -159,7 +160,7 @@ public class TechnicalDebtDecoratorTest {
 
   @Test
   public void add_technical_debt_from_one_issue_and_propagate_to_parents() throws Exception {
-    Issue issue = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
+    Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
     when(issuable.issues()).thenReturn(newArrayList(issue));
 
     DefaultCharacteristic parentCharacteristic = new DefaultCharacteristic().setKey("parentCharacteristic");
@@ -183,10 +184,10 @@ public class TechnicalDebtDecoratorTest {
     Long technicalDebt1 = ONE_DAY_IN_MINUTES;
     Long technicalDebt2 = 2 * ONE_DAY_IN_MINUTES;
 
-    Issue issue1 = createIssue("rule1", "repo1").setDebt(technicalDebt1);
-    Issue issue2 = createIssue("rule1", "repo1").setDebt(technicalDebt1);
-    Issue issue3 = createIssue("rule2", "repo2").setDebt(technicalDebt2);
-    Issue issue4 = createIssue("rule2", "repo2").setDebt(technicalDebt2);
+    Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1));
+    Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1));
+    Issue issue3 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2));
+    Issue issue4 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2));
     when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
 
     DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("rootCharacteristic");
@@ -209,8 +210,8 @@ public class TechnicalDebtDecoratorTest {
 
   @Test
   public void add_technical_debt_from_children_measures() throws Exception {
-    Issue issue1 = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
-    Issue issue2 = createIssue("rule1", "repo1").setDebt(ONE_DAY_IN_MINUTES);
+    Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
+    Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
     when(issuable.issues()).thenReturn(newArrayList(issue1, issue2));
 
     DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("rootCharacteristic");
index 276671185f0831f69c04383955240d45ee52ddc9..9b352136b6eb300b87bff7128e0a2ac467fa7715 100644 (file)
@@ -31,6 +31,7 @@ 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;
@@ -39,7 +40,7 @@ public class IssueChangelogDebtCalculator implements BatchComponent {
 
   @CheckForNull
   public Long calculateNewTechnicalDebt(Issue issue, @Nullable Date periodDate) {
-    Long debt = ((DefaultIssue) issue).debt();
+    Long debt = ((DefaultIssue) issue).debtInMinutes();
     Date periodDatePlusOneSecond = periodDate != null ? DateUtils.addSeconds(periodDate, 1) : null;
     if (isAfter(issue.creationDate(), periodDatePlusOneSecond)) {
       return debt;
@@ -129,5 +130,4 @@ public class IssueChangelogDebtCalculator implements BatchComponent {
     return (currentDate != null) && (pastDate == null || (DateUtils.truncatedCompareTo(currentDate, pastDate, Calendar.SECOND) <= 0));
   }
 
-
 }
index 442dfbd71f93261377929cc21304e3e70b0e7c8d..d19ad5de7ad8ba9e83f9369175999505c9c0f14b 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.rules.Violation;
+import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.MessageException;
 import org.sonar.batch.debt.RuleDebtCalculator;
 import org.sonar.core.issue.DefaultIssueBuilder;
@@ -111,7 +112,8 @@ public class ModuleIssues {
     if (issue.severity() == null) {
       issue.setSeverity(activeRule.getSeverity().name());
     }
-    issue.setDebt(technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix()));
+    Long debt = technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix());
+    issue.setDebt(debt != null ? Duration.create(debt) : null);
   }
 
 }
index 50d09eed2f58833594d9cd54f409d3b4ad444259..016d24a6d25ad80ac5a185028e091be740cf43af 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.api.profiles.Alert;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.resources.ResourceUtils;
+import org.sonar.api.utils.Duration;
 import org.sonar.core.timemachine.Periods;
 
 import java.util.Collection;
@@ -151,7 +152,7 @@ public class QualityGateVerifier implements Decorator {
   private String alertValue(Alert alert, Metric.Level level){
     String value = level.equals(Metric.Level.ERROR) ? alert.getValueError() : alert.getValueWarning();
     if (alert.getMetric().getType().equals(Metric.ValueType.WORK_DUR)) {
-      return i18n.formatWorkDuration(Locale.ENGLISH, Long.parseLong(value));
+      return i18n.formatWorkDuration(Locale.ENGLISH, Duration.create(Long.parseLong(value)));
     } else {
       return value;
     }
index 479b8e2f888b1737c75d8fc6a11c86fd3aab19d8..ca022819bc8ecafce294c68881afd1376acafd27 100644 (file)
@@ -23,11 +23,10 @@ package org.sonar.batch.debt;
 import org.apache.commons.lang.time.DateUtils;
 import org.junit.Before;
 import org.junit.Test;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.utils.Duration;
 
 import java.util.Date;
 
@@ -51,17 +50,18 @@ public class IssueChangelogDebtCalculatorTest {
   long twoDays = 2 * HOURS_IN_DAY * 60 * 60L;
   long fiveDays = 5 * HOURS_IN_DAY * 60 * 60L;
 
+  Duration oneDayDebt = Duration.create(oneDay);
+  Duration twoDaysDebt = Duration.create(twoDays);
+  Duration fiveDaysDebt = Duration.create(fiveDays);
+
   @Before
   public void setUp() throws Exception {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(HOURS_IN_DAY));
-
     issueChangelogDebtCalculator = new IssueChangelogDebtCalculator();
   }
 
   @Test
   public void calculate_new_technical_debt_with_one_diff_in_changelog() throws Exception {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDays).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
       newArrayList(
         // changelog created at is null because it has just been created on the current analysis
         new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
@@ -76,7 +76,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).setDebt(fiveDays).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", twoDays, fiveDays).setCreationDate(null),
         new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(fourDaysAgo)
@@ -90,7 +90,7 @@ public class IssueChangelogDebtCalculatorTest {
 
   @Test
   public void changelog_can_be_in_wrong_order() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDays).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
       newArrayList(
         // 3rd
         new FieldDiffs().setDiff("technicalDebt", null, oneDay).setCreationDate(nineDaysAgo),
@@ -107,7 +107,7 @@ public class IssueChangelogDebtCalculatorTest {
 
   @Test
   public void calculate_new_technical_debt_with_null_date() throws Exception {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDays).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
       )
@@ -137,7 +137,7 @@ public class IssueChangelogDebtCalculatorTest {
 
   @Test
   public void not_return_negative_debt() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDay).setChanges(
+    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDayDebt).setChanges(
       newArrayList(
         new FieldDiffs().setDiff("technicalDebt", twoDays, oneDay).setCreationDate(null)
       )
index 59cd9c3efbdcfe1f03cacf3578603c80af208d8d..c53cdcdc2d5ef57565724ab348f4ed83d57c33ef 100644 (file)
@@ -48,9 +48,7 @@ public class RuleDebtCalculatorTest {
 
   @Before
   public void before() {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY);
-    calculator = new RuleDebtCalculator(model, settings);
+    calculator = new RuleDebtCalculator(model, new Settings().setProperty(CoreProperties.HOURS_IN_DAY, 8));
   }
 
   @Test
index 0835389fdf0bfd49ab80302b3e45e1eeaefd7d7f..1150211081e81b5325bd7eff2168f924c42991b7 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.api.resources.Resource;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.rules.*;
+import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.MessageException;
 import org.sonar.batch.debt.RuleDebtCalculator;
 
@@ -277,7 +278,6 @@ public class ModuleIssuesTest {
     Date analysisDate = new Date();
     when(project.getAnalysisDate()).thenReturn(analysisDate);
 
-
     DefaultIssue issue = new DefaultIssue()
       .setKey("ABCDE")
       .setRuleKey(SQUID_RULE_KEY)
@@ -291,7 +291,7 @@ public class ModuleIssuesTest {
 
     ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
     verify(cache).put(argument.capture());
-    assertThat(argument.getValue().debt()).isEqualTo(debt);
+    assertThat(argument.getValue().debt()).isEqualTo(Duration.create(debt));
   }
 
 }
index 8cfc816b46c96845589c576cf58a332fbedc3bd6..bf1d149df9c8429905c4694110c5e8ccc056f49f 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.api.resources.File;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.test.IsMeasure;
+import org.sonar.api.utils.Duration;
 import org.sonar.core.timemachine.Periods;
 
 import java.util.Locale;
@@ -350,7 +351,7 @@ public class QualityGateVerifierTest {
 
     // metric name is declared in l10n bundle
     when(i18n.message(any(Locale.class), eq("metric.tech_debt.name"), anyString())).thenReturn("The Debt");
-    when(i18n.formatWorkDuration(any(Locale.class), eq(3600L))).thenReturn("1h");
+    when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(3600L)))).thenReturn("1h");
 
     when(context.getMeasure(metric)).thenReturn(new Measure(metric, 1800d));
     projectAlerts.addAll(Lists.newArrayList(new Alert(null, metric, Alert.OPERATOR_SMALLER, "3600", null)));
index 8be028d41346b4e41e5ecd07bb1b9bd2fe0e0747..eebe7325cd71c60ed06734e9d69753dd153e9c9b 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.ServerExtension;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.platform.PluginMetadata;
 import org.sonar.api.platform.PluginRepository;
+import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.SonarException;
 import org.sonar.api.utils.System2;
 
@@ -148,11 +149,12 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start
   }
 
   @Override
-  public String formatWorkDuration(Locale locale, long duration) {
-    if (duration == 0) {
+  public String formatWorkDuration(Locale locale, Duration duration) {
+    Long durationInMinutes = duration.toMinutes();
+    if (durationInMinutes == 0) {
       return "0";
     }
-    List<WorkDurationFormatter.Result> results = workDurationFormatter.format(duration);
+    List<WorkDurationFormatter.Result> results = workDurationFormatter.format(durationInMinutes);
     StringBuilder message = new StringBuilder();
     for (WorkDurationFormatter.Result result : results) {
       if (" ".equals(result.key())) {
index 754ad01f50b55a482aba2fd49342b0f7d57d426c..8a2a57b098308244ffce4be888a3f16990bf0c28 100644 (file)
@@ -29,8 +29,10 @@ 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.Duration;
 
 import javax.annotation.Nullable;
+
 import java.util.Calendar;
 import java.util.Date;
 
@@ -198,11 +200,11 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
     return setEffortToFix(issue, currentEffort, context);
   }
 
-  public boolean setTechnicalDebt(DefaultIssue issue, @Nullable Long value, IssueChangeContext context) {
-    Long oldValue = issue.debt();
+  public boolean setTechnicalDebt(DefaultIssue issue, @Nullable Duration value, IssueChangeContext context) {
+    Duration oldValue = issue.debt();
     if (!Objects.equal(value, oldValue)) {
-      issue.setDebt(value);
-      issue.setFieldChange(context, TECHNICAL_DEBT, oldValue, value);
+      issue.setDebt(value != null ? value : null);
+      issue.setFieldChange(context, TECHNICAL_DEBT, oldValue != null ? oldValue.toMinutes() : null, value != null ? value.toMinutes() : null);
       issue.setUpdateDate(context.date());
       issue.setChanged(true);
       return true;
@@ -210,8 +212,8 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
     return false;
   }
 
-  public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable Long previousTechnicalDebt, IssueChangeContext context) {
-    Long currentTechnicalDebt = issue.debt();
+  public boolean setPastTechnicalDebt(DefaultIssue issue, @Nullable Duration previousTechnicalDebt, IssueChangeContext context) {
+    Duration currentTechnicalDebt = issue.debt();
     issue.setDebt(previousTechnicalDebt);
     return setTechnicalDebt(issue, currentTechnicalDebt, context);
   }
@@ -244,4 +246,5 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
     }
     return false;
   }
+
 }
index e95036f788dba5e09d55fe3741af00b183eab011..da2bb38b728967f05c1af0ded77c1bbdb823e159 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.KeyValueFormat;
 
 import javax.annotation.CheckForNull;
@@ -367,7 +368,7 @@ public final class IssueDto implements Serializable {
       .setLine(issue.line())
       .setMessage(issue.message())
       .setEffortToFix(issue.effortToFix())
-      .setDebt(issue.debt())
+      .setDebt(issue.debtInMinutes())
       .setResolution(issue.resolution())
       .setStatus(issue.status())
       .setSeverity(issue.severity())
@@ -396,7 +397,7 @@ public final class IssueDto implements Serializable {
       .setLine(issue.line())
       .setMessage(issue.message())
       .setEffortToFix(issue.effortToFix())
-      .setDebt(issue.debt())
+      .setDebt(issue.debtInMinutes())
       .setResolution(issue.resolution())
       .setStatus(issue.status())
       .setSeverity(issue.severity())
@@ -421,7 +422,7 @@ public final class IssueDto implements Serializable {
     issue.setResolution(resolution);
     issue.setMessage(message);
     issue.setEffortToFix(effortToFix);
-    issue.setDebt(debt);
+    issue.setDebt(debt != null ? Duration.create(debt) : null);
     issue.setLine(line);
     issue.setSeverity(severity);
     issue.setReporter(reporter);
index f225a1b0e4024e0f02d758a61dc3df1690b3e444..954f4802092a5704c11c40f14b162e2dbc34aaa7 100644 (file)
@@ -27,6 +27,7 @@ import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.platform.PluginMetadata;
 import org.sonar.api.platform.PluginRepository;
 import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.System2;
 
 import java.net.URL;
@@ -208,12 +209,12 @@ public class DefaultI18nTest {
       new WorkDurationFormatter.Result(" ", null),
       new WorkDurationFormatter.Result("work_duration.x_minutes", 1)
     ));
-    assertThat(manager.formatWorkDuration(Locale.ENGLISH, 10)).isEqualTo("5d 2h 1min");
+    assertThat(manager.formatWorkDuration(Locale.ENGLISH, Duration.create(10))).isEqualTo("5d 2h 1min");
   }
 
   @Test
   public void format_work_duration_when_0() {
-    assertThat(manager.formatWorkDuration(Locale.ENGLISH, 0)).isEqualTo("0");
+    assertThat(manager.formatWorkDuration(Locale.ENGLISH, Duration.create(0))).isEqualTo("0");
   }
 
   static URLClassLoader newCoreClassloader() {
index 8f3c28a01c315b26f347be5200e0d7b4ff452cdc..0f003bec50f1d2fe44af41b28dc474d750172c51 100644 (file)
@@ -26,6 +26,7 @@ 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.Duration;
 import org.sonar.core.user.DefaultUser;
 
 import java.util.Date;
@@ -372,8 +373,8 @@ public class IssueUpdaterTest {
 
   @Test
   public void set_past_technical_debt() throws Exception {
-    long newDebt = 15 * 8 * 60 * 60;
-    long previousDebt = 10 * 8 * 60 * 60;
+    Duration newDebt = Duration.create(15 * 8 * 60);
+    Duration previousDebt = Duration.create(10 * 8 * 60);
     issue.setDebt(newDebt);
     boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
     assertThat(updated).isTrue();
@@ -381,13 +382,13 @@ public class IssueUpdaterTest {
     assertThat(issue.mustSendNotifications()).isFalse();
 
     FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
-    assertThat(diff.oldValue()).isEqualTo(previousDebt);
-    assertThat(diff.newValue()).isEqualTo(newDebt);
+    assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
+    assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
   }
 
   @Test
   public void set_past_technical_debt_without_previous_value() throws Exception {
-    long newDebt = 15 * 8 * 60 * 60;
+    Duration newDebt = Duration.create(15 * 8 * 60);
     issue.setDebt(newDebt);
     boolean updated = updater.setPastTechnicalDebt(issue, null, context);
     assertThat(updated).isTrue();
@@ -396,20 +397,20 @@ public class IssueUpdaterTest {
 
     FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
     assertThat(diff.oldValue()).isNull();
-    assertThat(diff.newValue()).isEqualTo(newDebt);
+    assertThat(diff.newValue()).isEqualTo(15L * 8 * 60);
   }
 
   @Test
   public void set_past_technical_debt_with_null_new_value() throws Exception {
     issue.setDebt(null);
-    long previousDebt = 10 * 8 * 60 * 60;
+    Duration previousDebt = Duration.create(10 * 8 * 60);
     boolean updated = updater.setPastTechnicalDebt(issue, previousDebt, context);
     assertThat(updated).isTrue();
     assertThat(issue.debt()).isNull();
     assertThat(issue.mustSendNotifications()).isFalse();
 
     FieldDiffs.Diff diff = issue.currentChange().get(TECHNICAL_DEBT);
-    assertThat(diff.oldValue()).isEqualTo(previousDebt);
+    assertThat(diff.oldValue()).isEqualTo(10L * 8 * 60);
     assertThat(diff.newValue()).isNull();
   }
 
index 571782bdb15917f93a700b77e034e70e37faf13d..e1040723d0092c8fabc8f9eb5e70ccd3792dd807 100644 (file)
@@ -25,6 +25,7 @@ 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.Duration;
 
 import java.util.Calendar;
 import java.util.Date;
@@ -87,7 +88,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.debt()).isEqualTo(10L);
+    assertThat(issue.debt()).isEqualTo(Duration.create(10L));
     assertThat(issue.line()).isEqualTo(6);
     assertThat(issue.severity()).isEqualTo("BLOCKER");
     assertThat(issue.message()).isEqualTo("message");
index 4a399e34fdfadd66caba0a8aec1eb4a2c7715a40..aad75923ec76b73fb71def78aabb32f6a7652ce9 100644 (file)
@@ -28,6 +28,7 @@ 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.Duration;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.MyBatis;
 
@@ -53,7 +54,7 @@ public class IssueStorageTest extends AbstractDaoTestCase {
 
       .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
       .setLine(5000)
-      .setDebt(10L)
+      .setDebt(Duration.create(10L))
       .setReporter("emmerik")
       .setResolution("OPEN")
       .setStatus("OPEN")
@@ -87,7 +88,7 @@ public class IssueStorageTest extends AbstractDaoTestCase {
 
         // updated fields
       .setLine(5000)
-      .setDebt(10L)
+      .setDebt(Duration.create(10L))
       .setChecksum("FFFFF")
       .setAuthorLogin("simon")
       .setAssignee("loic")
index b42d1b691f41b184077a7de805212e2f3874b70d..da84dee6ab9f717b4c0efd5f921da23828299bfc 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.api.rule.RuleKey;
 import org.sonar.core.issue.IssueUpdater;
 
 import javax.annotation.Nullable;
+
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
index c11356bd7c09d90d4462d9e777a33bae686c41c4..e30990f12dcf019c47010140b805a2622b5eba45 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.api.i18n;
 
 import org.sonar.api.BatchComponent;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.utils.Duration;
 
 import javax.annotation.Nullable;
 
@@ -105,10 +106,10 @@ public interface I18n extends ServerComponent, BatchComponent {
   /**
    * Return the formatted work duration.
    * <br>
-   * Example : format(Locale.ENGLISH, WorkDuration.create(10, 2, 0, 8)) -> 10d 2h
+   * Example : format(Locale.ENGLISH, Duration.create(10 * 24 * 60 + 2 * 60)) -> 10d 2h
    *
    * @since 4.3
    */
-  String formatWorkDuration(Locale locale, long duration);
+  String formatWorkDuration(Locale locale, Duration duration);
 
 }
index 7ef2cc6c6f6004ceead12fedfef8145a6853db18..0254753827401c9f9b6b9be43ca616ae6392de70 100644 (file)
@@ -33,6 +33,7 @@ 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.Duration;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
@@ -59,7 +60,7 @@ public class DefaultIssue implements Issue {
   private String message;
   private Integer line;
   private Double effortToFix;
-  private Long debt;
+  private Duration debt;
   private String status;
   private String resolution;
   private String reporter;
@@ -209,11 +210,16 @@ public class DefaultIssue implements Issue {
    * Elapsed time to fix the issue
    */
   @CheckForNull
-  public Long debt() {
+  public Duration debt() {
     return debt;
   }
 
-  public DefaultIssue setDebt(@Nullable Long t) {
+  @CheckForNull
+  public Long debtInMinutes(){
+    return debt != null ? debt.toMinutes() : null;
+  }
+
+  public DefaultIssue setDebt(@Nullable Duration t) {
     this.debt = t;
     return this;
   }
index f3bd658e70b6570ce3d0024eeafd29f41c4fb511..227a6e767b54f930dbce6fb7524f586a366fd35e 100644 (file)
@@ -25,6 +25,7 @@ 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.Duration;
 
 import java.text.SimpleDateFormat;
 import java.util.List;
@@ -50,7 +51,7 @@ public class DefaultIssueTest {
       .setMessage("a message")
       .setLine(7)
       .setEffortToFix(1.2d)
-      .setDebt(28800L)
+      .setDebt(Duration.create(28800L))
       .setActionPlanKey("BCDE")
       .setStatus(Issue.STATUS_CLOSED)
       .setResolution(Issue.RESOLUTION_FIXED)
@@ -79,7 +80,7 @@ public class DefaultIssueTest {
     assertThat(issue.message()).isEqualTo("a message");
     assertThat(issue.line()).isEqualTo(7);
     assertThat(issue.effortToFix()).isEqualTo(1.2d);
-    assertThat(issue.debt()).isEqualTo(28800L);
+    assertThat(issue.debt()).isEqualTo(Duration.create(28800L));
     assertThat(issue.actionPlanKey()).isEqualTo("BCDE");
     assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
     assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
index d33f3089aeae52614fe0cb0569d23091643d19e5..d87e499e3e25e4c363c5451f89285bb620ea7b8b 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.issue;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.utils.Duration;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.server.user.UserSession;
 
@@ -71,10 +72,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 = i18n.formatWorkDuration(UserSession.get().locale(), Long.parseLong(newValueString));
+        newValueString = i18n.formatWorkDuration(UserSession.get().locale(), Duration.create(Long.parseLong(newValueString)));
       }
       if (oldValueString != null) {
-        oldValueString = i18n.formatWorkDuration(UserSession.get().locale(), Long.parseLong(oldValueString));
+        oldValueString = i18n.formatWorkDuration(UserSession.get().locale(), Duration.create(Long.parseLong(oldValueString)));
       }
     }
     return new IssueChangelogDiffFormat(oldValueString, newValueString);
index 0f588f7fd471b759ea411f4358446bd80bd69bb4..116b32da940cd7475fe7ac11eff02e94a1bec588 100644 (file)
@@ -33,6 +33,7 @@ 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.Duration;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.component.ComponentDto;
@@ -98,7 +99,7 @@ public class IssueShowWsHandler implements RequestHandler {
   private void writeIssue(IssueQueryResult result, DefaultIssue issue, JsonWriter json) {
     String actionPlanKey = issue.actionPlanKey();
     ActionPlan actionPlan = result.actionPlan(issue);
-    Long technicalDebt = issue.debt();
+    Duration debt = issue.debt();
     Date updateDate = issue.updateDate();
     Date closeDate = issue.closeDate();
 
@@ -114,7 +115,7 @@ public class IssueShowWsHandler implements RequestHandler {
       .prop("author", issue.authorLogin())
       .prop("actionPlan", actionPlanKey)
       .prop("actionPlanName", actionPlan != null ? actionPlan.name() : null)
-      .prop("debt", technicalDebt != null ? i18n.formatWorkDuration(UserSession.get().locale(), technicalDebt) : null)
+      .prop("debt", debt != null ? i18n.formatWorkDuration(UserSession.get().locale(), debt) : null)
       .prop("creationDate", DateUtils.formatDateTime(issue.creationDate()))
       .prop("fCreationDate", formatDate(issue.creationDate()))
       .prop("updateDate", updateDate != null ? DateUtils.formatDateTime(updateDate) : null)
index 3931567b6fb75a2ce15a968dfd1aed20bc68d408..80a6ba85320273cd6501c72004a3874c7c445db6 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.collect.Maps;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.i18n.I18n;
+import org.sonar.api.utils.Duration;
 import org.sonar.core.i18n.GwtI18n;
 import org.sonar.server.user.UserSession;
 
@@ -86,8 +87,12 @@ public class JRubyI18n implements ServerComponent {
     return i18n.ageFromNow(UserSession.get().locale(), date);
   }
 
-  public String formatWorkDuration(long duration) {
+  public String formatWorkDuration(Duration duration) {
     return i18n.formatWorkDuration(UserSession.get().locale(), duration);
   }
 
+  public String formatLongWorkDuration(long duration) {
+    return formatWorkDuration(Duration.create(duration));
+  }
+
 }
index 59b3edb73d68c74b839d2e1e3cb9ce0009868d85..2c99796de442089dcc282e3253d264ae94ae8f86 100644 (file)
@@ -75,8 +75,8 @@ class Issue
         hash_diff = {}
         hash_diff[:key] = key
         if key == 'technicalDebt'
-          hash_diff[:newValue] = debt_to_hash(diff.newValue()) if diff.newValue.present?
-          hash_diff[:oldValue] = debt_to_hash(diff.oldValue()) if diff.oldValue.present?
+          hash_diff[:newValue] = long_debt_to_hash(diff.newValue()) if diff.newValue.present?
+          hash_diff[:oldValue] = long_debt_to_hash(diff.oldValue()) if diff.oldValue.present?
         else
           hash_diff[:newValue] = diff.newValue() if diff.newValue.present?
           hash_diff[:oldValue] = diff.oldValue() if diff.oldValue.present?
@@ -93,6 +93,11 @@ class Issue
   private
 
   def self.debt_to_hash(debt)
+    long_debt_to_hash(debt.toMinutes)
+  end
+
+  def self.long_debt_to_hash(debt)
+    # TODO do not use toWorkDuration() but calculate days, hours and minutes from the duration and from hoursInDay property
     work_duration = Internal.technical_debt.toWorkDuration(debt.to_i)
     {
         :days => work_duration.days(),
index f600e43430d087e60342573018731ee77c34587f..0198b35e57aa47fe4d39e3b0143aba7281f748bc 100644 (file)
@@ -164,7 +164,7 @@ class ProjectMeasure < ActiveRecord::Base
   end
 
   def work_duration_formatted_value(value)
-    Internal.i18n.formatWorkDuration(value.to_i)
+    Internal.i18n.formatLongWorkDuration(value.to_i)
   end
 
   def color
index f35b8b0cd7f4d17c82384b050b3d142169240686..33c965d511343a1f9964b994b7f654a20a632362 100644 (file)
@@ -33,6 +33,7 @@ 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.Duration;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.issue.DefaultActionPlan;
 import org.sonar.core.issue.db.IssueChangeDao;
@@ -333,7 +334,7 @@ public class
 
     assertThat(results.issues()).hasSize(1);
     DefaultIssue result = (DefaultIssue) results.issues().iterator().next();
-    assertThat(result.debt()).isEqualTo(10L);
+    assertThat(result.debt()).isEqualTo(Duration.create(10L));
   }
 
 }
index 1dcb81c46c71fb945c86a7d0f245c25fe6b0f412..98323c582b645266a2818c12d1ca542c7973faa5 100644 (file)
@@ -26,6 +26,7 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.utils.Duration;
 
 import java.util.List;
 import java.util.Locale;
@@ -127,8 +128,8 @@ public class IssueChangelogFormatterTest {
     FieldDiffs diffs = new FieldDiffs();
     diffs.setDiff("technicalDebt", "18000", "28800");
 
-    when(i18n.formatWorkDuration(any(Locale.class), eq(18000L))).thenReturn("5 hours");
-    when(i18n.formatWorkDuration(any(Locale.class), eq(28800L))).thenReturn("1 days");
+    when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(18000L)))).thenReturn("5 hours");
+    when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(28800L)))).thenReturn("1 days");
 
     when(i18n.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt");
     when(i18n.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days");
@@ -145,7 +146,7 @@ public class IssueChangelogFormatterTest {
     FieldDiffs diffs = new FieldDiffs();
     diffs.setDiff("technicalDebt", null, "28800");
 
-    when(i18n.formatWorkDuration(any(Locale.class), eq(28800L))).thenReturn("1 days");
+    when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(28800L)))).thenReturn("1 days");
 
     when(i18n.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt");
     when(i18n.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days");
index cf27de1d5855db4fa650ab0db36f5abd6d0b3fea..2dc944f55344fcb8eb5644fd49d6bb3db0b56ac4 100644 (file)
@@ -42,6 +42,7 @@ 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.Duration;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.issue.DefaultActionPlan;
@@ -302,11 +303,11 @@ public class IssueShowWsHandlerTest {
 
   @Test
   public void show_issue_with_technical_debt() throws Exception {
-    Long technicalDebt = 7260L;
-    Issue issue = createStandardIssue().setDebt(technicalDebt);
+    Duration debt = (Duration.create(7260L));
+    Issue issue = createStandardIssue().setDebt(debt);
     issues.add(issue);
 
-    when(i18n.formatWorkDuration(any(Locale.class), eq(technicalDebt))).thenReturn("2 hours 1 minutes");
+    when(i18n.formatWorkDuration(any(Locale.class), eq(debt))).thenReturn("2 hours 1 minutes");
 
     MockUserSession.set();
     WsTester.TestRequest request = tester.newRequest("show").setParam("key", issue.key());
@@ -315,7 +316,7 @@ public class IssueShowWsHandlerTest {
 
   @Test
   public void show_issue_with_characteristics() throws Exception {
-    Issue issue = createStandardIssue().setDebt(7260L);
+    Issue issue = createStandardIssue().setDebt(Duration.create(7260L));
     issues.add(issue);
 
     Characteristic requirement = new DefaultCharacteristic().setId(5).setParentId(2).setRootId(1);
index 1060704e1198e6f0c124536553b3ce9ab4db0720..ef26d5c0209c83e2430fe8788bf62fd371b57279 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.i18n.I18n;
+import org.sonar.api.utils.Duration;
 import org.sonar.core.i18n.GwtI18n;
 
 import java.util.Date;
@@ -94,8 +95,14 @@ public class JRubyI18nTest {
 
   @Test
   public void format_work_duration() throws Exception {
-    jRubyI18n.formatWorkDuration(10L);
-    verify(i18n).formatWorkDuration(any(Locale.class), eq(10L));
+    jRubyI18n.formatWorkDuration(Duration.create(10L));
+    verify(i18n).formatWorkDuration(any(Locale.class), eq(Duration.create(10L)));
+  }
+
+  @Test
+  public void format_long_work_duration() throws Exception {
+    jRubyI18n.formatLongWorkDuration(10L);
+    verify(i18n).formatWorkDuration(any(Locale.class), eq(Duration.create(10L)));
   }
 
 }