<br/>
<span style="font-weight: bold">
<%= message('widget.rules.removed') -%>
- <span class="varb"><%= Internal.i18n.formatLongWorkDuration(estimated_cleared_technical_debt) -%></span>
+ <span class="varb"><%= Internal.i18n.formatLongDuration(estimated_cleared_technical_debt, 'SHORT') -%></span>
</span>
<% end %>
<% end %>
<%
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?
</a>
</td>
<td class="val value-debt-<%= h(characteristic.key) -%>">
- <a href="<%= drilldown_url -%>" class="link-debt-<%= h(characteristic.key) -%>"><%= Internal.i18n.formatLongWorkDuration(value.to_i) -%></a>
+ <a href="<%= drilldown_url -%>" class="link-debt-<%= h(characteristic.key) -%>"><%= Internal.i18n.formatLongDuration(value.to_i, 'SHORT') -%></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.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')
%>
<span class="<%= css_style -%>"><b>(<%= diff_to_display -%>)</b></span>
<%
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;
PastSnapshotFinderByPreviousVersion.class,
PastMeasuresLoader.class,
PastSnapshotFinder.class,
- WorkDurationFormatter.class,
- WorkDurationFactory.class
+ Durations.class
);
}
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;
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
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;
}
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;
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);
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");
}
// 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)));
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;
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;
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() {
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<WorkDurationFormatter.Result> 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.
+++ /dev/null
-/*
- * 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<Result> 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<Result> format(WorkDuration workDuration, boolean isNegative) {
- List<Result> 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<Result> 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();
- }
- }
-}
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;
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;
@Mock
System2 system2;
- @Mock
- WorkDurationFormatter workDurationFormatter;
-
-
DefaultI18n manager;
@Before
I18nClassloader i18nClassloader = new I18nClassloader(new ClassLoader[]{
newCoreClassloader(), newFrenchPackClassloader(), newSqaleClassloader(), newCheckstyleClassloader()
});
- manager = new DefaultI18n(pluginRepository, workDurationFormatter, system2);
+ manager = new DefaultI18n(pluginRepository, system2);
manager.doStart(i18nClassloader);
}
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/");
}
+++ /dev/null
-/*
- * 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)));
- }
-
-}
import org.sonar.api.BatchComponent;
import org.sonar.api.ServerComponent;
-import org.sonar.api.utils.Duration;
import javax.annotation.Nullable;
/**
* 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);
*/
String formatDate(Locale locale, Date date);
- /**
- * Return the formatted work duration.
- * <br>
- * Example : format(Locale.ENGLISH, Duration.create(10 * 24 * 60 + 2 * 60)) -> 10d 2h
- *
- * @since 4.3
- */
- String formatWorkDuration(Locale locale, Duration duration);
-
}
--- /dev/null
+/*
+ * 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 <pre>Internal.durations</pre>
+ *
+ * @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
+ * <br>
+ * 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.
+ * <br>
+ * 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.
+ * <br>
+ * 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);
+ }
+
+}
+++ /dev/null
-/*
- * 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);
- }
-
-}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
+++ /dev/null
-/*
- * 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);
- }
-}
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;
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<String> format(Locale locale, FieldDiffs diffs) {
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);
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;
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
.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)
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;
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);
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;
import java.util.List;
/**
- * Used through ruby code <pre>Internal.technical_debt</pre>
+ * Used through ruby code <pre>Internal.debt</pre>
*/
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<Characteristic> findRootCharacteristics() {
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;
public class JRubyI18n implements ServerComponent {
private I18n i18n;
+ private Durations durations;
private Map<String, Locale> 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;
}
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);
}
}
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
component(Java::OrgSonarServerPermission::InternalPermissionTemplateService.java_class)
end
- def self.technical_debt
+ def self.debt
component(Java::OrgSonarServerTechnicaldebt::DebtService.java_class)
end
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
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
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?
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
end
def work_duration_formatted_value(value)
- Internal.i18n.formatLongWorkDuration(value.to_i)
+ Internal.i18n.formatLongDuration(value.to_i, 'SHORT')
end
def color
<% end %>
<% end %>
<% if issue.debt %>
- <li><%= message('issue.debt') -%> <%= Internal.i18n.formatWorkDuration(issue.debt) -%></li>
+ <li><%= message('issue.debt') -%> <%= Internal.i18n.formatDuration(issue.debt, 'SHORT') -%></li>
<% end %>
<% if issue.authorLogin %>
<li><%= message('issue.authorLogin') -%> <%= issue.authorLogin -%></li>
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;
@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
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");
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");
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;
@Mock
I18n i18n;
+ @Mock
+ Durations durations;
+
List<Issue> issues;
DefaultIssueQueryResult result;
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
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());
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;
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
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;
@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
@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));
}
}
Double effortToFix();
@CheckForNull
- WorkDayDuration technicalDebt();
+ String debt();
String status();
+++ /dev/null
-/*
- * 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();
-
-}
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;
}
@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() {
}
public Map<String, String> attributes() {
- Map<String, String> attr = (Map<String,String>) json.get("attr");
+ Map<String, String> attr = (Map<String, String>) json.get("attr");
if (attr == null) {
return Collections.emptyMap();
}
}
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);
}
}
+++ /dev/null
-/*
- * 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");
- }
-
-}
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");
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();
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");
}
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
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
"diffs": [
{
"key": "technicalDebt",
- "newValue": {
- "days": 2,
- "hours": 1,
- "minutes": 0
- }
+ "newValue": "2d1h"
}
]
}
"diffs": [
{
"key": "technicalDebt",
- "oldValue": {
- "days": 3,
- "hours": 0,
- "minutes": 10
- },
- "newValue": {
- "days": 2,
- "hours": 1,
- "minutes": 0
- }
+ "oldValue": "3d10min",
+ "newValue": "2d1h"
}
]
}
"rule": "squid:CycleBetweenPackages",
"severity": "CRITICAL",
"status": "OPEN",
- "technicalDebt": {
- "days": 3,
- "hours": 0,
- "minutes": 10
- }
+ "debt": "3d10min"
}
],
"rules": [