-
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel/index.jelly b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel/index.jelly
index 3c1e3e2dd..90faa8daa 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel/index.jelly
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel/index.jelly
@@ -8,12 +8,10 @@
-
-
+
-
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/model/CoverageViewModel/index.jelly b/plugin/src/main/resources/io/jenkins/plugins/coverage/model/CoverageViewModel/index.jelly
index ad5b54f12..d7a95d7af 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/model/CoverageViewModel/index.jelly
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/model/CoverageViewModel/index.jelly
@@ -8,9 +8,8 @@
-
-
+
diff --git a/plugin/src/main/webapp/css/column-style.css b/plugin/src/main/webapp/css/column-style.css
deleted file mode 100644
index 231a36a67..000000000
--- a/plugin/src/main/webapp/css/column-style.css
+++ /dev/null
@@ -1,14 +0,0 @@
-.coverage-column-outer {
- border: 1px solid var(--medium-grey);
- border-radius: 10px;
-}
-
-.coverage-column-inner {
- padding: 4px 7px;
- border-radius: 10px
-}
-
-.coverage-column-link:hover {
- text-decoration: none;
-}
-
diff --git a/plugin/src/main/webapp/css/custom-style.css b/plugin/src/main/webapp/css/view-model.css
similarity index 60%
rename from plugin/src/main/webapp/css/custom-style.css
rename to plugin/src/main/webapp/css/view-model.css
index 4060948ee..99cd44d4c 100644
--- a/plugin/src/main/webapp/css/custom-style.css
+++ b/plugin/src/main/webapp/css/view-model.css
@@ -93,3 +93,73 @@
#coverage-table td {
vertical-align: middle;
}
+
+table.source {
+ border-spacing: 0;
+ border-collapse: collapse;
+ border: 1px solid #bbb;
+ width: 100%;
+}
+
+table.source td {
+ border-spacing: 0;
+ border-collapse: collapse;
+ border: 0 solid #bbb;
+ padding-left: 0.2em;
+ padding-right: 0.2em;
+ font-family: monospace;
+}
+
+table.source .text {
+ margin-top: -1px;
+}
+
+table.source td.line {
+ text-align: right;
+ border-width: 0 1px 0 0;
+}
+
+table.source td.hits {
+ text-align: right;
+ border-width: 0px 1px 0px 0px;
+}
+
+table.source th {
+ padding-left: 0.5em;
+ font-weight: bold;
+ font-family: serif;
+ background-color: #f0f0f0;
+ border-width: 1px 1px 1px 1px;
+ text-align: left;
+}
+
+table.source tr.coverFull {
+ background-color: var(--green);
+ color: var(--white);
+ font-weight: bold;
+}
+
+table.source tr.coverPart {
+ background-color: var(--orange);
+ color: var(--text-color);
+ font-weight: bold;
+}
+
+table.source tr.coverPart td.hits, table.source tr.coverNone td.hits {
+ font-weight: bold;
+}
+
+table.source tr.coverNone {
+ background-color: var(--red);
+ color: var(--white);
+ font-weight: bold;
+}
+
+table.source tr.noCover {
+ background-color: var(--background-color);
+ color: var(--text-color);
+}
+
+table.source tr.coverSkip {
+ background-color: #b4b4b4;
+}
diff --git a/plugin/src/main/webapp/js/view-model.js b/plugin/src/main/webapp/js/view-model.js
index fe4300622..55ac31900 100644
--- a/plugin/src/main/webapp/js/view-model.js
+++ b/plugin/src/main/webapp/js/view-model.js
@@ -1,5 +1,17 @@
/* global jQuery3, viewProxy, echartsJenkinsApi, bootstrap5 */
+getJenkinsColors = function (colors) {
+ // TODO: also handle HSL colors and parse them to hex in order to use dark mode colors
+ const colorHexMapping = new Map;
+ colors.forEach(function (jenkinsId) {
+ const colorHex = getComputedStyle(document.body).getPropertyValue(jenkinsId);
+ if (colorHex.match(/^#[a-fA-F0-9]{6}$/) !== null) {
+ colorHexMapping.set(jenkinsId, colorHex);
+ }
+ })
+ return colorHexMapping;
+};
+
const CoverageChartGenerator = function ($) {
var selectedTreeNode;
@@ -14,41 +26,18 @@ const CoverageChartGenerator = function ($) {
}
});
};
-
- function getTextColor() {
- return getComputedStyle(document.body).getPropertyValue('--text-color') || '#333';
- }
-
- /**
- * Searches for a Jenkins color by a color id.
- *
- * @param jenkinsColors The available Jenkins colors
- * @param id The color id
- * @param defaultValue The default value if the id does not exist
- * @param alpha The alpha value between [0;255]
- * @returns {string} the hex code of the Jenkins color or, if not existent, the default value
- */
- function getJenkinsColorById(jenkinsColors, id, defaultValue, alpha) {
- const alphaHex = alpha.toString(16);
- if (jenkinsColors.has(id)) {
- const color = jenkinsColors.get(id);
- if (color.match(/^#[a-fA-F0-9]{6}$/) !== null) {
- return color + alphaHex;
- }
- }
- return defaultValue + alphaHex;
- }
-
- function createOverview(overview, id, jenkinsColors) {
- const missedColor = getJenkinsColorById(jenkinsColors, "--red", "#ff4d65", 120);
- const coveredColor = getJenkinsColorById(jenkinsColors, "--green", "#4bdf7c", 120);
+ function createOverview(overview, id) {
+ const missedColor = echartsJenkinsApi.resolveJenkinsColor("--red");
+ const missedText = echartsJenkinsApi.resolveJenkinsColor("--white");
+ const coveredColor = echartsJenkinsApi.resolveJenkinsColor("--green");
+ const coveredText = echartsJenkinsApi.resolveJenkinsColor("--white");
const summaryChartDiv = $('#' + id);
summaryChartDiv.height(overview.metrics.length * 31 + 150 + 'px');
const summaryChart = echarts.init(summaryChartDiv[0]);
summaryChartDiv[0].echart = summaryChart;
- const textColor = getTextColor();
+ const textColor = echartsJenkinsApi.getTextColor();
const summaryOption = {
tooltip: {
@@ -143,7 +132,8 @@ const CoverageChartGenerator = function ($) {
label: {
show: true,
position: 'insideLeft',
- color: 'black',
+ color: coveredText,
+ fontWeight: 'bold',
formatter: function (obj) {
return overview.covered[obj.dataIndex];
}
@@ -162,7 +152,8 @@ const CoverageChartGenerator = function ($) {
label: {
show: true,
position: 'insideRight',
- color: 'black',
+ color: missedText,
+ fontWeight: 'bold',
formatter: function (obj) {
return overview.missed[obj.dataIndex];
}
@@ -359,7 +350,7 @@ const CoverageChartGenerator = function ($) {
renderTrendChart();
viewProxy.getOverview(function (t) {
- createOverview(t.responseObject(), 'coverage-overview', jenkinsColors);
+ createOverview(t.responseObject(), 'coverage-overview');
});
$('.tree-chart').each(function () {
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java
index 526624c32..8e9ce50ce 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java
@@ -15,10 +15,12 @@
import edu.hm.hafner.echarts.ChartModelConfiguration.AxisType;
import edu.hm.hafner.echarts.line.LinesChartModel;
import edu.hm.hafner.echarts.line.LinesDataSet;
+import edu.hm.hafner.util.ResourceTest;
import edu.hm.hafner.util.VisibleForTesting;
import io.jenkins.plugins.coverage.metrics.model.CoverageStatistics;
+import static net.javacrumbs.jsonunit.assertj.JsonAssertions.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
@@ -27,7 +29,7 @@
*
* @author Ullrich Hafner
*/
-class CoverageSeriesBuilderTest {
+class CoverageSeriesBuilderTest extends ResourceTest {
@Test
void shouldHaveEmptyDataSetForEmptyIterator() {
CoverageSeriesBuilder builder = new CoverageSeriesBuilder();
@@ -99,6 +101,37 @@ void shouldHaveTwoValuesForSingleBuild() {
assertThat(dataSet.getSeries(CoverageSeriesBuilder.BRANCH_COVERAGE)).containsExactly(75.0);
}
+ @Test
+ void shouldHaveTwoValuesForTwoBuilds() {
+ CoverageSeriesBuilder builder = new CoverageSeriesBuilder();
+
+ BuildResult first = createResult(1,
+ new CoverageBuilder().setMetric(Metric.LINE).setCovered(1).setMissed(1).build(),
+ new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(3).setMissed(1).build());
+ BuildResult second = createResult(2,
+ new CoverageBuilder().setMetric(Metric.LINE).setCovered(1).setMissed(3).build(),
+ new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(1).setMissed(3).build());
+
+ LinesDataSet dataSet = builder.createDataSet(createConfiguration(), List.of(first, second));
+
+ assertThat(dataSet.getDomainAxisSize()).isEqualTo(2);
+ assertThat(dataSet.getDomainAxisLabels()).containsExactly("#1", "#2");
+
+ assertThat(dataSet.getDataSetIds()).containsExactlyInAnyOrder(
+ CoverageSeriesBuilder.LINE_COVERAGE,
+ CoverageSeriesBuilder.BRANCH_COVERAGE);
+
+ assertThat(dataSet.getSeries(CoverageSeriesBuilder.LINE_COVERAGE))
+ .containsExactly(50.0, 25.0);
+ assertThat(dataSet.getSeries(CoverageSeriesBuilder.BRANCH_COVERAGE))
+ .containsExactly(75.0, 25.0);
+
+ CoverageTrendChart trendChart = new CoverageTrendChart();
+ var model = trendChart.create(List.of(first, second), createConfiguration());
+
+ assertThatJson(model).isEqualTo(toString("chart.json"));
+ }
+
private ChartModelConfiguration createConfiguration() {
ChartModelConfiguration configuration = mock(ChartModelConfiguration.class);
when(configuration.getAxisType()).thenReturn(AxisType.BUILD);
diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/charts/chart.json b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/charts/chart.json
new file mode 100644
index 000000000..b6008e20e
--- /dev/null
+++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/charts/chart.json
@@ -0,0 +1,48 @@
+{
+ "domainAxisLabels": [
+ "#1", "#2"
+ ],
+ "buildNumbers": [
+ 1, 2
+ ],
+ "series": [
+ {
+ "name": "Line Coverage",
+ "type": "line",
+ "symbol": "circle",
+ "data": [
+ 50.0, 25.0
+ ],
+ "itemStyle": {
+ "color": "--green",
+ "borderColor": "#ffffff",
+ "borderWidth": 0
+ },
+ "stack": "",
+ "areaStyle": {
+ "normal": true
+ }
+ },
+ {
+ "name": "Branch Coverage",
+ "type": "line",
+ "symbol": "circle",
+ "data": [
+ 75.0, 25.0
+ ],
+ "itemStyle": {
+ "color": "--dark-green",
+ "borderColor": "#ffffff",
+ "borderWidth": 0
+ },
+ "stack": "",
+ "areaStyle": {
+ "normal": true
+ }
+ }
+ ],
+ "domainAxisItemName": "Build",
+ "integerRangeAxis": false,
+ "rangeMax": 100.0,
+ "rangeMin": 25.0
+}