diff --git a/src/main/java/io/jenkins/plugins/reporter/ReportAction.java b/src/main/java/io/jenkins/plugins/reporter/ReportAction.java index cbe96c31..d21dc0bb 100644 --- a/src/main/java/io/jenkins/plugins/reporter/ReportAction.java +++ b/src/main/java/io/jenkins/plugins/reporter/ReportAction.java @@ -109,6 +109,11 @@ public ReportDetails getTarget() { public ReportResult getResult() { return result; } + + @Whitelisted + public io.jenkins.plugins.reporter.model.Report getReport() { + return result.getReport(); + } /** * Returns the name of the report. diff --git a/src/main/java/io/jenkins/plugins/reporter/ReportDetails.java b/src/main/java/io/jenkins/plugins/reporter/ReportDetails.java index 56737a5b..c24ebb6e 100644 --- a/src/main/java/io/jenkins/plugins/reporter/ReportDetails.java +++ b/src/main/java/io/jenkins/plugins/reporter/ReportDetails.java @@ -146,7 +146,7 @@ public String getItemPieChartModel() { */ @SuppressWarnings("unused") // Called by jelly view public ItemTableModel getTableModel() { - return new ItemTableModel(result.getReport(), getItem()); + return new ItemTableModel(result.getReport(), getItem(), owner); } /** diff --git a/src/main/java/io/jenkins/plugins/reporter/model/DisplayType.java b/src/main/java/io/jenkins/plugins/reporter/model/DisplayType.java index d186fe61..0a626450 100644 --- a/src/main/java/io/jenkins/plugins/reporter/model/DisplayType.java +++ b/src/main/java/io/jenkins/plugins/reporter/model/DisplayType.java @@ -4,5 +4,6 @@ public enum DisplayType { ABSOLUTE, RELATIVE, - DUAL; + DUAL, + DELTA; } diff --git a/src/main/java/io/jenkins/plugins/reporter/model/ItemTableModel.java b/src/main/java/io/jenkins/plugins/reporter/model/ItemTableModel.java index 96e83a93..f8b426aa 100644 --- a/src/main/java/io/jenkins/plugins/reporter/model/ItemTableModel.java +++ b/src/main/java/io/jenkins/plugins/reporter/model/ItemTableModel.java @@ -1,6 +1,9 @@ package io.jenkins.plugins.reporter.model; +import hudson.model.Run; import io.jenkins.plugins.datatables.TableColumn; +import io.jenkins.plugins.reporter.ReportAction; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.CaseUtils; import java.io.UnsupportedEncodingException; @@ -9,6 +12,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; /** @@ -23,6 +27,10 @@ public class ItemTableModel { private final Item item; + private final Run owner; + + private final Optional referenceReport; + /** * Creates a new instance of {@link ItemTableModel}. * @@ -32,11 +40,13 @@ public class ItemTableModel { * @param item * the item to render */ - public ItemTableModel(final Report report, final Item item) { + public ItemTableModel(final Report report, final Item item, final Run owner) { super(); this.report = report; this.item = item; + this.owner = owner; + this.referenceReport = getReferenceReport(); } public String getId() { @@ -60,7 +70,7 @@ public List getColumns() { public List getRows() { return item.getItems() .stream() - .map(item -> new ItemRow(report, item, this)) + .map(item -> new ItemRow(report, item, this, referenceReport)) .collect(Collectors.toList()); } @@ -73,7 +83,8 @@ protected TableColumn createResultAbsoluteColumn(String property) { } public String label(Integer value) { - return item.getLabel(report, value, value / (double) item.getTotal() * 100); + // This method is now only used for the total row, which doesn't show delta + return String.valueOf(value); } /** @@ -83,6 +94,7 @@ public static class ItemRow { private final Report report; private final Item item; + private final Optional referenceReport; private final ItemTableModel model; @@ -96,10 +108,11 @@ public static class ItemRow { * @param item * the item to render. */ - ItemRow(Report report, Item item, ItemTableModel model) { + ItemRow(Report report, Item item, ItemTableModel model, Optional referenceReport) { this.report = report; this.item = item; this.model = model; + this.referenceReport = referenceReport; } public String getId() { @@ -145,15 +158,68 @@ public String getColor(String id) { } public String label(String id, Integer value) { - if (item.getResult().size() == 1) { - return item.getLabel(report, value, value / (double) model.getItem().getTotal() * 100); + switch (report.getDisplayType()) { + case DELTA: + Integer previousValue = getLastSuccessBuildValue(id); + return formatDeltaLabel(value, previousValue); + case RELATIVE: + if (item.getResult().size() == 1) { + return String.format("%.2f%%", value / (double) model.getItem().getTotal() * 100); + } + return String.format("%.2f%%", value / (double) item.getTotal() * 100); + case DUAL: + if (item.getResult().size() == 1) { + return String.format("%d (%.2f%%)", value, value / (double) model.getItem().getTotal() * 100); + } + return String.format("%d (%.2f%%)", value, value / (double) item.getTotal() * 100); + case ABSOLUTE: + default: + return String.valueOf(value); } - - return item.getLabel(report, value, value / (double) model.getItem().getResult().get(id) * 100); } public String tooltip(String id, double percentage) { return String.format("%s: %.2f%%", id, percentage); } + + public Integer getLastSuccessBuildValue(String property) { + if (referenceReport.isPresent()) { + Optional referenceItem = referenceReport.get().findItem(item.getId()); + if (referenceItem.isPresent()) { + return referenceItem.get().getResult().get(property); + } + } + return null; + } + + private String formatDeltaLabel(Integer currentValue, Integer previousValue) { + if (previousValue == null) { + return String.format("%d (+%d)", currentValue, currentValue); + } + + int delta = currentValue - previousValue; + + if (delta == 0) { + return currentValue.toString(); + } else { + return String.format("%d (%s%d)", currentValue, delta > 0 ? "+" : "", delta); + } + } + } + + private Optional getReferenceReport() { + if (owner == null) { + return Optional.empty(); + } + + Run lastSuccessfulBuild = owner.getParent().getLastSuccessfulBuild(); + if (lastSuccessfulBuild != null) { + ReportAction action = lastSuccessfulBuild.getAction(ReportAction.class); + if (action != null) { + return Optional.of(action.getReport()); + } + } + + return Optional.empty(); } } \ No newline at end of file diff --git a/src/main/resources/report/help-displayType.html b/src/main/resources/report/help-displayType.html index 0e7c7059..9258685f 100644 --- a/src/main/resources/report/help-displayType.html +++ b/src/main/resources/report/help-displayType.html @@ -1,5 +1,6 @@
- This can be used to change the display of the displayed metrics within the distribution table. - 'absolute' shows the absolute values from the underlying files. 'relative', shows percentage values - and 'dual' shows the absolute value and additionally the relative frequency within the category. + This can be used to change the display of the displayed metrics within the distribution table. + 'absolute' shows the absolute values from the underlying files. 'relative', shows percentage values, + 'dual' shows the absolute value and additionally the relative frequency within the category and 'delta' + shows the absolute value and additionally the delta to the last successful build.
\ No newline at end of file diff --git a/src/main/resources/report/step.properties b/src/main/resources/report/step.properties index f81ecade..7a348b4c 100644 --- a/src/main/resources/report/step.properties +++ b/src/main/resources/report/step.properties @@ -1,3 +1,3 @@ description.name=Choose a name for the report. The name is shown in the UI. description.displayType=Select the display type of the metrics in the table. Choose between 'absolute', \ - 'relative' and 'dual'. As default, if nothing is specified, 'absolute is used. \ No newline at end of file + 'relative', 'dual' and 'delta'. As default, if nothing is specified, 'absolute is used. \ No newline at end of file