From 94ed63a7c64ddebf9056604535e4439a82ceecae Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Thu, 6 Mar 2014 12:15:15 +0100 Subject: [PATCH] SONAR-5056 Create new Durations API to format Duration and convert String to Duration --- .../core/widgets/issues/issues.html.erb | 2 +- .../widgets/technical_debt_pyramid.html.erb | 8 +- .../batch/bootstrap/BootstrapContainer.java | 6 +- .../qualitygate/QualityGateVerifier.java | 9 +- .../qualitygate/QualityGateVerifierTest.java | 7 +- .../java/org/sonar/core/i18n/DefaultI18n.java | 27 +--- .../core/i18n/WorkDurationFormatter.java | 139 ------------------ .../org/sonar/core/i18n/DefaultI18nTest.java | 25 +--- .../core/i18n/WorkDurationFormatterTest.java | 98 ------------ .../main/java/org/sonar/api/i18n/I18n.java | 14 +- .../java/org/sonar/api/utils/Durations.java | 137 +++++++++++++++++ .../utils/internal/WorkDurationFactory.java | 66 --------- .../org/sonar/api/utils/DurationsTest.java | 119 +++++++++++++++ .../internal/WorkDurationFactoryTest.java | 67 --------- .../server/issue/IssueChangelogFormatter.java | 9 +- .../server/issue/ws/IssueShowWsHandler.java | 7 +- .../org/sonar/server/platform/Platform.java | 6 +- .../server/technicaldebt/DebtService.java | 12 +- .../java/org/sonar/server/ui/JRubyI18n.java | 13 +- .../app/controllers/issue_controller.rb | 6 +- .../webapp/WEB-INF/app/models/internal.rb | 6 +- .../main/webapp/WEB-INF/app/models/issue.rb | 23 +-- .../WEB-INF/app/models/project_measure.rb | 2 +- .../WEB-INF/app/views/issue/_issue.html.erb | 2 +- .../issue/IssueChangelogFormatterTest.java | 13 +- .../issue/ws/IssueShowWsHandlerTest.java | 8 +- .../server/technicaldebt/DebtServiceTest.java | 14 +- .../org/sonar/server/ui/JRubyI18nTest.java | 14 +- .../java/org/sonar/wsclient/issue/Issue.java | 2 +- .../sonar/wsclient/issue/WorkDayDuration.java | 33 ----- .../wsclient/issue/internal/DefaultIssue.java | 11 +- .../internal/DefaultIssueChangeDiff.java | 14 +- .../internal/DefaultWorkDayDuration.java | 50 ------- .../issue/internal/IssueJsonParserTest.java | 30 +--- ...hangelog-with-only-new-technical-debt.json | 6 +- .../changelog-with-technical-debt.json | 12 +- .../issue-with-technical-debt.json | 6 +- 37 files changed, 357 insertions(+), 666 deletions(-) delete mode 100644 sonar-core/src/main/java/org/sonar/core/i18n/WorkDurationFormatter.java delete mode 100644 sonar-core/src/test/java/org/sonar/core/i18n/WorkDurationFormatterTest.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java delete mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/WorkDurationFactory.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/utils/DurationsTest.java delete mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/utils/internal/WorkDurationFactoryTest.java delete mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/issue/WorkDayDuration.java delete mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultWorkDayDuration.java diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb index 660d6236804..a93d324cda2 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb @@ -71,7 +71,7 @@
<%= message('widget.rules.removed') -%>  - <%= Internal.i18n.formatLongWorkDuration(estimated_cleared_technical_debt) -%> + <%= Internal.i18n.formatLongDuration(estimated_cleared_technical_debt, 'SHORT') -%> <% end %> <% end %> diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb index 93c3cfd1e2b..a2ecdbd479f 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb @@ -1,7 +1,7 @@ <% technical_debt = measure('sqale_index') - root_characteristics = Internal.technical_debt.findRootCharacteristics().to_a + root_characteristics = Internal.debt.findRootCharacteristics().to_a should_display_diff_measures = dashboard_configuration.selected_period? && technical_debt.variation(dashboard_configuration.period_index)!=nil if technical_debt.nil? || root_characteristics.empty? @@ -115,7 +115,7 @@ - <%= Internal.i18n.formatLongWorkDuration(value.to_i) -%> + <%= Internal.i18n.formatLongDuration(value.to_i, 'SHORT') -%> <% if should_display_diff_measures %> <% if diff_by_characteristic_id[characteristic.id] %> <%= format_variation(measure) -%> @@ -125,13 +125,13 @@ <% end %> - <%= Internal.i18n.formatLongWorkDuration(cumulated.to_i) -%> + <%= Internal.i18n.formatLongDuration(cumulated.to_i, 'SHORT') -%> <% 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.formatLongWorkDuration(total_diff.to_i) + diff_to_display = (total_diff < 0 ? '' : '+') + Internal.i18n.formatLongDuration(total_diff.to_i, 'SHORT') %> (<%= diff_to_display -%>) <% diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java index 88a43090fbd..7428fe50fe6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java @@ -24,15 +24,14 @@ import org.sonar.api.Plugin; import org.sonar.api.config.EmailSettings; import org.sonar.api.platform.ComponentContainer; import org.sonar.api.platform.PluginMetadata; +import org.sonar.api.utils.Durations; import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.UriReader; import org.sonar.api.utils.internal.TempFolderCleaner; -import org.sonar.api.utils.internal.WorkDurationFactory; import org.sonar.batch.components.*; import org.sonar.core.config.Logback; import org.sonar.core.i18n.DefaultI18n; import org.sonar.core.i18n.RuleI18nManager; -import org.sonar.core.i18n.WorkDurationFormatter; import org.sonar.core.metric.CacheMetricFinder; import org.sonar.core.persistence.*; import org.sonar.core.purge.PurgeProfiler; @@ -126,8 +125,7 @@ public class BootstrapContainer extends ComponentContainer { PastSnapshotFinderByPreviousVersion.class, PastMeasuresLoader.class, PastSnapshotFinder.class, - WorkDurationFormatter.class, - WorkDurationFactory.class + Durations.class ); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java index 016d24a6d25..32b6d86fbe2 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java +++ b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateVerifier.java @@ -33,6 +33,7 @@ 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.api.utils.Durations; import org.sonar.core.timemachine.Periods; import java.util.Collection; @@ -48,13 +49,15 @@ public class QualityGateVerifier implements Decorator { private final Snapshot snapshot; private final Periods periods; private final I18n i18n; + private final Durations durations; private ProjectAlerts projectAlerts; - public QualityGateVerifier(Snapshot snapshot, ProjectAlerts projectAlerts, Periods periods, I18n i18n) { + public QualityGateVerifier(Snapshot snapshot, ProjectAlerts projectAlerts, Periods periods, I18n i18n, Durations durations) { this.snapshot = snapshot; this.projectAlerts = projectAlerts; this.periods = periods; this.i18n = i18n; + this.durations = durations; } @DependedUpon @@ -149,10 +152,10 @@ public class QualityGateVerifier implements Decorator { return stringBuilder.toString(); } - private String alertValue(Alert alert, Metric.Level level){ + 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, Duration.create(Long.parseLong(value))); + return durations.format(Locale.ENGLISH, Duration.create(Long.parseLong(value)), Durations.DurationFormat.SHORT); } else { return value; } diff --git a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java index bf1d149df9c..ef894d67851 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java @@ -38,6 +38,7 @@ 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.api.utils.Durations; import org.sonar.core.timemachine.Periods; import java.util.Locale; @@ -62,12 +63,14 @@ public class QualityGateVerifierTest { Snapshot snapshot; Periods periods; I18n i18n; + Durations durations; @Before public void before() { context = mock(DecoratorContext.class); periods = mock(Periods.class); i18n = mock(I18n.class); + durations = mock(Durations.class); when(i18n.message(any(Locale.class), eq("variation"), eq("variation"))).thenReturn("variation"); measureClasses = new Measure(CoreMetrics.CLASSES, 20d); @@ -80,7 +83,7 @@ public class QualityGateVerifierTest { snapshot = mock(Snapshot.class); projectAlerts = new ProjectAlerts(); - verifier = new QualityGateVerifier(snapshot, projectAlerts, periods, i18n); + verifier = new QualityGateVerifier(snapshot, projectAlerts, periods, i18n, durations); project = new Project("foo"); } @@ -351,7 +354,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(Duration.create(3600L)))).thenReturn("1h"); + when(durations.format(any(Locale.class), eq(Duration.create(3600L)), eq(Durations.DurationFormat.SHORT))).thenReturn("1h"); when(context.getMeasure(metric)).thenReturn(new Measure(metric, 1800d)); projectAlerts.addAll(Lists.newArrayList(new Alert(null, metric, Alert.OPERATOR_SMALLER, "3600", null))); diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java b/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java index eebe7325cd7..23fe352d0a8 100644 --- a/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java +++ b/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java @@ -30,7 +30,6 @@ 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; @@ -48,7 +47,6 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start private static final Logger LOG = LoggerFactory.getLogger(DefaultI18n.class); public static final String BUNDLE_PACKAGE = "org.sonar.l10n."; - private final WorkDurationFormatter workDurationFormatter; private PluginRepository pluginRepository; private I18nClassloader i18nClassloader; @@ -56,14 +54,13 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start private final ResourceBundle.Control control; private final System2 system2; - public DefaultI18n(PluginRepository pluginRepository, WorkDurationFormatter workDurationFormatter) { - this(pluginRepository, workDurationFormatter, System2.INSTANCE); + public DefaultI18n(PluginRepository pluginRepository) { + this(pluginRepository, System2.INSTANCE); } @VisibleForTesting - DefaultI18n(PluginRepository pluginRepository, WorkDurationFormatter workDurationFormatter, System2 system2) { + DefaultI18n(PluginRepository pluginRepository, System2 system2) { this.pluginRepository = pluginRepository; - this.workDurationFormatter = workDurationFormatter; this.system2 = system2; // SONAR-2927 this.control = new ResourceBundle.Control() { @@ -148,24 +145,6 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start return DateFormat.getDateInstance(DateFormat.DEFAULT, locale).format(date); } - @Override - public String formatWorkDuration(Locale locale, Duration duration) { - Long durationInMinutes = duration.toMinutes(); - if (durationInMinutes == 0) { - return "0"; - } - List results = workDurationFormatter.format(durationInMinutes); - StringBuilder message = new StringBuilder(); - for (WorkDurationFormatter.Result result : results) { - if (" ".equals(result.key())) { - message.append(" "); - } else { - message.append(message(locale, result.key(), null, result.value())); - } - } - return message.toString(); - } - /** * Only the given locale is searched. Contrary to java.util.ResourceBundle, no strategy for locating the bundle is implemented in * this method. diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/WorkDurationFormatter.java b/sonar-core/src/main/java/org/sonar/core/i18n/WorkDurationFormatter.java deleted file mode 100644 index f760bf44802..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/i18n/WorkDurationFormatter.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.core.i18n; - -import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; -import org.sonar.api.BatchExtension; -import org.sonar.api.ServerComponent; -import org.sonar.api.utils.internal.WorkDuration; -import org.sonar.api.utils.internal.WorkDurationFactory; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; - -import java.util.List; - -import static com.google.common.collect.Lists.newArrayList; - -public class WorkDurationFormatter implements ServerComponent, BatchExtension { - - private final WorkDurationFactory workDurationFactory; - - public WorkDurationFormatter(WorkDurationFactory workDurationFactory) { - this.workDurationFactory = workDurationFactory; - } - - public List format(long durationInMinutes) { - if (durationInMinutes == 0) { - return newArrayList(new Result("0", null)); - } - boolean isNegative = durationInMinutes < 0; - Long absDuration = Math.abs(durationInMinutes); - return format(workDurationFactory.createFromMinutes(absDuration), isNegative); - } - - private List format(WorkDuration workDuration, boolean isNegative) { - List results = newArrayList(); - if (workDuration.days() > 0) { - results.add(message("work_duration.x_days", isNegative ? -1 * workDuration.days() : workDuration.days())); - } - if (displayHours(workDuration)) { - addSpaceIfNeeded(results); - results.add(message("work_duration.x_hours", isNegative && results.isEmpty() ? -1 * workDuration.hours() : workDuration.hours())); - } - if (displayMinutes(workDuration)) { - addSpaceIfNeeded(results); - results.add(message("work_duration.x_minutes", isNegative && results.isEmpty() ? -1 * workDuration.minutes() : workDuration.minutes())); - } - return results; - } - - private boolean displayHours(WorkDuration workDuration){ - return workDuration.hours() > 0 && workDuration.days() < 10; - } - - private boolean displayMinutes(WorkDuration workDuration){ - return workDuration.minutes() > 0 && workDuration.hours() < 10 && workDuration.days() == 0; - } - - private void addSpaceIfNeeded(List results){ - if (!results.isEmpty()) { - results.add(new Result(" ", null)); - } - } - - private Result message(String key, @CheckForNull Object parameter) { - return new Result(key, parameter); - } - - static class Result { - private String key; - private Object value; - - Result(String key, @Nullable Object value) { - this.key = key; - this.value = value; - } - - String key() { - return key; - } - - @CheckForNull - Object value() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Result result = (Result) o; - - if (key != null ? !key.equals(result.key) : result.key != null) { - return false; - } - if (value != null ? !value.equals(result.value) : result.value != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = key != null ? key.hashCode() : 0; - result = 31 * result + (value != null ? value.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return new ReflectionToStringBuilder(this, ToStringStyle.SIMPLE_STYLE).toString(); - } - } -} diff --git a/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java index 954f4802092..3c5bc0d6d48 100644 --- a/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java +++ b/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java @@ -27,7 +27,6 @@ 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; @@ -36,7 +35,6 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; -import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -47,10 +45,6 @@ public class DefaultI18nTest { @Mock System2 system2; - @Mock - WorkDurationFormatter workDurationFormatter; - - DefaultI18n manager; @Before @@ -62,7 +56,7 @@ public class DefaultI18nTest { I18nClassloader i18nClassloader = new I18nClassloader(new ClassLoader[]{ newCoreClassloader(), newFrenchPackClassloader(), newSqaleClassloader(), newCheckstyleClassloader() }); - manager = new DefaultI18n(pluginRepository, workDurationFormatter, system2); + manager = new DefaultI18n(pluginRepository, system2); manager.doStart(i18nClassloader); } @@ -200,23 +194,6 @@ public class DefaultI18nTest { assertThat(manager.formatDate(Locale.ENGLISH, DateUtils.parseDate("2014-01-22"))).isEqualTo("Jan 22, 2014"); } - @Test - public void format_work_duration() { - when(workDurationFormatter.format(10)).thenReturn(newArrayList( - new WorkDurationFormatter.Result("work_duration.x_days", 5), - new WorkDurationFormatter.Result(" ", null), - new WorkDurationFormatter.Result("work_duration.x_hours", 2), - new WorkDurationFormatter.Result(" ", null), - new WorkDurationFormatter.Result("work_duration.x_minutes", 1) - )); - 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, Duration.create(0))).isEqualTo("0"); - } - static URLClassLoader newCoreClassloader() { return newClassLoader("/org/sonar/core/i18n/corePlugin/"); } diff --git a/sonar-core/src/test/java/org/sonar/core/i18n/WorkDurationFormatterTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/WorkDurationFormatterTest.java deleted file mode 100644 index 984b2f78364..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/i18n/WorkDurationFormatterTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.core.i18n; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.Settings; -import org.sonar.api.utils.internal.WorkDurationFactory; - -import static com.google.common.collect.Lists.newArrayList; -import static org.fest.assertions.Assertions.assertThat; - -public class WorkDurationFormatterTest { - - static final int HOURS_IN_DAY = 8; - - static final long ONE_MINUTE = 1L; - static final long ONE_HOUR = ONE_MINUTE * 60; - static final long ONE_DAY = HOURS_IN_DAY * ONE_HOUR; - - Settings settings; - - WorkDurationFormatter formatter; - - @Before - public void setUp() throws Exception { - settings = new Settings(); - settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(HOURS_IN_DAY)); - formatter = new WorkDurationFormatter(new WorkDurationFactory(settings)); - } - - @Test - public void format() { - assertThat(formatter.format(5 * ONE_DAY)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_days", 5))); - assertThat(formatter.format(2 * ONE_HOUR)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_hours", 2))); - assertThat(formatter.format(ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_minutes", 1))); - - assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR)).isEqualTo(newArrayList( - new WorkDurationFormatter.Result("work_duration.x_days", 5), - new WorkDurationFormatter.Result(" ", null), - new WorkDurationFormatter.Result("work_duration.x_hours", 2) - )); - - assertThat(formatter.format(2 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList( - new WorkDurationFormatter.Result("work_duration.x_hours", 2), - new WorkDurationFormatter.Result(" ", null), - new WorkDurationFormatter.Result("work_duration.x_minutes", 1) - )); - - assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList( - new WorkDurationFormatter.Result("work_duration.x_days", 5), - new WorkDurationFormatter.Result(" ", null), - new WorkDurationFormatter.Result("work_duration.x_hours", 2) - )); - } - - @Test - public void not_display_following_element_when_bigger_than_ten() { - int hoursInDay = 15; - settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(hoursInDay)); - - assertThat(formatter.format(15 * hoursInDay * ONE_HOUR + 2 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_days", 15))); - - assertThat(formatter.format(12 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_hours", 12))); - } - - @Test - public void display_zero_without_unit() { - assertThat(formatter.format(0)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("0", null))); - } - - @Test - public void display_negative_duration() { - assertThat(formatter.format(-5 * ONE_DAY)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_days", -5))); - assertThat(formatter.format(-2 * ONE_HOUR)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_hours", -2))); - assertThat(formatter.format(-1 * ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_minutes", -1))); - } - -} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java b/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java index e30990f12dc..bf8b6ee9a75 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java @@ -21,7 +21,6 @@ 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; @@ -71,16 +70,16 @@ public interface I18n extends ServerComponent, BatchComponent { /** * Return the distance in time between two dates. - * @see I18n#age(java.util.Locale, long durationInMillis) * + * @see I18n#age(java.util.Locale, long durationInMillis) * @since 4.2 */ String age(Locale locale, Date fromDate, Date toDate); /** * Reports the distance in time a date and now. - * @see I18n#age(java.util.Locale, java.util.Date, java.util.Date) * + * @see I18n#age(java.util.Locale, java.util.Date, java.util.Date) * @since 4.2 */ String ageFromNow(Locale locale, Date date); @@ -103,13 +102,4 @@ public interface I18n extends ServerComponent, BatchComponent { */ String formatDate(Locale locale, Date date); - /** - * Return the formatted work duration. - *
- * Example : format(Locale.ENGLISH, Duration.create(10 * 24 * 60 + 2 * 60)) -> 10d 2h - * - * @since 4.3 - */ - String formatWorkDuration(Locale locale, Duration duration); - } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java new file mode 100644 index 00000000000..7f0f5ef3ffc --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java @@ -0,0 +1,137 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.api.utils; + +import org.sonar.api.BatchComponent; +import org.sonar.api.CoreProperties; +import org.sonar.api.ServerComponent; +import org.sonar.api.config.Settings; +import org.sonar.api.i18n.I18n; + +import javax.annotation.CheckForNull; + +import java.util.Locale; + +/** + * Used through ruby code
Internal.durations
+ * + * @since 4.3 + */ +public class Durations implements BatchComponent, ServerComponent { + + public enum DurationFormat { + /** + * Display duration with only one or two members. + * For instance, Duration.decode("1d 1h 10min", 8) will return "1d 1h" and Duration.decode("12d 5h", 8) will return "12d" + */ + SHORT + } + + private final Settings settings; + private final I18n i18n; + + public Durations(Settings settings, I18n i18n) { + this.settings = settings; + this.i18n = i18n; + } + + /** + * Create a Duration object from a number of minutes + */ + public Duration create(long minutes) { + return Duration.create(minutes); + } + + /** + * Convert the text to a Duration + *
+ * Example : decode("9d 10 h") -> Duration.encode("10d2h") (if sonar.technicalDebt.hoursInDay property is set to 8) + */ + public Duration decode(String duration) { + return Duration.decode(duration, hoursInDay()); + } + + /** + * Return the string value of the Duration. + *
+ * Example : encode(Duration.encode("9d 10h")) -> "10d2h" (if sonar.technicalDebt.hoursInDay property is set to 8) + */ + public String encode(Duration duration) { + return duration.encode(hoursInDay()); + } + + /** + * Return the formatted work duration. + *
+ * Example : format(Locale.FRENCH, Duration.encode("9d 10h"), DurationFormat.SHORT) -> 10j 2h (if sonar.technicalDebt.hoursInDay property is set to 8) + */ + public String format(Locale locale, Duration duration, DurationFormat format) { + Long durationInMinutes = duration.toMinutes(); + if (durationInMinutes == 0) { + return "0"; + } + boolean isNegative = durationInMinutes < 0; + Long absDuration = Math.abs(durationInMinutes); + + int days = ((Double) ((double) absDuration / hoursInDay() / 60)).intValue(); + Long remainingDuration = absDuration - (days * hoursInDay() * 60); + int hours = ((Double) (remainingDuration.doubleValue() / 60)).intValue(); + remainingDuration = remainingDuration - (hours * 60); + int minutes = remainingDuration.intValue(); + + StringBuilder message = new StringBuilder(); + if (days > 0) { + message.append(message(locale, "work_duration.x_days", isNegative ? -1 * days : days)); + } + if (displayHours(days, hours)) { + addSpaceIfNeeded(message); + message.append(message(locale, "work_duration.x_hours", isNegative && message.length() == 0 ? -1 * hours : hours)); + } + if (displayMinutes(days, hours, minutes)) { + addSpaceIfNeeded(message); + message.append(message(locale, "work_duration.x_minutes", isNegative && message.length() == 0 ? -1 * minutes : minutes)); + } + return message.toString(); + } + + private String message(Locale locale, String key, @CheckForNull Object parameter) { + return i18n.message(locale, key, null, parameter); + } + + private boolean displayHours(int days, int hours) { + return hours > 0 && days < 10; + } + + private boolean displayMinutes(int days, int hours, int minutes) { + return minutes > 0 && hours < 10 && days == 0; + } + + private void addSpaceIfNeeded(StringBuilder message) { + if (message.length() > 0) { + message.append(" "); + } + } + + private int hoursInDay() { + return settings.getInt(CoreProperties.HOURS_IN_DAY); + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/WorkDurationFactory.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/WorkDurationFactory.java deleted file mode 100644 index 442f68998f9..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/WorkDurationFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.api.utils.internal; - -import org.sonar.api.BatchComponent; -import org.sonar.api.CoreProperties; -import org.sonar.api.ServerComponent; -import org.sonar.api.config.Settings; - -/** - * @since 4.2 - */ -public final class WorkDurationFactory implements BatchComponent, ServerComponent { - - private final Settings settings; - - public WorkDurationFactory(Settings settings) { - this.settings = settings; - } - - /** - * @deprecated since 4.3 - */ - @Deprecated - public WorkDuration createFromWorkingValue(int value, WorkDuration.UNIT unit) { - return WorkDuration.createFromValueAndUnit(value, unit, hoursInDay()); - } - - /** - * @deprecated since 4.3 - */ - @Deprecated - public WorkDuration createFromWorkingLong(long duration) { - return WorkDuration.createFromLong(duration, hoursInDay()); - } - - /** - * @since 4.3 - */ - public WorkDuration createFromMinutes(long duration) { - return WorkDuration.createFromMinutes(duration, hoursInDay()); - } - - private int hoursInDay(){ - return settings.getInt(CoreProperties.HOURS_IN_DAY); - } - -} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/DurationsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/DurationsTest.java new file mode 100644 index 00000000000..5926f490cca --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/DurationsTest.java @@ -0,0 +1,119 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.api.utils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.i18n.I18n; + +import java.util.Locale; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class DurationsTest { + + static final int HOURS_IN_DAY = 8; + + static final long ONE_MINUTE = 1L; + static final long ONE_HOUR = ONE_MINUTE * 60; + static final long ONE_DAY = HOURS_IN_DAY * ONE_HOUR; + + @Mock + I18n i18n; + + Locale locale = Locale.ENGLISH; + + Settings settings; + + Durations durations; + + @Before + public void setUp() throws Exception { + settings = new Settings(); + settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY); + durations = new Durations(settings, i18n); + } + + @Test + public void create_from_minutes() throws Exception { + assertThat(durations.create(10L).toMinutes()).isEqualTo(10L); + } + + @Test + public void decode() throws Exception { + // 1 working day -> 8 hours + assertThat(durations.decode("1d").toMinutes()).isEqualTo(8L * ONE_HOUR); + // 8 hours + assertThat(durations.decode("8h").toMinutes()).isEqualTo(8L * ONE_HOUR); + } + + @Test + public void format() { + when(i18n.message(eq(locale), eq("work_duration.x_days"), eq((String) null), eq(5))).thenReturn("5d"); + when(i18n.message(eq(locale), eq("work_duration.x_hours"), eq((String) null), eq(2))).thenReturn("2h"); + when(i18n.message(eq(locale), eq("work_duration.x_minutes"), eq((String) null), eq(1))).thenReturn("1min"); + + assertThat(durations.format(locale, Duration.create(5 * ONE_DAY), Durations.DurationFormat.SHORT)).isEqualTo("5d"); + assertThat(durations.format(locale, Duration.create(2 * ONE_HOUR), Durations.DurationFormat.SHORT)).isEqualTo("2h"); + assertThat(durations.format(locale, Duration.create(ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("1min"); + + assertThat(durations.format(locale, Duration.create(5 * ONE_DAY + 2 * ONE_HOUR), Durations.DurationFormat.SHORT)).isEqualTo("5d 2h"); + assertThat(durations.format(locale, Duration.create(2 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("2h 1min"); + assertThat(durations.format(locale, Duration.create(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("5d 2h"); + } + + @Test + public void not_display_following_element_when_bigger_than_ten() { + int hoursInDay = 15; + settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(hoursInDay)); + + when(i18n.message(eq(locale), eq("work_duration.x_days"), eq((String) null), eq(15))).thenReturn("15d"); + when(i18n.message(eq(locale), eq("work_duration.x_hours"), eq((String) null), eq(12))).thenReturn("12h"); + + assertThat(durations.format(locale, Duration.create(15 * hoursInDay * ONE_HOUR + 2 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("15d"); + assertThat(durations.format(locale, Duration.create(12 * ONE_HOUR + ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("12h"); + } + + @Test + public void display_zero_without_unit() { + assertThat(durations.format(locale, Duration.create(0), Durations.DurationFormat.SHORT)).isEqualTo("0"); + } + + @Test + public void display_negative_duration() { + when(i18n.message(eq(locale), eq("work_duration.x_days"), eq((String) null), eq(-5))).thenReturn("-5d"); + when(i18n.message(eq(locale), eq("work_duration.x_hours"), eq((String) null), eq(-2))).thenReturn("-2h"); + when(i18n.message(eq(locale), eq("work_duration.x_minutes"), eq((String) null), eq(-1))).thenReturn("-1min"); + + assertThat(durations.format(locale, Duration.create(-5 * ONE_DAY), Durations.DurationFormat.SHORT)).isEqualTo("-5d"); + assertThat(durations.format(locale, Duration.create(-2 * ONE_HOUR), Durations.DurationFormat.SHORT)).isEqualTo("-2h"); + assertThat(durations.format(locale, Duration.create(-1 * ONE_MINUTE), Durations.DurationFormat.SHORT)).isEqualTo("-1min"); + } + +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/internal/WorkDurationFactoryTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/internal/WorkDurationFactoryTest.java deleted file mode 100644 index 735ab46fc8c..00000000000 --- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/internal/WorkDurationFactoryTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.api.utils.internal; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.Settings; - -import static org.fest.assertions.Assertions.assertThat; - -public class WorkDurationFactoryTest { - - WorkDurationFactory factory; - - static final int HOURS_IN_DAY = 8; - static final Long ONE_HOUR_IN_MINUTES = 1L * 60; - - @Before - public void setUp() throws Exception { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY); - factory = new WorkDurationFactory(settings); - } - - @Test - public void create_from_working_value() throws Exception { - // 1 working day -> 8 hours - assertThat(factory.createFromWorkingValue(1, WorkDuration.UNIT.DAYS).toMinutes()).isEqualTo(8L * ONE_HOUR_IN_MINUTES); - // 8 hours - assertThat(factory.createFromWorkingValue(8, WorkDuration.UNIT.HOURS).toMinutes()).isEqualTo(8L * ONE_HOUR_IN_MINUTES); - } - - @Test - public void create_from_working_long() throws Exception { - WorkDuration workDuration = factory.createFromWorkingLong(1l); - assertThat(workDuration.days()).isEqualTo(0); - assertThat(workDuration.hours()).isEqualTo(0); - assertThat(workDuration.minutes()).isEqualTo(1); - } - - @Test - public void create_from_seconds() throws Exception { - WorkDuration workDuration = factory.createFromMinutes(8L * ONE_HOUR_IN_MINUTES); - assertThat(workDuration.days()).isEqualTo(1); - assertThat(workDuration.hours()).isEqualTo(0); - assertThat(workDuration.minutes()).isEqualTo(0); - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java index d87e499e3e2..b8b86d3e60b 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java @@ -23,6 +23,7 @@ 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.api.utils.Durations; import org.sonar.core.issue.IssueUpdater; import org.sonar.server.user.UserSession; @@ -38,9 +39,11 @@ public class IssueChangelogFormatter implements ServerComponent { private static final String ISSUE_CHANGELOG_FIELD = "issue.changelog.field."; private final I18n i18n; + private final Durations durations; - public IssueChangelogFormatter(I18n i18n) { + public IssueChangelogFormatter(I18n i18n, Durations durations) { this.i18n = i18n; + this.durations = durations; } public List format(Locale locale, FieldDiffs diffs) { @@ -72,10 +75,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(), Duration.create(Long.parseLong(newValueString))); + newValueString = durations.format(UserSession.get().locale(), Duration.create(Long.parseLong(newValueString)), Durations.DurationFormat.SHORT); } if (oldValueString != null) { - oldValueString = i18n.formatWorkDuration(UserSession.get().locale(), Duration.create(Long.parseLong(oldValueString))); + oldValueString = durations.format(UserSession.get().locale(), Duration.create(Long.parseLong(oldValueString)), Durations.DurationFormat.SHORT); } } return new IssueChangelogDiffFormat(oldValueString, newValueString); diff --git a/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java b/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java index 116b32da940..3a78d88179f 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java @@ -34,6 +34,7 @@ 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.Durations; import org.sonar.api.utils.text.JsonWriter; import org.sonar.api.web.UserRole; import org.sonar.core.component.ComponentDto; @@ -64,15 +65,17 @@ public class IssueShowWsHandler implements RequestHandler { private final ActionService actionService; private final DefaultTechnicalDebtManager technicalDebtManager; private final I18n i18n; + private final Durations durations; public IssueShowWsHandler(IssueFinder issueFinder, IssueService issueService, IssueChangelogService issueChangelogService, ActionService actionService, - DefaultTechnicalDebtManager technicalDebtManager, I18n i18n) { + DefaultTechnicalDebtManager technicalDebtManager, I18n i18n, Durations durations) { this.issueFinder = issueFinder; this.issueService = issueService; this.issueChangelogService = issueChangelogService; this.actionService = actionService; this.technicalDebtManager = technicalDebtManager; this.i18n = i18n; + this.durations = durations; } @Override @@ -115,7 +118,7 @@ public class IssueShowWsHandler implements RequestHandler { .prop("author", issue.authorLogin()) .prop("actionPlan", actionPlanKey) .prop("actionPlanName", actionPlan != null ? actionPlan.name() : null) - .prop("debt", debt != null ? i18n.formatWorkDuration(UserSession.get().locale(), debt) : null) + .prop("debt", debt != null ? durations.format(UserSession.get().locale(), debt, Durations.DurationFormat.SHORT) : null) .prop("creationDate", DateUtils.formatDateTime(issue.creationDate())) .prop("fCreationDate", formatDate(issue.creationDate())) .prop("updateDate", updateDate != null ? DateUtils.formatDateTime(updateDate) : null) diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 619cc7b6625..4a4f73cb465 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -32,18 +32,17 @@ import org.sonar.api.resources.Languages; import org.sonar.api.resources.ResourceTypes; import org.sonar.api.rules.AnnotationRuleParser; import org.sonar.api.rules.XMLRuleParser; +import org.sonar.api.utils.Durations; import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.TimeProfiler; import org.sonar.api.utils.UriReader; import org.sonar.api.utils.internal.TempFolderCleaner; -import org.sonar.api.utils.internal.WorkDurationFactory; import org.sonar.core.component.SnapshotPerspectives; import org.sonar.core.component.db.ComponentDao; import org.sonar.core.config.Logback; import org.sonar.core.i18n.DefaultI18n; import org.sonar.core.i18n.GwtI18n; import org.sonar.core.i18n.RuleI18nManager; -import org.sonar.core.i18n.WorkDurationFormatter; import org.sonar.core.issue.IssueFilterSerializer; import org.sonar.core.issue.IssueNotifications; import org.sonar.core.issue.IssueUpdater; @@ -221,8 +220,7 @@ public final class Platform { rootContainer.addSingleton(DefaultI18n.class); rootContainer.addSingleton(RuleI18nManager.class); rootContainer.addSingleton(GwtI18n.class); - rootContainer.addSingleton(WorkDurationFormatter.class); - rootContainer.addSingleton(WorkDurationFactory.class); + rootContainer.addSingleton(Durations.class); rootContainer.addSingleton(PreviewDatabaseFactory.class); rootContainer.addSingleton(SemaphoreUpdater.class); diff --git a/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java b/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java index 8496e53051c..55b2cb52a4f 100644 --- a/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java +++ b/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java @@ -22,8 +22,6 @@ package org.sonar.server.technicaldebt; import org.sonar.api.ServerComponent; import org.sonar.api.technicaldebt.server.Characteristic; -import org.sonar.api.utils.internal.WorkDuration; -import org.sonar.api.utils.internal.WorkDurationFactory; import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager; import javax.annotation.CheckForNull; @@ -31,20 +29,14 @@ import javax.annotation.CheckForNull; import java.util.List; /** - * Used through ruby code
Internal.technical_debt
+ * Used through ruby code
Internal.debt
*/ public class DebtService implements ServerComponent { private final DefaultTechnicalDebtManager finder; - private final WorkDurationFactory workDurationFactory; - public DebtService(DefaultTechnicalDebtManager finder, WorkDurationFactory workDurationFactory) { + public DebtService(DefaultTechnicalDebtManager finder) { this.finder = finder; - this.workDurationFactory = workDurationFactory; - } - - public WorkDuration toWorkDuration(long debt) { - return workDurationFactory.createFromMinutes(debt); } public List findRootCharacteristics() { diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java index 80a6ba85320..b0a2eb4061e 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java @@ -24,6 +24,7 @@ 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.api.utils.Durations; import org.sonar.core.i18n.GwtI18n; import org.sonar.server.user.UserSession; @@ -39,11 +40,13 @@ import java.util.Map; public class JRubyI18n implements ServerComponent { private I18n i18n; + private Durations durations; private Map localesByRubyKey = Maps.newHashMap(); private GwtI18n gwtI18n; - public JRubyI18n(I18n i18n, GwtI18n gwtI18n) { + public JRubyI18n(I18n i18n, Durations durations, GwtI18n gwtI18n) { this.i18n = i18n; + this.durations = durations; this.gwtI18n = gwtI18n; } @@ -87,12 +90,12 @@ public class JRubyI18n implements ServerComponent { return i18n.ageFromNow(UserSession.get().locale(), date); } - public String formatWorkDuration(Duration duration) { - return i18n.formatWorkDuration(UserSession.get().locale(), duration); + public String formatDuration(Duration duration, String format) { + return durations.format(UserSession.get().locale(), duration, Durations.DurationFormat.valueOf(format)); } - public String formatLongWorkDuration(long duration) { - return formatWorkDuration(Duration.create(duration)); + public String formatLongDuration(long duration, String format) { + return formatDuration(Duration.create(duration), format); } } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb index a9b04bcd49b..155e122d4e6 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb @@ -187,11 +187,11 @@ class IssueController < ApplicationController require_parameters :id rule_key = params[:id].split(':') @rule = Rule.first(:conditions => ['plugin_name=? and plugin_rule_key=?', rule_key[0], rule_key[1]]) - @requirement = Internal.technical_debt.findRequirementByRuleId(@rule.id) + @requirement = Internal.debt.findRequirementByRuleId(@rule.id) # Requirement can be null if it's disabled or if there's no requirement on this rule if @requirement - @characteristic = Internal.technical_debt.findCharacteristic(@requirement.parentId) - @root_characteristic = Internal.technical_debt.findCharacteristic(@requirement.rootId) + @characteristic = Internal.debt.findCharacteristic(@requirement.parentId) + @root_characteristic = Internal.debt.findCharacteristic(@requirement.rootId) end render :partial => 'issue/rule' end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb index b169243bb19..c986b8101f0 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb @@ -54,7 +54,7 @@ class Internal component(Java::OrgSonarServerPermission::InternalPermissionTemplateService.java_class) end - def self.technical_debt + def self.debt component(Java::OrgSonarServerTechnicaldebt::DebtService.java_class) end @@ -86,6 +86,10 @@ class Internal component(Java::OrgSonarServerRule::RuleTags.java_class) end + def self.durations + component(Java::OrgSonarApiUtils::Durations.java_class) + end + def self.i18n component(Java::OrgSonarServerUi::JRubyI18n.java_class) end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb index 2c99796de44..4d05132ced8 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/issue.rb @@ -34,7 +34,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] = debt_to_hash(issue.debt) if issue.debt + hash[:debt] = Internal.durations.encode(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 @@ -75,8 +75,8 @@ class Issue hash_diff = {} hash_diff[:key] = key if key == 'technicalDebt' - 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? + hash_diff[:newValue] = Internal.durations.encode(Internal.durations.create(diff.newValue().to_i)) if diff.newValue.present? + hash_diff[:oldValue] = Internal.durations.encode(Internal.durations.create(diff.oldValue().to_i)) if diff.oldValue.present? else hash_diff[:newValue] = diff.newValue() if diff.newValue.present? hash_diff[:oldValue] = diff.oldValue() if diff.oldValue.present? @@ -89,21 +89,4 @@ class Issue hash end - - 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(), - :hours => work_duration.hours(), - :minutes => work_duration.minutes() - } - end - end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb index 0198b35e57a..d60697245a1 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb @@ -164,7 +164,7 @@ class ProjectMeasure < ActiveRecord::Base end def work_duration_formatted_value(value) - Internal.i18n.formatLongWorkDuration(value.to_i) + Internal.i18n.formatLongDuration(value.to_i, 'SHORT') end def color diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb index 304bf918f5b..7f15477920d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb @@ -96,7 +96,7 @@ <% end %> <% end %> <% if issue.debt %> -
  • <%= message('issue.debt') -%> <%= Internal.i18n.formatWorkDuration(issue.debt) -%>
  • +
  • <%= message('issue.debt') -%> <%= Internal.i18n.formatDuration(issue.debt, 'SHORT') -%>
  • <% end %> <% if issue.authorLogin %>
  • <%= message('issue.authorLogin') -%> <%= issue.authorLogin -%>
  • diff --git a/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java b/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java index 98323c582b6..a6c35a51f28 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java @@ -27,6 +27,7 @@ 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 org.sonar.api.utils.Durations; import java.util.List; import java.util.Locale; @@ -44,11 +45,15 @@ public class IssueChangelogFormatterTest { @Mock private I18n i18n; + @Mock + private Durations durations; + + private IssueChangelogFormatter formatter; @Before public void before() { - formatter = new IssueChangelogFormatter(i18n); + formatter = new IssueChangelogFormatter(i18n, durations); } @Test @@ -128,8 +133,8 @@ public class IssueChangelogFormatterTest { FieldDiffs diffs = new FieldDiffs(); diffs.setDiff("technicalDebt", "18000", "28800"); - 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(durations.format(any(Locale.class), eq(Duration.create(18000L)), eq(Durations.DurationFormat.SHORT))).thenReturn("5 hours"); + when(durations.format(any(Locale.class), eq(Duration.create(28800L)), eq(Durations.DurationFormat.SHORT))).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"); @@ -146,7 +151,7 @@ public class IssueChangelogFormatterTest { FieldDiffs diffs = new FieldDiffs(); diffs.setDiff("technicalDebt", null, "28800"); - when(i18n.formatWorkDuration(any(Locale.class), eq(Duration.create(28800L)))).thenReturn("1 days"); + when(durations.format(any(Locale.class), eq(Duration.create(28800L)), eq(Durations.DurationFormat.SHORT))).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"); diff --git a/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java b/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java index 2dc944f5534..5d9c8edeb54 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java @@ -43,6 +43,7 @@ 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.utils.Durations; import org.sonar.api.web.UserRole; import org.sonar.core.component.ComponentDto; import org.sonar.core.issue.DefaultActionPlan; @@ -89,6 +90,9 @@ public class IssueShowWsHandlerTest { @Mock I18n i18n; + @Mock + Durations durations; + List issues; DefaultIssueQueryResult result; @@ -110,7 +114,7 @@ public class IssueShowWsHandlerTest { when(i18n.message(any(Locale.class), eq("created"), eq((String) null))).thenReturn("Created"); - tester = new WsTester(new IssuesWs(new IssueShowWsHandler(issueFinder, issueService, issueChangelogService, actionService, technicalDebtManager, i18n))); + tester = new WsTester(new IssuesWs(new IssueShowWsHandler(issueFinder, issueService, issueChangelogService, actionService, technicalDebtManager, i18n, durations))); } @Test @@ -307,7 +311,7 @@ public class IssueShowWsHandlerTest { Issue issue = createStandardIssue().setDebt(debt); issues.add(issue); - when(i18n.formatWorkDuration(any(Locale.class), eq(debt))).thenReturn("2 hours 1 minutes"); + when(durations.format(any(Locale.class), eq(debt), eq(Durations.DurationFormat.SHORT))).thenReturn("2 hours 1 minutes"); MockUserSession.set(); WsTester.TestRequest request = tester.newRequest("show").setParam("key", issue.key()); diff --git a/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java b/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java index f60b78dae01..b66fc6c26f5 100644 --- a/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java @@ -21,12 +21,8 @@ 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.technicaldebt.server.Characteristic; import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic; -import org.sonar.api.utils.internal.WorkDuration; -import org.sonar.api.utils.internal.WorkDurationFactory; import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager; import java.util.List; @@ -37,21 +33,13 @@ import static org.mockito.Mockito.*; public class DebtServiceTest { - private static final int HOURS_IN_DAY = 8; DefaultTechnicalDebtManager finder = mock(DefaultTechnicalDebtManager.class); DebtService service; @Before public void setUp() throws Exception { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY); - service = new DebtService(finder, new WorkDurationFactory(settings)); - } - - @Test - public void to_work_duration() { - assertThat(service.toWorkDuration(60L * HOURS_IN_DAY)).isEqualTo(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, HOURS_IN_DAY)); + service = new DebtService(finder); } @Test diff --git a/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java b/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java index ef26d5c0209..a66ecac1370 100644 --- a/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java +++ b/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java @@ -26,6 +26,7 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.sonar.api.i18n.I18n; import org.sonar.api.utils.Duration; +import org.sonar.api.utils.Durations; import org.sonar.core.i18n.GwtI18n; import java.util.Date; @@ -45,12 +46,15 @@ public class JRubyI18nTest { @Mock GwtI18n gwtI18n; + @Mock + Durations durations; + JRubyI18n jRubyI18n; @Before public void setUp() throws Exception { - jRubyI18n = new JRubyI18n(i18n, gwtI18n); + jRubyI18n = new JRubyI18n(i18n, durations, gwtI18n); } @Test @@ -95,14 +99,14 @@ public class JRubyI18nTest { @Test public void format_work_duration() throws Exception { - jRubyI18n.formatWorkDuration(Duration.create(10L)); - verify(i18n).formatWorkDuration(any(Locale.class), eq(Duration.create(10L))); + jRubyI18n.formatDuration(Duration.create(10L), "SHORT"); + verify(durations).format(any(Locale.class), eq(Duration.create(10L)), eq(Durations.DurationFormat.SHORT)); } @Test public void format_long_work_duration() throws Exception { - jRubyI18n.formatLongWorkDuration(10L); - verify(i18n).formatWorkDuration(any(Locale.class), eq(Duration.create(10L))); + jRubyI18n.formatLongDuration(10L, "SHORT"); + verify(durations).format(any(Locale.class), eq(Duration.create(10L)), eq(Durations.DurationFormat.SHORT)); } } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java index 5f0c825ca50..fe396834f22 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java @@ -55,7 +55,7 @@ public interface Issue { Double effortToFix(); @CheckForNull - WorkDayDuration technicalDebt(); + String debt(); String status(); diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/WorkDayDuration.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/WorkDayDuration.java deleted file mode 100644 index 1db322bf5e3..00000000000 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/WorkDayDuration.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.wsclient.issue; - -/** - * @since 4.0 - */ -public interface WorkDayDuration { - - Integer days(); - - Integer minutes(); - - Integer hours(); - -} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java index 75c1d776925..cbe7005e074 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java @@ -21,7 +21,6 @@ package org.sonar.wsclient.issue.internal; import org.sonar.wsclient.issue.Issue; import org.sonar.wsclient.issue.IssueComment; -import org.sonar.wsclient.issue.WorkDayDuration; import org.sonar.wsclient.unmarshallers.JsonUtils; import javax.annotation.CheckForNull; @@ -82,12 +81,8 @@ public class DefaultIssue implements Issue { } @CheckForNull - public WorkDayDuration technicalDebt() { - Map technicalDebt = (Map) json.get("technicalDebt"); - if (technicalDebt != null) { - return new DefaultWorkDayDuration(technicalDebt); - } - return null; + public String debt() { + return JsonUtils.getString(json, "debt"); } public String status() { @@ -147,7 +142,7 @@ public class DefaultIssue implements Issue { } public Map attributes() { - Map attr = (Map) json.get("attr"); + Map attr = (Map) json.get("attr"); if (attr == null) { return Collections.emptyMap(); } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueChangeDiff.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueChangeDiff.java index 289d3dd62e4..e357076fa1b 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueChangeDiff.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueChangeDiff.java @@ -53,19 +53,7 @@ public class DefaultIssueChangeDiff implements IssueChangeDiff { } private Object parseValue(String attribute) { - if ("technicalDebt".equals(key())) { - return parseDefaultTechnicalDebt(attribute); - } else { - return JsonUtils.getString(json, attribute); - } - } - - private DefaultWorkDayDuration parseDefaultTechnicalDebt(String attribute){ - Map technicalDebt = (Map) json.get(attribute); - if (technicalDebt != null) { - return new DefaultWorkDayDuration(technicalDebt); - } - return null; + return JsonUtils.getString(json, attribute); } } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultWorkDayDuration.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultWorkDayDuration.java deleted file mode 100644 index 7e2ecc79091..00000000000 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultWorkDayDuration.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.wsclient.issue.internal; - -import org.sonar.wsclient.issue.WorkDayDuration; -import org.sonar.wsclient.unmarshallers.JsonUtils; - -import java.util.Map; - -/** - * @since 4.0 - */ -public class DefaultWorkDayDuration implements WorkDayDuration { - - private final Map json; - - DefaultWorkDayDuration(Map json) { - this.json = json; - } - - public Integer days() { - return JsonUtils.getInteger(json, "days"); - } - - public Integer hours() { - return JsonUtils.getInteger(json, "hours"); - } - - public Integer minutes() { - return JsonUtils.getInteger(json, "minutes"); - } - -} diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java index 5440852389b..b0f5de37056 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java @@ -52,7 +52,7 @@ public class IssueJsonParserTest { assertThat(first.assignee()).isEqualTo("karadoc"); assertThat(first.message()).isEqualTo("the message"); assertThat(first.effortToFix()).isEqualTo(4.2); - assertThat(first.technicalDebt()).isNull(); + assertThat(first.debt()).isNull(); assertThat(first.reporter()).isEqualTo("perceval"); assertThat(first.author()).isEqualTo("pirlouis"); assertThat(first.actionPlan()).isEqualTo("9450b10c-e725-48b8-bf01-acdec751c491"); @@ -68,7 +68,7 @@ public class IssueJsonParserTest { assertThat(second.key()).isEqualTo("FGHIJ"); assertThat(second.line()).isNull(); assertThat(second.effortToFix()).isNull(); - assertThat(second.technicalDebt()).isNull(); + assertThat(second.debt()).isNull(); assertThat(second.reporter()).isNull(); assertThat(second.author()).isNull(); assertThat(second.attribute("JIRA")).isNull(); @@ -207,9 +207,7 @@ public class IssueJsonParserTest { assertThat(issues.size()).isEqualTo(1); Issue issue = issues.list().get(0); - assertThat(issue.technicalDebt().days()).isEqualTo(3); - assertThat(issue.technicalDebt().hours()).isEqualTo(0); - assertThat(issue.technicalDebt().minutes()).isEqualTo(10); + assertThat(issue.debt()).isEqualTo("3d10min"); } @@ -255,16 +253,8 @@ public class IssueJsonParserTest { assertThat(change.diffs()).hasSize(1); IssueChangeDiff changeDiff = change.diffs().get(0); assertThat(changeDiff.key()).isEqualTo("technicalDebt"); - - WorkDayDuration newTechnicalDebt = (WorkDayDuration) changeDiff.newValue(); - assertThat(newTechnicalDebt.days()).isEqualTo(2); - assertThat(newTechnicalDebt.hours()).isEqualTo(1); - assertThat(newTechnicalDebt.minutes()).isEqualTo(0); - - WorkDayDuration oldTechnicalDebt = (WorkDayDuration) changeDiff.oldValue(); - assertThat(oldTechnicalDebt.days()).isEqualTo(3); - assertThat(oldTechnicalDebt.hours()).isEqualTo(0); - assertThat(oldTechnicalDebt.minutes()).isEqualTo(10); + assertThat(changeDiff.newValue()).isEqualTo("2d1h"); + assertThat(changeDiff.oldValue()).isEqualTo("3d10min"); } @Test @@ -280,14 +270,8 @@ public class IssueJsonParserTest { assertThat(change.diffs()).hasSize(1); IssueChangeDiff changeDiff = change.diffs().get(0); assertThat(changeDiff.key()).isEqualTo("technicalDebt"); - - WorkDayDuration newTechnicalDebt = (WorkDayDuration) changeDiff.newValue(); - assertThat(newTechnicalDebt.days()).isEqualTo(2); - assertThat(newTechnicalDebt.hours()).isEqualTo(1); - assertThat(newTechnicalDebt.minutes()).isEqualTo(0); - - WorkDayDuration oldTechnicalDebt = (WorkDayDuration) changeDiff.oldValue(); - assertThat(oldTechnicalDebt).isNull(); + assertThat(changeDiff.newValue()).isEqualTo("2d1h"); + assertThat(changeDiff.oldValue()).isNull(); } @Test diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-only-new-technical-debt.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-only-new-technical-debt.json index 8600644db31..645c9eb2dac 100644 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-only-new-technical-debt.json +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-only-new-technical-debt.json @@ -6,11 +6,7 @@ "diffs": [ { "key": "technicalDebt", - "newValue": { - "days": 2, - "hours": 1, - "minutes": 0 - } + "newValue": "2d1h" } ] } diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-technical-debt.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-technical-debt.json index 980a523216c..3989c989ad6 100644 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-technical-debt.json +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-technical-debt.json @@ -6,16 +6,8 @@ "diffs": [ { "key": "technicalDebt", - "oldValue": { - "days": 3, - "hours": 0, - "minutes": 10 - }, - "newValue": { - "days": 2, - "hours": 1, - "minutes": 0 - } + "oldValue": "3d10min", + "newValue": "2d1h" } ] } diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-technical-debt.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-technical-debt.json index cda81fc2262..1da214fac67 100644 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-technical-debt.json +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-technical-debt.json @@ -7,11 +7,7 @@ "rule": "squid:CycleBetweenPackages", "severity": "CRITICAL", "status": "OPEN", - "technicalDebt": { - "days": 3, - "hours": 0, - "minutes": 10 - } + "debt": "3d10min" } ], "rules": [ -- 2.39.5