diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/model/ElementFormatter.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/model/ElementFormatter.java index db50e1f85..7c2d77b07 100644 --- a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/model/ElementFormatter.java +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/model/ElementFormatter.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; -import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -15,7 +14,6 @@ import edu.hm.hafner.coverage.FractionValue; import edu.hm.hafner.coverage.IntegerValue; import edu.hm.hafner.coverage.Metric; -import edu.hm.hafner.coverage.Node; import edu.hm.hafner.coverage.Percentage; import edu.hm.hafner.coverage.Value; @@ -417,23 +415,6 @@ public List getFormattedValues(final Stream values, fin return values.map(value -> formatDetails(value, locale)).collect(Collectors.toList()); } - /** - * Returns a stream of {@link Coverage} values for the given root node sorted by the metric ordinal. - * - * @param coverage - * The coverage root node - * - * @return a stream containing the existent coverage values - */ - public Stream getSortedCoverageValues(final Node coverage) { - return Metric.getCoverageMetrics() - .stream() - .map(m -> m.getValueFor(coverage)) - .flatMap(Optional::stream) - .filter(value -> value instanceof Coverage) - .map(Coverage.class::cast); - } - /** * Returns a localized human-readable label for the specified metric. * @@ -498,6 +479,8 @@ public String getDisplayName(final Baseline baseline) { return Messages.Baseline_MODIFIED_LINES_DELTA(); case MODIFIED_FILES_DELTA: return Messages.Baseline_MODIFIED_FILES_DELTA(); + case INDIRECT: + return Messages.Baseline_INDIRECT(); default: throw new NoSuchElementException("No display name found for baseline " + baseline); } diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildAction.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildAction.java index 96585e9bb..a2e920d54 100644 --- a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildAction.java +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildAction.java @@ -274,6 +274,9 @@ public Baseline getDeltaBaseline(final Baseline baseline) { if (baseline == Baseline.MODIFIED_FILES) { return Baseline.MODIFIED_FILES_DELTA; } + if (baseline == Baseline.INDIRECT) { + return Baseline.INDIRECT; + } throw new NoSuchElementException("No delta baseline for this baseline: " + baseline); } diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisher.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisher.java index 19bc2ea19..faa3fefbe 100644 --- a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisher.java +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisher.java @@ -4,25 +4,24 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.NavigableMap; +import java.util.Map; +import java.util.Map.Entry; import java.util.NavigableSet; import java.util.Optional; import java.util.Set; -import java.util.TreeMap; import java.util.TreeSet; +import java.util.stream.Collector; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.math.Fraction; -import edu.hm.hafner.coverage.Coverage; import edu.hm.hafner.coverage.FileNode; import edu.hm.hafner.coverage.Metric; import edu.hm.hafner.coverage.Node; import edu.hm.hafner.coverage.Value; import edu.hm.hafner.util.VisibleForTesting; -import hudson.Functions; import hudson.model.TaskListener; import io.jenkins.plugins.checks.api.ChecksAnnotation; @@ -48,6 +47,9 @@ @SuppressWarnings("PMD.GodClass") class CoverageChecksPublisher { private static final ElementFormatter FORMATTER = new ElementFormatter(); + private static final int TITLE_HEADER_LEVEL = 4; + private static final char NEW_LINE = '\n'; + private static final String COLUMN = "|"; private final CoverageBuildAction action; private final Node rootNode; @@ -86,6 +88,7 @@ ChecksDetails extractChecksDetails() { var output = new ChecksOutputBuilder() .withTitle(getChecksTitle()) .withSummary(getSummary()) + .withText(getProjectMetricsSummary()) .withAnnotations(getAnnotations()) .build(); @@ -137,9 +140,96 @@ private NavigableSet getMetricsForTitle() { } private String getSummary() { - return getOverallCoverageSummary() + "\n\n" - + getQualityGatesSummary() + "\n\n" - + getProjectMetricsSummary(rootNode); + return getAnnotationSummary() + + getOverallCoverageSummary() + + getQualityGatesSummary(); + } + + private String getAnnotationSummary() { + if (rootNode.hasModifiedLines()) { + var filteredRoot = rootNode.filterByModifiedLines(); + var modifiedFiles = filteredRoot.getAllFileNodes(); + + var summary = new StringBuilder("Modified lines summary:\n"); + + createTotalLinesSummary(modifiedFiles, summary); + createLineCoverageSummary(modifiedFiles, summary); + createBranchCoverageSummary(filteredRoot, modifiedFiles, summary); + createMutationCoverageSummary(filteredRoot, modifiedFiles, summary); + + return summary.toString(); + } + return StringUtils.EMPTY; + } + + private void createTotalLinesSummary(final List modifiedFiles, final StringBuilder summary) { + var total = modifiedFiles.stream().map(FileNode::getModifiedLines).map(Set::size).count(); + if (total == 1) { + summary.append("- 1 line has been modified"); + } + else { + summary.append(String.format("- %d lines have been modified", total)); + } + summary.append(NEW_LINE); + } + + private void createLineCoverageSummary(final List modifiedFiles, final StringBuilder summary) { + var missed = modifiedFiles.stream().map(FileNode::getMissedLines).map(Set::size).count(); + if (missed == 0) { + summary.append("- all lines are covered"); + } + else if (missed == 1) { + summary.append("- 1 line is not covered"); + } + else { + summary.append(String.format("- %d lines are not covered", missed)); + } + summary.append(NEW_LINE); + } + + private void createBranchCoverageSummary(final Node filteredRoot, final List modifiedFiles, + final StringBuilder summary) { + if (filteredRoot.containsMetric(Metric.BRANCH)) { + var partiallyCovered = modifiedFiles.stream() + .map(FileNode::getPartiallyCoveredLines) + .map(Map::size) + .count(); + if (partiallyCovered == 1) { + summary.append("- 1 line is covered only partially"); + } + else { + summary.append(String.format("- %d lines are covered only partially", partiallyCovered)); + } + summary.append(NEW_LINE); + } + } + + private void createMutationCoverageSummary(final Node filteredRoot, final List modifiedFiles, + final StringBuilder summary) { + if (filteredRoot.containsMetric(Metric.MUTATION)) { + var survived = modifiedFiles.stream() + .map(FileNode::getSurvivedMutations) + .map(Map::entrySet) + .flatMap(Collection::stream) + .map(Entry::getValue) + .count(); + var mutations = modifiedFiles.stream().map(FileNode::getMutations).mapToLong(Collection::size).sum(); + if (survived == 0) { + if (mutations == 1) { + summary.append("- 1 mutation has been killed"); + } + else { + summary.append(String.format("- all %d mutations have been killed", mutations)); + } + } + if (survived == 1) { + summary.append(String.format("- 1 mutation survived (of %d)", mutations)); + } + else { + summary.append(String.format("- %d mutations survived (of %d)", survived, mutations)); + } + summary.append(NEW_LINE); + } } private List getAnnotations() { @@ -228,7 +318,7 @@ private List getBaselines() { } private String getOverallCoverageSummary() { - StringBuilder description = new StringBuilder(getSectionHeader(2, Messages.Checks_Summary())); + StringBuilder description = new StringBuilder(getSectionHeader(TITLE_HEADER_LEVEL, "Overview by baseline")); for (Baseline baseline : getBaselines()) { if (action.hasBaselineResult(baseline)) { @@ -240,10 +330,11 @@ private String getOverallCoverageSummary() { if (action.hasDelta(baseline, value.getMetric())) { display += String.format(" - Delta: %s", action.formatDelta(baseline, value.getMetric())); } - description.append(getBulletListItem(2, display)); + description.append(getBulletListItem(TITLE_HEADER_LEVEL, display)); } } } + description.append(NEW_LINE); return description.toString(); } @@ -252,38 +343,70 @@ private String getOverallCoverageSummary() { * * @return the markdown string representing the status summary */ - // TODO: expand with summary of status of each defined quality gate private String getQualityGatesSummary() { - return getSectionHeader(2, - Messages.Checks_QualityGates(action.getQualityGateResult().getOverallStatus().name())); - } - - private String getProjectMetricsSummary(final Node result) { - String sectionHeader = getSectionHeader(2, Messages.Checks_ProjectOverview()); + String summary = getSectionHeader(TITLE_HEADER_LEVEL, "Quality Gates Summary"); + var qualityGateResult = action.getQualityGateResult(); + if (qualityGateResult.isInactive()) { + return summary + "No active quality gates."; + } + return summary + + "Overall result: " + qualityGateResult.getOverallStatus().getDescription() + "\n" + + qualityGateResult.getMessages().stream() + .map(s -> s.replaceAll("-> ", "")) + .map(s -> s.replaceAll("[\\[\\]]", "")) + .collect(asSeparateLines()); + } + + private Collector asSeparateLines() { + return Collectors.joining("\n- ", "- ", "\n"); + } + + private String getProjectMetricsSummary() { + var builder = new StringBuilder(getSectionHeader(TITLE_HEADER_LEVEL, "Project coverage details")); + builder.append(COLUMN); + builder.append(COLUMN); + builder.append(getMetricStream() + .map(FORMATTER::getDisplayName) + .collect(asColumn())); + builder.append(COLUMN); + builder.append(":---:"); + builder.append(COLUMN); + builder.append(getMetricStream() + .map(i -> ":---:") + .collect(asColumn())); + for (Baseline baseline : action.getBaselines()) { + if (action.hasBaselineResult(baseline)) { + builder.append(String.format("%s **%s**|", Icon.FEET.markdown, + FORMATTER.getDisplayName(baseline))); + builder.append(getMetricStream() + .map(metric -> action.formatValue(baseline, metric)) + .collect(asColumn())); + + var deltaBaseline = action.getDeltaBaseline(baseline); + if (deltaBaseline != baseline) { + builder.append(String.format("%s **%s**|", Icon.CHART_UPWARDS_TREND.markdown, + FORMATTER.getDisplayName(deltaBaseline))); + builder.append(getMetricStream() + .map(metric -> getFormatDelta(baseline, metric)) + .collect(asColumn())); + } + } + } - List coverageDisplayNames = FORMATTER.getSortedCoverageDisplayNames(); - String header = formatRow(coverageDisplayNames); - String headerSeparator = formatRow( - getTableSeparators(ColumnAlignment.CENTER, coverageDisplayNames.size())); + return builder.toString(); + } - String projectCoverageName = String.format("|%s **%s**", Icon.WHITE_CHECK_MARK.markdown, - FORMATTER.getDisplayName(Baseline.PROJECT)); - List projectCoverage = FORMATTER.getFormattedValues(FORMATTER.getSortedCoverageValues(result), - Functions.getCurrentLocale()); - String projectCoverageRow = projectCoverageName + formatRow(projectCoverage); + private String getFormatDelta(final Baseline baseline, final Metric metric) { + var delta = action.formatDelta(baseline, metric); + return delta + getTrendIcon(delta); + } - String projectCoverageDeltaName = String.format("|%s **%s**", Icon.CHART_UPWARDS_TREND.markdown, - FORMATTER.getDisplayName(Baseline.PROJECT_DELTA)); - Collection projectCoverageDelta = formatCoverageDelta(Metric.getCoverageMetrics(), - action.getAllDeltas(Baseline.PROJECT_DELTA)); - String projectCoverageDeltaRow = - projectCoverageDeltaName + formatRow(projectCoverageDelta); + private Stream getMetricStream() { + return Metric.getCoverageMetrics().stream().skip(1); + } - return sectionHeader - + header - + headerSeparator - + projectCoverageRow - + projectCoverageDeltaRow; + private Collector asColumn() { + return Collectors.joining(COLUMN, "", "\n"); } private String formatText(final TextFormat format, final String text) { @@ -297,62 +420,21 @@ private String formatText(final TextFormat format, final String text) { } } - /** - * Formats the passed delta computation to a collection of its display representations, which is sorted by the - * metric ordinal. Also, a collection of required metrics is passed. This is used to fill not existent metrics which - * are required for the representation. Coverage deltas might not be existent if the reference does not contain a - * reference value of the metric. - * - * @param requiredMetrics - * The metrics which should be displayed - * @param deltas - * The delta calculation mapped by their metric - * @return the delta for each metric to be shown in the MD file - */ - private Collection formatCoverageDelta(final Collection requiredMetrics, - final NavigableMap deltas) { - var coverageDelta = new TreeMap(); - for (Metric metric : requiredMetrics) { - if (deltas.containsKey(metric)) { - var coverage = deltas.get(metric); - coverageDelta.putIfAbsent(metric, - FORMATTER.formatDelta(coverage, metric, Functions.getCurrentLocale()) - + getTrendIcon(coverage.doubleValue())); - } - else { - coverageDelta.putIfAbsent(metric, - FORMATTER.formatPercentage(Coverage.nullObject(metric), Functions.getCurrentLocale())); - } - } - return coverageDelta.values(); - } - - private String getTrendIcon(final double trend) { - if (trend > 0) { + private String getTrendIcon(final String trend) { + if (trend.startsWith("+")) { return " " + Icon.ARROW_UP.markdown; } - else if (trend < 0) { + else if (trend.startsWith("-")) { return " " + Icon.ARROW_DOWN.markdown; } - else { - return " " + Icon.ARROW_RIGHT.markdown; - } - } - - private List getTableSeparators(final ColumnAlignment alignment, final int count) { - switch (alignment) { - case LEFT: - return Collections.nCopies(count, ":---"); - case RIGHT: - return Collections.nCopies(count, "---:"); - case CENTER: - default: - return Collections.nCopies(count, ":---:"); + else if (trend.startsWith("n/a")) { + return StringUtils.EMPTY; } + return " " + Icon.ARROW_RIGHT.markdown; } private String getBulletListItem(final int level, final String text) { - int whitespaces = (level - 1) * 2; + int whitespaces = (level - 1) * TITLE_HEADER_LEVEL; return String.join("", Collections.nCopies(whitespaces, " ")) + "* " + text + "\n"; } @@ -360,18 +442,6 @@ private String getUrlText(final String text, final String url) { return String.format("[%s](%s)", text, url); } - private String formatRow(final Collection columns) { - StringBuilder row = new StringBuilder(); - for (Object column : columns) { - row.append(String.format("|%s", column)); - } - if (!columns.isEmpty()) { - row.append('|'); - } - row.append('\n'); - return row.toString(); - } - private String getSectionHeader(final int level, final String text) { return String.join("", Collections.nCopies(level, "#")) + " " + text + "\n\n"; } @@ -396,6 +466,7 @@ private enum ColumnAlignment { } private enum Icon { + FEET(":feet:"), WHITE_CHECK_MARK(":white_check_mark:"), CHART_UPWARDS_TREND(":chart_with_upwards_trend:"), ARROW_UP(":arrow_up:"), diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java index 659b72a92..adcfad6a1 100644 --- a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java @@ -487,10 +487,19 @@ public List getMetrics() { } private Stream sortCoverages() { - return ELEMENT_FORMATTER.getSortedCoverageValues(coverage) + return getSortedCoverageValues() .filter(c -> c.getTotal() > 1); // ignore elements that have a total of 1 } + private Stream getSortedCoverageValues() { + return Metric.getCoverageMetrics() + .stream() + .map(m -> m.getValueFor(coverage)) + .flatMap(Optional::stream) + .filter(value -> value instanceof Coverage) + .map(Coverage.class::cast); + } + public List getCovered() { return getCoverageCounter(Coverage::getCovered); } 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 68f0622c7..cb9351e53 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 @@ -33,8 +33,6 @@ 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 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 index 51e1d8180..9fa656e9d 100644 --- 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 @@ -1,7 +1,6 @@ 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; @@ -41,6 +40,24 @@ class CoverageChecksPublisherTest extends AbstractCoverageTest { private static final String REPORT_NAME = "Name"; private static final int ANNOTATIONS_COUNT_FOR_MODIFIED = 3; + @Test + void shouldShowQualityGateDetails() { + var result = readJacocoResult("jacoco-codingstyle.xml"); + + var publisher = new CoverageChecksPublisher(createActionWithoutDelta(result, + CoverageQualityGateEvaluatorTest.createQualityGateResult()), result, REPORT_NAME, + ChecksAnnotationScope.SKIP, createJenkins()); + + var checkDetails = publisher.extractChecksDetails(); + var expectedSummary = toString("coverage-publisher-quality-gate.checks-expected-result"); + assertThat(checkDetails.getOutput()).isPresent().get().satisfies(output -> { + assertThat(output.getSummary()).isPresent() + .get() + .asString() + .containsIgnoringWhitespaces(expectedSummary); + }); + } + @Test void shouldShowProjectBaselineForJaCoCo() { var result = readJacocoResult("jacoco-codingstyle.xml"); @@ -93,14 +110,15 @@ private void assertThatDetailsAreCorrect(final ChecksDetails checkDetails, final assertThat(output.getTitle()).isPresent() .get() .isEqualTo("Line Coverage: 50.00% (+50.00%)"); - assertThat(output.getText()).isEmpty(); + var expectedDetails = toString("coverage-publisher-details.checks-expected-result"); + assertThat(output.getText()).isPresent().get().asString().isEqualToNormalizingWhitespace(expectedDetails); assertChecksAnnotations(output, expectedAnnotations); assertSummary(output); }); } private void assertSummary(final ChecksOutput checksOutput) throws IOException { - var expectedContent = Files.readString(getResourceAsFile("coverage-publisher-summary.checks-expected-result")); + var expectedContent = toString("coverage-publisher-summary.checks-expected-result"); assertThat(checksOutput.getSummary()).isPresent() .get() .asString().isEqualToNormalizingWhitespace(expectedContent); @@ -170,11 +188,15 @@ private CoverageBuildAction createCoverageBuildAction(final Node result) { } private CoverageBuildAction createActionWithoutDelta(final Node result) { + return createActionWithoutDelta(result, new QualityGateResult()); + } + + CoverageBuildAction createActionWithoutDelta(final Node result, final QualityGateResult qualityGateResult) { var run = mock(Run.class); when(run.getUrl()).thenReturn(BUILD_LINK); return new CoverageBuildAction(run, COVERAGE_ID, REPORT_NAME, StringUtils.EMPTY, result, - new QualityGateResult(), null, "refId", + qualityGateResult, null, "refId", 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/CoverageQualityGateEvaluatorTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGateEvaluatorTest.java index 1af65e2fc..3ded4fed5 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGateEvaluatorTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGateEvaluatorTest.java @@ -92,6 +92,24 @@ void shouldSkipIfValueNotDefined() { @Test void shouldReportUnstableIfBelowThreshold() { + QualityGateResult result = createQualityGateResult(); + + assertThat(result).hasOverallStatus(QualityGateStatus.WARNING).isNotSuccessful().isNotInactive().hasMessages( + "-> [Overall project - File Coverage]: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00)", + "-> [Overall project - Line Coverage]: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00)", + "-> [Modified code lines - File Coverage]: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00)", + "-> [Modified code lines - Line Coverage]: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00)", + "-> [Modified files - File Coverage]: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00)", + "-> [Modified files - Line Coverage]: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00)", + "-> [Overall project (difference to reference job) - File Coverage]: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00)", + "-> [Overall project (difference to reference job) - Line Coverage]: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00)", + "-> [Modified code lines (difference to modified files) - File Coverage]: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00)", + "-> [Modified code lines (difference to modified files) - Line Coverage]: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00)", + "-> [Modified files (difference to overall project) - File Coverage]: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00)", + "-> [Modified files (difference to overall project) - Line Coverage]: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00)"); + } + + static QualityGateResult createQualityGateResult() { Collection qualityGates = new ArrayList<>(); qualityGates.add(new CoverageQualityGate(76.0, Metric.FILE, Baseline.PROJECT, QualityGateCriticality.UNSTABLE)); @@ -110,21 +128,7 @@ void shouldReportUnstableIfBelowThreshold() { qualityGates.add(new CoverageQualityGate(minimum, Metric.LINE, Baseline.MODIFIED_FILES_DELTA, QualityGateCriticality.UNSTABLE)); CoverageQualityGateEvaluator evaluator = new CoverageQualityGateEvaluator(qualityGates, createStatistics()); - QualityGateResult result = evaluator.evaluate(); - - assertThat(result).hasOverallStatus(QualityGateStatus.WARNING).isNotSuccessful().isNotInactive().hasMessages( - "-> [Overall project - File Coverage]: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00)", - "-> [Overall project - Line Coverage]: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00)", - "-> [Modified code lines - File Coverage]: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00)", - "-> [Modified code lines - Line Coverage]: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00)", - "-> [Modified files - File Coverage]: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00)", - "-> [Modified files - Line Coverage]: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00)", - "-> [Overall project (difference to reference job) - File Coverage]: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00)", - "-> [Overall project (difference to reference job) - Line Coverage]: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00)", - "-> [Modified code lines (difference to modified files) - File Coverage]: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00)", - "-> [Modified code lines (difference to modified files) - Line Coverage]: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00)", - "-> [Modified files (difference to overall project) - File Coverage]: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00)", - "-> [Modified files (difference to overall project) - Line Coverage]: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00)"); + return evaluator.evaluate(); } @Test diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-details.checks-expected-result b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-details.checks-expected-result new file mode 100644 index 000000000..b8352bee7 --- /dev/null +++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-details.checks-expected-result @@ -0,0 +1,11 @@ +#### Project coverage details + +||Module Coverage|Package Coverage|File Coverage|Class Coverage|Method Coverage|Line Coverage|Branch Coverage|Instruction Coverage +|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---: +:feet: **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:|n/a|n/a|n/a|n/a|+50.00% :arrow_up:|n/a|n/a +:feet: **Modified files**|n/a|n/a|n/a|n/a|n/a|50.00% (1/2)|n/a|n/a +:chart_with_upwards_trend: **Modified files (difference to overall project)**|n/a|n/a|n/a|n/a|n/a|+50.00% :arrow_up:|n/a|n/a +:feet: **Modified code lines**|n/a|n/a|n/a|n/a|n/a|50.00% (1/2)|n/a|n/a +:chart_with_upwards_trend: **Modified code lines (difference to modified files)**|n/a|n/a|n/a|n/a|n/a|+50.00% :arrow_up:|n/a|n/a +:feet: **Indirect changes**|n/a|n/a|n/a|n/a|n/a|50.00% (1/2)|n/a|n/a diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-quality-gate.checks-expected-result b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-quality-gate.checks-expected-result new file mode 100644 index 000000000..6c8c5c963 --- /dev/null +++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-quality-gate.checks-expected-result @@ -0,0 +1,15 @@ +#### Quality Gates Summary + +Overall result: Unstable +- Overall project - File Coverage: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00) +- Overall project - Line Coverage: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00) +- Modified code lines - File Coverage: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00) +- Modified code lines - Line Coverage: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00) +- Modified files - File Coverage: ≪Unstable≫ - (Actual value: 75.00%, Quality gate: 76.00) +- Modified files - Line Coverage: ≪Unstable≫ - (Actual value: 50.00%, Quality gate: 51.00) +- Overall project (difference to reference job) - File Coverage: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00) +- Overall project (difference to reference job) - Line Coverage: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00) +- Modified code lines (difference to modified files) - File Coverage: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00) +- Modified code lines (difference to modified files) - Line Coverage: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00) +- Modified files (difference to overall project) - File Coverage: ≪Unstable≫ - (Actual value: -10.00%, Quality gate: 10.00) +- Modified files (difference to overall project) - Line Coverage: ≪Unstable≫ - (Actual value: +5.00%, Quality gate: 10.00) diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result index fde6afb9b..896556689 100644 --- a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result +++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result @@ -1,4 +1,9 @@ -## Coverage Report Overview +Modified lines summary: +- 1 line has been modified +- 1 line is not covered +- 1 line is covered only partially + +#### Overview by baseline * **[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) - Delta: +50.00% @@ -12,14 +17,6 @@ * **[Indirect changes](http://127.0.0.1:8080/job/pipeline-coding-style/job/5/coverage#indirectCoverage)** * Line Coverage: 50.00% (1/2) +#### Quality Gates Summary -## 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:|-|-| +No active quality gates.