Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
80600eb
Added customizable coverage dashboard column and advanced color utility
fo-code Feb 1, 2022
b54b15e
Merge branch 'jenkinsci:master' into coverage-visualization
fo-code Feb 1, 2022
87b8025
Fixed import
fo-code Feb 1, 2022
8fc810e
Fixed warnings
fo-code Feb 1, 2022
4b32a0c
Fixed warnings
fo-code Feb 1, 2022
46c44b8
Fixed import
fo-code Feb 1, 2022
52e4a39
Adjusted colorization levels
fo-code Feb 2, 2022
493ba4f
Merge branch 'master' into coverage-visualization
fo-code Feb 14, 2022
39b1b2b
Resolved merge conflicts
fo-code Feb 15, 2022
efa0c9e
Merge branch 'jenkinsci:master' into coverage-visualization
fo-code Feb 15, 2022
13a059a
Fixed test errors
fo-code Feb 16, 2022
b9427fb
Merge branch 'coverage-visualization' of https://github.com/fo-code/c…
fo-code Feb 16, 2022
dacd36c
Fixed test errors
fo-code Feb 16, 2022
e3c6dda
Merge branch 'master' into coverage-visualization
fo-code Feb 20, 2022
9707cef
Adjusted dependencies
fo-code Feb 22, 2022
9bedd54
Rework and advanced color handling
fo-code Feb 23, 2022
2f65f01
Merge branch 'master' into coverage-visualization
fo-code Feb 23, 2022
402ede9
Fixed tests
fo-code Feb 23, 2022
79a6f32
Added tests and javadoc
fo-code Feb 24, 2022
3aa8b5f
Style fixes
fo-code Feb 24, 2022
bf75d1e
Style fixes
fo-code Feb 24, 2022
dd13b4a
Adjusted color IDs
fo-code Mar 8, 2022
d6d5e85
Merge branch 'master' into coverage-visualization
fo-code Mar 10, 2022
f2959d1
Style fixes
fo-code Mar 10, 2022
934e4c6
Dynamically compute localized text so that the client locale will be …
uhafner Mar 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import hudson.model.Run;
import hudson.util.XStream2;

import io.jenkins.plugins.coverage.model.util.FractionFormatter;
import io.jenkins.plugins.forensics.reference.ReferenceBuild;
import io.jenkins.plugins.util.AbstractXmlStream;
import io.jenkins.plugins.util.BuildAction;
Expand Down Expand Up @@ -121,6 +122,30 @@ public Coverage getBranchCoverage() {
return branchCoverage;
}

/**
* Returns whether the {@link Coverage} for the passed metric exists.
*
* @param coverageMetric
* the metric to check
*
* @return {@code true} if a coverage is available for the specified metric
*/
public boolean hasCoverage(final CoverageMetric coverageMetric) {
return getResult().getCoverage(coverageMetric).isSet();
}

/**
* Gets the {@link Coverage} for the passed metric.
*
* @param coverageMetric
* The coverage metric
*
* @return the coverage
*/
public Coverage getCoverage(final CoverageMetric coverageMetric) {
return getResult().getCoverage(coverageMetric);
}

/**
* Returns the possible reference build that has been used to compute the coverage delta.
*
Expand Down Expand Up @@ -179,7 +204,7 @@ public boolean hasDelta(final CoverageMetric metric) {
public String formatDelta(final CoverageMetric metric) {
Locale clientLocale = Functions.getCurrentLocale();
if (hasDelta(metric)) {
return String.format(clientLocale, "%+.3f", difference.get(metric).doubleValue());
return FractionFormatter.formatDeltaFraction(difference.get(metric), clientLocale);
}
return Messages.Coverage_Not_Available();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.jenkins.plugins.coverage.model;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -79,6 +81,15 @@ public static CoverageMetric valueOf(final String name) {
return new CoverageMetric(name, DEFAULT_ORDER);
}

/**
* Provides all available values of {@link CoverageMetric}.
*
* @return the available metrics
*/
public static List<CoverageMetric> getAvailableCoverageMetrics() {
return Arrays.asList(LINE, BRANCH, INSTRUCTION, METHOD, CLASS, FILE, PACKAGE, MODULE);
}

