+
+
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-checksAnnotationScope.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-checksAnnotationScope.html
new file mode 100644
index 000000000..737f1ec3f
--- /dev/null
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-checksAnnotationScope.html
@@ -0,0 +1,22 @@
+
+ Select the scope of source code annotations in SCM checks.
+
+ The following different scopes are supported:
+
+
+ - SKIP - Skip annotations
+ -
+ Do not publish any annotations, just report the coverage report summary.
+
+ - MODIFIED_LINES - Publish annotations for modified lines
+ -
+ Publish only annotations for lines that have been changed (with respect to the reference build).
+ Teams can use these annotations to improve the quality of pull or merge requests.
+
+ - ALL_LINES - Publish annotations for all lines
+ -
+ Publish annotations for existing and new code. There might be a lot of annotations depending on
+ your code coverage.
+
+
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-checksName.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-checksName.html
new file mode 100644
index 000000000..b1d1ace7d
--- /dev/null
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-checksName.html
@@ -0,0 +1,4 @@
+
+If provided, and publishing checks enabled, the plugin will use this name when publishing results to corresponding
+SCM hosting platforms. If not, the default name will be used.
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-checksAnnotationScope.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-checksAnnotationScope.html
new file mode 100644
index 000000000..737f1ec3f
--- /dev/null
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-checksAnnotationScope.html
@@ -0,0 +1,22 @@
+
+ Select the scope of source code annotations in SCM checks.
+
+ The following different scopes are supported:
+
+
+ - SKIP - Skip annotations
+ -
+ Do not publish any annotations, just report the coverage report summary.
+
+ - MODIFIED_LINES - Publish annotations for modified lines
+ -
+ Publish only annotations for lines that have been changed (with respect to the reference build).
+ Teams can use these annotations to improve the quality of pull or merge requests.
+
+ - ALL_LINES - Publish annotations for all lines
+ -
+ Publish annotations for existing and new code. There might be a lot of annotations depending on
+ your code coverage.
+
+
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-checksName.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-checksName.html
new file mode 100644
index 000000000..b1d1ace7d
--- /dev/null
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-checksName.html
@@ -0,0 +1,4 @@
+
+If provided, and publishing checks enabled, the plugin will use this name when publishing results to corresponding
+SCM hosting platforms. If not, the default name will be used.
+
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 3de61eea9..e81b3929d 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
@@ -17,7 +17,7 @@
-
+
@@ -33,9 +33,9 @@
File Coverage
-
+
- Change Coverage
+ Modified Lines Coverage
@@ -72,10 +72,10 @@
-
+
-
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties
index 83dd1df40..68f0622c7 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties
@@ -32,3 +32,14 @@ Column.Complexity=Complexity
Column.ComplexityDensity=Complexity / LOC
MessagesViewModel.Title=Code Coverage
+
+Checks.Summary=Coverage Report Overview
+Checks.QualityGates=Quality Gates Summary - {0}
+Checks.ProjectOverview=Project Coverage Summary
+Checks.Annotation.Title=Missing Coverage
+Checks.Annotation.Message.SingleLine=Changed line #L{0} is not covered by tests
+Checks.Annotation.Message.MultiLine=Changed lines #L{0} - L{1} are not covered by tests
+
+ChecksAnnotationScope.Skip=Skip annotations
+ChecksAnnotationScope.ModifiedLines=Publish annotations for modified lines
+ChecksAnnotationScope.AllLines=Publish annotations for all lines
diff --git a/plugin/src/main/webapp/js/view-model.js b/plugin/src/main/webapp/js/view-model.js
index 384219d5b..fe4300622 100644
--- a/plugin/src/main/webapp/js/view-model.js
+++ b/plugin/src/main/webapp/js/view-model.js
@@ -470,6 +470,14 @@ const CoverageChartGenerator = function ($) {
initializeSourceCodeSelection('absolute-coverage');
initializeSourceCodeSelection('change-coverage');
initializeSourceCodeSelection('indirect-coverage');
+
+ $('input[name="changed"]').on('change', function () {
+ const showChanged = $(this).prop('checked');
+ $('table.data-table').each(function () {
+ const table = $(this).DataTable();
+ table.column(1).search(showChanged ? 'true' : '').draw();
+ });
+ });
});
}
};
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/TreeMapNodeConverterTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/TreeMapNodeConverterTest.java
index ab4432c06..795ead83c 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/TreeMapNodeConverterTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/TreeMapNodeConverterTest.java
@@ -1,5 +1,8 @@
package io.jenkins.plugins.coverage.metrics.charts;
+import java.util.List;
+import java.util.stream.Collectors;
+
import org.junit.jupiter.api.Test;
import edu.hm.hafner.echarts.LabeledTreeMapNode;
@@ -11,6 +14,8 @@
import io.jenkins.plugins.coverage.metrics.color.ColorProviderFactory;
import io.jenkins.plugins.coverage.metrics.color.CoverageLevel;
+import static org.assertj.core.api.Assertions.*;
+
/**
* Tests the class {@link TreeMapNodeConverter}.
*
@@ -24,44 +29,44 @@ class TreeMapNodeConverterTest extends AbstractCoverageTest {
void shouldConvertCodingStyleToTree() {
Node tree = readJacocoResult(JACOCO_CODING_STYLE_FILE);
- final double totalLines = JACOCO_CODING_STYLE_TOTAL;
- final double coveredLines = JACOCO_CODING_STYLE_COVERED;
- final double coveredPercentage = coveredLines / totalLines * 100.0;
-
-// LabeledTreeMapNode root = new TreeMapNodeConverter().toTreeChartModel(tree, Metric.LINE, COLOR_PROVIDER);
-// assertThat(root.getName()).isEqualTo("Java coding style");
-// assertThat(root.getValue()).containsExactly(totalLines, coveredLines);
-// assertThat(root.getItemStyle().getColor()).isEqualTo(getNodeColorAsRGBHex(coveredPercentage));
-//
-// assertThat(root.getChildren()).hasSize(1).element(0).satisfies(
-// node -> {
-// assertThat(node.getName()).isEqualTo("edu.hm.hafner.util");
-// assertThat(node.getValue()).containsExactly(totalLines, coveredLines);
-// assertThat(root.getItemStyle().getColor()).isEqualTo(getNodeColorAsRGBHex(coveredPercentage));
-// }
-// );
+ LabeledTreeMapNode root = new TreeMapNodeConverter().toTreeChartModel(tree, Metric.LINE, COLOR_PROVIDER);
+ assertThat(root.getName()).isEqualTo("Java coding style");
+
+ var overallCoverage = String.valueOf(JACOCO_CODING_STYLE_TOTAL);
+ assertThat(root.getValue()).contains(overallCoverage);
+
+ var overallCoveragePercentage = 100.0 * JACOCO_CODING_STYLE_COVERED / JACOCO_CODING_STYLE_TOTAL;
+ assertThat(root.getItemStyle().getColor()).isEqualTo(getNodeColorAsRGBHex(overallCoveragePercentage));
+
+ assertThat(root.getChildren()).hasSize(1).element(0).satisfies(
+ node -> {
+ assertThat(node.getName()).isEqualTo("edu.hm.hafner.util");
+ assertThat(node.getValue()).contains(overallCoverage);
+ assertThat(root.getItemStyle().getColor()).isEqualTo(getNodeColorAsRGBHex(overallCoveragePercentage));
+ }
+ );
}
@Test
- void shouldConvertAnalysisModelToTree() {
+ void shouldReadBranchCoverage() {
Node tree = readJacocoResult(JACOCO_ANALYSIS_MODEL_FILE);
- LabeledTreeMapNode root = new TreeMapNodeConverter().toTreeChartModel(tree, Metric.LINE, COLOR_PROVIDER);
+ LabeledTreeMapNode root = new TreeMapNodeConverter().toTreeChartModel(tree, Metric.BRANCH, COLOR_PROVIDER);
+
+ var nodes = aggregateChildren(root);
+ nodes.stream().filter(node -> node.getName().endsWith(".java")).forEach(node -> {
+ assertThat(node.getValue()).hasSize(2);
+ });
+ }
- double totalLines = JACOCO_ANALYSIS_MODEL_TOTAL;
- double coveredLines = JACOCO_ANALYSIS_MODEL_COVERED;
- double coveredPercentage = coveredLines / totalLines * 100.0;
-
-// assertThat(root.getName()).isEqualTo("Static Analysis Model and Parsers");
-// assertThat(root.getValue()).containsExactly(totalLines, coveredLines);
-// assertThat(root.getItemStyle().getColor()).isEqualTo(getNodeColorAsRGBHex(coveredPercentage));
-// assertThat(root.getChildren()).hasSize(1).element(0).satisfies(
-// node -> {
-// assertThat(node.getName()).isEqualTo("edu.hm.hafner");
-// assertThat(node.getValue()).containsExactly(totalLines, coveredLines);
-// assertThat(node.getItemStyle().getColor()).isEqualTo(getNodeColorAsRGBHex(coveredPercentage));
-// }
-// );
+ private List aggregateChildren(final LabeledTreeMapNode root) {
+ var children = root.getChildren();
+ var subChildren = children.stream()
+ .map(this::aggregateChildren)
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
+ subChildren.addAll(children);
+ return subChildren;
}
@Override
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java
index df28e8fdb..200e2ce53 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java
@@ -21,19 +21,20 @@
*/
class SourceCodeFacadeTest extends ResourceTest {
private static final String WHOLE_SOURCE_CODE = "SourcecodeTest.html";
- private static final String CHANGE_COVERAGE_SOURCE_CODE = "SourcecodeTestCC.html";
+ private static final String MODIFIED_LINES_COVERAGE_SOURCE_CODE = "SourcecodeTestCC.html";
private static final String INDIRECT_COVERAGE_SOURCE_CODE = "SourcecodeTestICC.html";
@Test
- void shouldCalculateSourcecodeForChangeCoverage() throws IOException {
+ void shouldCalculateSourcecodeForModifiedLinesCoverage() throws IOException {
SourceCodeFacade sourceCodeFacade = createSourceCodeFacade();
String originalHtml = readHtml(WHOLE_SOURCE_CODE);
FileNode node = createFileCoverageNode();
- String requiredHtml = Jsoup.parse(readHtml(CHANGE_COVERAGE_SOURCE_CODE), Parser.xmlParser()).html();
+ String requiredHtml = Jsoup.parse(readHtml(MODIFIED_LINES_COVERAGE_SOURCE_CODE), Parser.xmlParser()).html();
- String changeCoverageHtml = sourceCodeFacade.calculateChangeCoverageSourceCode(originalHtml, node);
- assertThat(changeCoverageHtml).isEqualTo(requiredHtml);
+ String modifiedLinesCoverageHtml =
+ sourceCodeFacade.calculateModifiedLinesCoverageSourceCode(originalHtml, node);
+ assertThat(modifiedLinesCoverageHtml).isEqualTo(requiredHtml);
}
@Test
@@ -44,8 +45,8 @@ void shouldCalculateSourcecodeForIndirectCoverageChanges() throws IOException {
String requiredHtml = Jsoup.parse(readHtml(INDIRECT_COVERAGE_SOURCE_CODE), Parser.xmlParser()).html();
- String changeCoverageHtml = sourceCodeFacade.calculateIndirectCoverageChangesSourceCode(originalHtml, node);
- assertThat(changeCoverageHtml).isEqualTo(requiredHtml);
+ String modifiedLinesCoverageHtml = sourceCodeFacade.calculateIndirectCoverageChangesSourceCode(originalHtml, node);
+ assertThat(modifiedLinesCoverageHtml).isEqualTo(requiredHtml);
}
/**
@@ -61,7 +62,7 @@ private FileNode createFileCoverageNode() {
FileNode file = new FileNode("");
List lines = Arrays.asList(10, 11, 12, 16, 17, 18, 19);
for (Integer line : lines) {
- file.addModifiedLine(line);
+ file.addModifiedLines(line);
}
file.addIndirectCoverageChange(6, -1);
file.addIndirectCoverageChange(7, -1);
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java
index 202ed0f1a..b23c61dda 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java
@@ -50,7 +50,7 @@ void shouldNotLoadResultIfCoverageValuesArePersistedInAction() {
var coverages = List.of(percent50, percent80);
var action = spy(new CoverageBuildAction(mock(FreeStyleBuild.class), CoverageRecorder.DEFAULT_ID,
StringUtils.EMPTY, StringUtils.EMPTY, module, new QualityGateResult(),
- createLog(), "-", deltas, coverages, deltas, coverages, false));
+ createLog(), "-", deltas, coverages, deltas, coverages, deltas, coverages, false));
when(action.getResult()).thenThrow(new IllegalStateException("Result should not be accessed with getResult() when getting a coverage metric that is persisted in the build"));
@@ -60,6 +60,8 @@ StringUtils.EMPTY, StringUtils.EMPTY, module, new QualityGateResult(),
assertThat(action.getStatistics().getValue(Baseline.PROJECT, Metric.LINE)).hasValue(percent80);
assertThat(action.getStatistics().getValue(Baseline.MODIFIED_LINES, Metric.BRANCH)).hasValue(percent50);
assertThat(action.getStatistics().getValue(Baseline.MODIFIED_LINES, Metric.LINE)).hasValue(percent80);
+ assertThat(action.getStatistics().getValue(Baseline.MODIFIED_FILES, Metric.BRANCH)).hasValue(percent50);
+ assertThat(action.getStatistics().getValue(Baseline.MODIFIED_FILES, Metric.LINE)).hasValue(percent80);
assertThat(action.getStatistics().getValue(Baseline.PROJECT_DELTA, Metric.LINE))
.hasValue(new FractionValue(Metric.LINE, lineDelta));
assertThat(action.getStatistics().getValue(Baseline.PROJECT_DELTA, Metric.BRANCH))
@@ -71,7 +73,7 @@ StringUtils.EMPTY, StringUtils.EMPTY, module, new QualityGateResult(),
private static CoverageBuildAction createEmptyAction(final Node module) {
return new CoverageBuildAction(mock(FreeStyleBuild.class), CoverageRecorder.DEFAULT_ID,
StringUtils.EMPTY, StringUtils.EMPTY, module, new QualityGateResult(), createLog(), "-",
- new TreeMap<>(), List.of(), new TreeMap<>(), List.of(), false);
+ new TreeMap<>(), List.of(), new TreeMap<>(), List.of(), new TreeMap<>(), List.of(), false);
}
private static FilteredLog createLog() {
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisherTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisherTest.java
new file mode 100644
index 000000000..20d5b419d
--- /dev/null
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisherTest.java
@@ -0,0 +1,133 @@
+package io.jenkins.plugins.coverage.metrics.steps;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.Fraction;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junitpioneer.jupiter.DefaultLocale;
+
+import edu.hm.hafner.metric.Coverage.CoverageBuilder;
+import edu.hm.hafner.metric.Metric;
+
+import hudson.model.Run;
+
+import io.jenkins.plugins.checks.api.ChecksAnnotation.ChecksAnnotationLevel;
+import io.jenkins.plugins.checks.api.ChecksConclusion;
+import io.jenkins.plugins.checks.api.ChecksDetails;
+import io.jenkins.plugins.checks.api.ChecksOutput;
+import io.jenkins.plugins.checks.api.ChecksStatus;
+import io.jenkins.plugins.coverage.metrics.AbstractCoverageTest;
+import io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder.ChecksAnnotationScope;
+import io.jenkins.plugins.util.JenkinsFacade;
+import io.jenkins.plugins.util.QualityGateResult;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@DefaultLocale("en")
+class CoverageChecksPublisherTest extends AbstractCoverageTest {
+ private static final String JENKINS_BASE_URL = "http://127.0.0.1:8080";
+ private static final String BUILD_LINK = "job/pipeline-coding-style/job/5";
+ private static final String COVERAGE_ID = "coverage";
+ private static final String REPORT_NAME = "Name";
+
+ @ParameterizedTest(name = "should create checks (scope = {0}, expected annotations = {1})")
+ @CsvSource({"SKIP, 0", "ALL_LINES, 36", "MODIFIED_LINES, 3"})
+ void shouldCreateChecksReport(final ChecksAnnotationScope scope, final int expectedAnnotations) {
+ var publisher = new CoverageChecksPublisher(createCoverageBuildAction(), REPORT_NAME, scope, createJenkins());
+
+ var checkDetails = publisher.extractChecksDetails();
+
+ assertThat(checkDetails.getName()).isPresent().get().isEqualTo(REPORT_NAME);
+ assertThat(checkDetails.getStatus()).isEqualTo(ChecksStatus.COMPLETED);
+ assertThat(checkDetails.getConclusion()).isEqualTo(ChecksConclusion.SUCCESS);
+ assertThat(checkDetails.getDetailsURL()).isPresent()
+ .get()
+ .isEqualTo("http://127.0.0.1:8080/job/pipeline-coding-style/job/5/coverage");
+ assertThatDetailsAreCorrect(checkDetails, expectedAnnotations);
+ }
+
+ private void assertThatDetailsAreCorrect(final ChecksDetails checkDetails, final int expectedAnnotations) {
+ assertThat(checkDetails.getOutput()).isPresent().get().satisfies(output -> {
+ assertThat(output.getTitle()).isPresent()
+ .get()
+ .isEqualTo("Modified code lines: 50.00% (1/2)");
+ assertThat(output.getText()).isEmpty();
+ assertChecksAnnotations(output, expectedAnnotations);
+ assertSummary(output);
+ });
+ }
+
+ private void assertSummary(final ChecksOutput checksOutput) throws IOException {
+ var expectedContent = Files.readString(getResourceAsFile("coverage-publisher-summary.md"));
+ assertThat(checksOutput.getSummary()).isPresent()
+ .get()
+ .isEqualTo(expectedContent);
+ }
+
+ private void assertChecksAnnotations(final ChecksOutput checksOutput, final int expectedAnnotations) {
+ if (expectedAnnotations == 3) {
+ assertThat(checksOutput.getChecksAnnotations()).hasSize(expectedAnnotations).satisfiesExactly(
+ annotation -> {
+ assertThat(annotation.getTitle()).contains("Not covered line");
+ assertThat(annotation.getAnnotationLevel()).isEqualTo(ChecksAnnotationLevel.WARNING);
+ assertThat(annotation.getPath()).contains("edu/hm/hafner/util/TreeStringBuilder.java");
+ assertThat(annotation.getMessage()).contains("Line 61 is not covered by tests");
+ assertThat(annotation.getStartLine()).isPresent().get().isEqualTo(61);
+ },
+ annotation -> {
+ assertThat(annotation.getTitle()).contains("Not covered line");
+ assertThat(annotation.getAnnotationLevel()).isEqualTo(ChecksAnnotationLevel.WARNING);
+ assertThat(annotation.getPath()).contains("edu/hm/hafner/util/TreeStringBuilder.java");
+ assertThat(annotation.getMessage()).contains("Line 62 is not covered by tests");
+ assertThat(annotation.getStartLine()).isPresent().get().isEqualTo(62);
+ },
+ annotation -> {
+ assertThat(annotation.getTitle()).contains("Partially covered line");
+ assertThat(annotation.getAnnotationLevel()).isEqualTo(ChecksAnnotationLevel.WARNING);
+ assertThat(annotation.getPath()).contains("edu/hm/hafner/util/TreeStringBuilder.java");
+ assertThat(annotation.getMessage()).contains("Line 113 is only partially covered, one branch is missing");
+ assertThat(annotation.getStartLine()).isPresent().get().isEqualTo(113);
+ });
+ }
+ else {
+ assertThat(checksOutput.getChecksAnnotations()).hasSize(expectedAnnotations);
+ }
+ }
+
+ private JenkinsFacade createJenkins() {
+ JenkinsFacade jenkinsFacade = mock(JenkinsFacade.class);
+ when(jenkinsFacade.getAbsoluteUrl(BUILD_LINK, COVERAGE_ID)).thenReturn(
+ JENKINS_BASE_URL + "/" + BUILD_LINK + "/" + COVERAGE_ID);
+ return jenkinsFacade;
+ }
+
+ private CoverageBuildAction createCoverageBuildAction() {
+ var testCoverage = new CoverageBuilder().setMetric(Metric.LINE)
+ .setCovered(1)
+ .setMissed(1)
+ .build();
+
+ var run = mock(Run.class);
+ when(run.getUrl()).thenReturn(BUILD_LINK);
+ var result = readJacocoResult("jacoco-codingstyle.xml");
+ result.findFile("TreeStringBuilder.java")
+ .ifPresent(file -> {
+ assertThat(file.getMissedLines()).contains(61, 62);
+ assertThat(file.getPartiallyCoveredLines()).contains(entry(113, 1));
+ file.addModifiedLines(61, 62, 113);
+ });
+
+ return new CoverageBuildAction(run, COVERAGE_ID, REPORT_NAME, StringUtils.EMPTY, result,
+ new QualityGateResult(), null, "refId",
+ new TreeMap<>(Map.of(Metric.LINE, Fraction.ONE_HALF, Metric.MODULE, Fraction.ONE_FIFTH)),
+ List.of(testCoverage), new TreeMap<>(Map.of(Metric.LINE, Fraction.ONE_HALF)), List.of(testCoverage),
+ new TreeMap<>(Map.of(Metric.LINE, Fraction.ONE_HALF)), List.of(testCoverage), false);
+ }
+}
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java
index 123534ad3..0b0b5b29c 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java
@@ -104,11 +104,19 @@ void shouldProvideSelectedColumn() {
column.setBaseline(Baseline.MODIFIED_LINES);
assertThat(column.getBaseline()).isEqualTo(Baseline.MODIFIED_LINES);
- assertThat(column.getRelativeCoverageUrl(job)).isEqualTo("coverage/#changeCoverage");
+ assertThat(column.getRelativeCoverageUrl(job)).isEqualTo("coverage/#modifiedLinesCoverage");
column.setBaseline(Baseline.MODIFIED_LINES_DELTA);
assertThat(column.getBaseline()).isEqualTo(Baseline.MODIFIED_LINES_DELTA);
- assertThat(column.getRelativeCoverageUrl(job)).isEqualTo("coverage/#changeCoverage");
+ assertThat(column.getRelativeCoverageUrl(job)).isEqualTo("coverage/#modifiedLinesCoverage");
+
+ column.setBaseline(Baseline.MODIFIED_FILES);
+ assertThat(column.getBaseline()).isEqualTo(Baseline.MODIFIED_FILES);
+ assertThat(column.getRelativeCoverageUrl(job)).isEqualTo("coverage/#modifiedFilesCoverage");
+
+ column.setBaseline(Baseline.MODIFIED_FILES_DELTA);
+ assertThat(column.getBaseline()).isEqualTo(Baseline.MODIFIED_FILES_DELTA);
+ assertThat(column.getRelativeCoverageUrl(job)).isEqualTo("coverage/#modifiedFilesCoverage");
column.setBaseline(Baseline.INDIRECT);
assertThat(column.getBaseline()).isEqualTo(Baseline.INDIRECT);
@@ -219,7 +227,7 @@ private CoverageMetricColumn createColumn() {
CoverageBuildAction coverageBuildAction =
new CoverageBuildAction(run, "coverage", "Code Coverage", StringUtils.EMPTY,
node, new QualityGateResult(), new FilteredLog("Test"),
- "-", delta, List.of(), new TreeMap<>(), List.of(), false);
+ "-", delta, List.of(), new TreeMap<>(), List.of(), new TreeMap<>(), List.of(), false);
when(run.getAction(CoverageBuildAction.class)).thenReturn(coverageBuildAction);
when(run.getActions(CoverageBuildAction.class)).thenReturn(Collections.singletonList(coverageBuildAction));
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java
index 283ed1e46..e19c19951 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java
@@ -35,7 +35,7 @@ void shouldReturnEmptySourceViewForExistingLinkButMissingSourceFile() {
String hash = String.valueOf("PathUtil.java".hashCode());
assertThat(model.getSourceCode(hash, ABSOLUTE_COVERAGE_TABLE_ID)).isEqualTo("n/a");
- assertThat(model.getSourceCode(hash, CHANGE_COVERAGE_TABLE_ID)).isEqualTo("n/a");
+ assertThat(model.getSourceCode(hash, MODIFIED_LINES_COVERAGE_TABLE_ID)).isEqualTo("n/a");
assertThat(model.getSourceCode(hash, INDIRECT_COVERAGE_TABLE_ID)).isEqualTo("n/a");
}
@@ -92,7 +92,7 @@ private Node createIndirectCoverageChangesNode() {
@Test
void shouldProvideRightTableModelById() {
CoverageViewModel model = createModelFromCodingStyleReport();
- assertThat(model.getTableModel(CHANGE_COVERAGE_TABLE_ID)).isInstanceOf(ChangeCoverageTableModel.class);
+ assertThat(model.getTableModel(MODIFIED_LINES_COVERAGE_TABLE_ID)).isInstanceOf(ModifiedLinesCoverageTableModel.class);
assertThat(model.getTableModel(INDIRECT_COVERAGE_TABLE_ID)).isInstanceOf(IndirectCoverageChangesTable.class);
assertThat(model.getTableModel(ABSOLUTE_COVERAGE_TABLE_ID)).isInstanceOf(CoverageTableModel.class);
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java
index 57978a501..accd11557 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java
@@ -230,7 +230,7 @@ CoverageBuildAction createAction() {
return new CoverageBuildAction(mock(FreeStyleBuild.class), CoverageRecorder.DEFAULT_ID, StringUtils.EMPTY,
StringUtils.EMPTY,
tree, new QualityGateResult(), new FilteredLog("Test"), "-",
- new TreeMap<>(), List.of(),
+ new TreeMap<>(), List.of(), new TreeMap<>(), List.of(),
new TreeMap<>(), List.of(), false);
}
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java
index a18b81f6f..c95573f00 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java
@@ -115,19 +115,19 @@ private void verifyDeltaComputation(final Run, ?> firstBuild, final Run, ?>
assertThat(action.formatDelta(Baseline.PROJECT, LOC)).isEqualTo(String.valueOf(-JACOCO_ANALYSIS_MODEL_TOTAL));
assertThat(action.formatDelta(Baseline.PROJECT, COMPLEXITY)).isEqualTo(String.valueOf(160 - 2718));
- verifyChangeCoverage(action);
+ verifyModifiedLinesCoverage(action);
}
/**
- * Verifies the calculated change coverage including the change coverage delta and the code delta. This makes sure
+ * Verifies the calculated modified lines coverage including the modified lines coverage delta and the code delta. This makes sure
* these metrics are set properly even if there are no code changes.
*
* @param action
* The created Jenkins action
*/
- private void verifyChangeCoverage(final CoverageBuildAction action) {
+ private void verifyModifiedLinesCoverage(final CoverageBuildAction action) {
Node root = action.getResult();
assertThat(root).isNotNull();
- assertThat(root.getAllFileNodes()).flatExtracting(FileNode::getChangedLines).isEmpty();
+ assertThat(root.getAllFileNodes()).flatExtracting(FileNode::getModifiedLines).isEmpty();
}
}
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java
index c74c9641c..f6688e30e 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java
@@ -86,13 +86,13 @@ void shouldAttachChangesCodeLines() {
assertThat(tree.findByHashCode(Metric.FILE, TEST_FILE_1_PATH.hashCode()))
.isNotEmpty()
.satisfies(node -> assertThat(node.get())
- .isInstanceOfSatisfying(FileNode.class, f -> assertThat(f.getChangedLines())
+ .isInstanceOfSatisfying(FileNode.class, f -> assertThat(f.getModifiedLines())
.containsExactly(
5, 6, 7, 8, 9, 14, 15, 16, 17, 18, 20, 21, 22, 33, 34, 35, 36)));
assertThat(tree.findByHashCode(Metric.FILE, TEST_FILE_2.hashCode()))
.isNotEmpty()
.satisfies(node -> assertThat(node.get())
- .isInstanceOfSatisfying(FileNode.class, f -> assertThat(f.getChangedLines())
+ .isInstanceOfSatisfying(FileNode.class, f -> assertThat(f.getModifiedLines())
.isEmpty()));
}
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java
index 2c27c2acb..c24ad30ad 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java
@@ -154,7 +154,7 @@ private void verifyGitIntegration(final Run, ?> build, final Run, ?> referen
*/
private void verifyCoverage(final CoverageBuildAction action) {
verifyOverallCoverage(action);
- verifyChangeCoverage(action);
+ verifyModifiedLinesCoverage(action);
verifyIndirectCoverageChanges(action);
}
@@ -172,12 +172,12 @@ private void verifyOverallCoverage(final CoverageBuildAction action) {
}
/**
- * Verifies the calculated change coverage including the change coverage delta.
+ * Verifies the calculated modified lines coverage including the modified lines coverage delta.
*
* @param action
* The created Jenkins action
*/
- private void verifyChangeCoverage(final CoverageBuildAction action) {
+ private void verifyModifiedLinesCoverage(final CoverageBuildAction action) {
var builder = new CoverageBuilder();
assertThat(action.getAllValues(Baseline.MODIFIED_LINES)).contains(
builder.setMetric(LINE).setCovered(1).setMissed(1).build());
@@ -206,14 +206,14 @@ private void verifyCodeDelta(final CoverageBuildAction action) {
edu.hm.hafner.metric.Node root = action.getResult();
assertThat(root).isNotNull();
- List changedFiles = root.getAllFileNodes().stream()
- .filter(FileNode::hasChangedLines)
+ List modifiedFiles = root.getAllFileNodes().stream()
+ .filter(FileNode::hasModifiedLines)
.collect(Collectors.toList());
- assertThat(changedFiles).hasSize(4);
- assertThat(changedFiles).extracting(FileNode::getName)
+ assertThat(modifiedFiles).hasSize(4);
+ assertThat(modifiedFiles).extracting(FileNode::getName)
.containsExactlyInAnyOrder("MinerFactory.java", "RepositoryMinerStep.java",
"SimpleReferenceRecorder.java", "CommitDecoratorFactory.java");
- assertThat(changedFiles).flatExtracting(FileNode::getChangedLines)
+ assertThat(modifiedFiles).flatExtracting(FileNode::getModifiedLines)
.containsExactlyInAnyOrder(15, 17, 63, 68, 80, 90, 130);
}
diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.md b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.md
new file mode 100644
index 000000000..09f7a2f97
--- /dev/null
+++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.md
@@ -0,0 +1,32 @@
+## Coverage Report Overview
+
+* **[Overall project (difference to reference job)](http://127.0.0.1:8080/job/pipeline-coding-style/job/5/coverage#overview)**
+ * Line Coverage: 91.02% (294/323) / +50.00%
+ * Branch Coverage: 93.97% (109/116) / n/a
+ * Complexity Density: +49.54%
+ * Lines of Code: 323
+* **[Modified files (difference to overall project)](http://127.0.0.1:8080/job/pipeline-coding-style/job/5/coverage#modifiedFilesCoverage)**
+ * Line Coverage: 50.00% (1/2) / +50.00%
+ * Branch Coverage: n/a / n/a
+ * Complexity Density: +43.40%
+ * Lines of Code: 53
+* **[Modified code lines (difference to overall project)](http://127.0.0.1:8080/job/pipeline-coding-style/job/5/coverage#modifiedLinesCoverage)**
+ * Line Coverage: 50.00% (1/2) / +50.00%
+ * Branch Coverage: n/a / n/a
+ * Lines of Code: 3
+* **[Indirect changes](http://127.0.0.1:8080/job/pipeline-coding-style/job/5/coverage#indirectCoverage)**
+ * Line Coverage: 50.00% (1/2) / n/a
+ * Branch Coverage: n/a / n/a
+ * Lines of Code: n/a
+
+
+## Quality Gates Summary - INACTIVE
+
+
+
+## Project Coverage Summary
+
+|Container Coverage|Module Coverage|Package Coverage|File Coverage|Class Coverage|Method Coverage|Line Coverage|Branch Coverage|Instruction Coverage|
+|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
+|:white_check_mark: **Overall project**|100.00% (1/1)|100.00% (4/4)|70.00% (7/10)|83.33% (15/18)|95.10% (97/102)|91.02% (294/323)|93.97% (109/116)|93.33% (1260/1350)|
+|:chart_with_upwards_trend: **Overall project (difference to reference job)**|-|+20.00% :arrow_up:|-|-|-|-|+50.00% :arrow_up:|-|-|