/**
* Checks if this instance has a name that is equal to the specified name (ignoring case).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import hudson.model.ModelObject;
import hudson.model.Run;

import io.jenkins.plugins.coverage.model.visualization.colorization.ColorProvider;
import io.jenkins.plugins.coverage.model.visualization.colorization.ColorProviderFactory;
import io.jenkins.plugins.datatables.DefaultAsyncTableContentProvider;
import io.jenkins.plugins.datatables.TableColumn;
import io.jenkins.plugins.datatables.TableColumn.ColumnCss;
Expand All @@ -45,7 +47,8 @@ public class CoverageViewModel extends DefaultAsyncTableContentProvider implemen
private static final CoverageMetric LINE_COVERAGE = CoverageMetric.LINE;
private static final CoverageMetric BRANCH_COVERAGE = CoverageMetric.BRANCH;
private static final JacksonFacade JACKSON_FACADE = new JacksonFacade();
private static final TreeMapNodeConverter TREE_MAP_NODE_CONVERTER = new TreeMapNodeConverter();
private static final ColorProvider COLOR_PROVIDER = ColorProviderFactory.createColorProvider();
private static final TreeMapNodeConverter TREE_MAP_NODE_CONVERTER = new TreeMapNodeConverter(COLOR_PROVIDER);
private static final BuildResultNavigator NAVIGATOR = new BuildResultNavigator();

private final Run<?, ?> owner;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@

import edu.hm.hafner.echarts.TreeMapNode;

import io.jenkins.plugins.coverage.model.util.FractionFormatter;
import io.jenkins.plugins.coverage.model.visualization.colorization.ColorProvider;
import io.jenkins.plugins.coverage.model.visualization.colorization.CoverageLevel;

/**
* Converts a tree of {@link CoverageNode coverage nodes} to a corresponding tree of {@link TreeMapNode ECharts tree
* map nodes}.
* Converts a tree of {@link CoverageNode coverage nodes} to a corresponding tree of {@link TreeMapNode ECharts tree map
* nodes}.
*
* @author Ullrich Hafner
*/
class TreeMapNodeConverter {

private final ColorProvider colorProvider;

TreeMapNodeConverter(final ColorProvider colorProvider) {
this.colorProvider = colorProvider;
}

TreeMapNode toTeeChartModel(final CoverageNode node) {
TreeMapNode root = toTreeMapNode(node);
for (TreeMapNode child : root.getChildren()) {
Expand All @@ -21,9 +32,15 @@ TreeMapNode toTeeChartModel(final CoverageNode node) {
private TreeMapNode toTreeMapNode(final CoverageNode node) {
Coverage coverage = node.getCoverage(CoverageMetric.LINE);

TreeMapNode treeNode = new TreeMapNode(node.getName(),
assignColor(coverage.getRoundedPercentage()),
coverage.getTotal(), coverage.getCovered());
double coveragePercentage = FractionFormatter
.transformFractionToPercentage(coverage.getCoveredPercentage())
.doubleValue();

String color = CoverageLevel
.getDisplayColorsOfCoverageLevel(coveragePercentage, colorProvider)
.getFillColorAsHex();

TreeMapNode treeNode = new TreeMapNode(node.getName(), color, coverage.getTotal(), coverage.getCovered());
if (node.getMetric().equals(CoverageMetric.FILE)) {
return treeNode;
}
Expand All @@ -33,17 +50,4 @@ private TreeMapNode toTreeMapNode(final CoverageNode node) {
.forEach(treeNode::insertNode);
return treeNode;
}

private String assignColor(final double percentage) {
String[] colors = {"#ef9a9a", "#f6bca0", "#fbdea6", "#e2f1aa", "#c4e4a9", "#a5d6a7"};
double[] levels = {75, 50, 85, 90, 95};

for (int index = 0; index < levels.length; index++) {
if (percentage < levels[index]) {
return colors[index];
}
}
return colors[levels.length - 1];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.jenkins.plugins.coverage.model.util;

import java.util.Locale;

import org.apache.commons.lang3.math.Fraction;

/**
* Formats fraction and percentage values represented by {@link Fraction} and provides these values as formatted
* percentages dependent on the use case.
*
* @author Florian Orendi
*/
public class FractionFormatter {

private static final Fraction HUNDRED = Fraction.getFraction(100, 1);

private FractionFormatter() {
// prevents instantiation
}

/**
* Transforms a fraction within the range [0;1] to a percentage value within the range [0;100].
*
* @param fraction
* The fraction to be transformed
*
* @return the fraction as percentage
*/
public static Fraction transformFractionToPercentage(final Fraction fraction) {
return fraction.multiplyBy(HUNDRED);
}

/**
* Formats a percentage to plain text and rounds the value to two decimals.
*
* @param percentage
* The percentage to be formatted
* @param locale
* The used locale
*
* @return the formatted percentage as plain text
*/
public static String formatPercentage(final Fraction percentage, final Locale locale) {
return String.format(locale, "%.2f%%", percentage.doubleValue());
}

/**
* Formats a delta fraction to its plain text percentage representation with a leading sign and rounds the value to
* two decimals.
*
* @param fraction
* The fraction to be formatted
* @param locale
* The used locale
*
* @return the formatted delta fraction as plain text with a leading sign
*/
public static String formatDeltaFraction(final Fraction fraction, final Locale locale) {
return String.format(locale, "%+.2f%%", transformFractionToPercentage(fraction).doubleValue());
}

/**
* Formats a delta percentage to its plain text representation with a leading sign and rounds the value to two
* decimals.
*
* @param percentage
* The percentage to be formatted
* @param locale
* The used locale
*
* @return the formatted delta percentage as plain text with a leading sign
*/
public static String formatDeltaPercentage(final Fraction percentage, final Locale locale) {
return String.format(locale, "%+.2f%%", percentage.doubleValue());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.jenkins.plugins.coverage.model.visualization.colorization;

/**
* Provides IDs for colors which are used within this plugin in order to separate the color palette from the logic.
*
* @author Florian Orendi
*/
public enum ColorId {
INSUFFICIENT,
VERY_BAD,
BAD,
INADEQUATE,
BELOW_AVERAGE,
AVERAGE,
ABOVE_AVERAGE,
GOOD,
VERY_GOOD,
EXCELLENT,
OUTSTANDING,

BLACK,
WHITE
}
Loading