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
fe45ac2
Add Modified Files Coverage and GitHub Checks API
fo-code Feb 5, 2023
5686bea
Add Modified Files Coverage and GitHub Checks API
fo-code Feb 5, 2023
444c8ca
Merge branch 'file-change-coverage' of https://github.com/fo-code/cod…
fo-code Feb 11, 2023
bf9b3a5
Rename Change Coverage to Modified Lines Coverage an fix tests
fo-code Feb 11, 2023
42a5ee9
Renaming of changes.
uhafner Feb 14, 2023
c35c60a
Fix checks publisher tests
fo-code Feb 16, 2023
eb78397
Add a toggle to show only changed files in absolute coverage table.
uhafner Feb 28, 2023
14f40ac
Merge branch 'coverage-model' into file-change-coverage
uhafner Mar 1, 2023
24c9815
Merge with latest renames in coverage model.
uhafner Mar 1, 2023
f727183
Fix typo.
uhafner Mar 1, 2023
8c97776
Fix typo.
uhafner Mar 1, 2023
8719661
Fix typo.
uhafner Mar 1, 2023
9c05d7a
Remove @since
uhafner Mar 1, 2023
5709d5c
Remove @since
uhafner Mar 1, 2023
96b4228
Do not create tree nodes that do not have a value attached.
uhafner Mar 1, 2023
7eb5c4f
Add incremental versions of dependencies.
uhafner Mar 1, 2023
cacc7df
Add incremental version of forensics-plugin.
uhafner Mar 1, 2023
495ece7
Fix for review comments
fo-code Mar 1, 2023
1a6c504
Use latest incremental version of plugin-util.
uhafner Mar 3, 2023
f41892d
Add customization options for checks.
uhafner Mar 3, 2023
af27993
Add different types of single lines.
uhafner Mar 7, 2023
afb110e
Bump version of coverage-model to 0.15.0.
uhafner Mar 7, 2023
d7f922e
Delete unused table model.
uhafner Mar 7, 2023
5b483c4
Simplify assertions.
uhafner Mar 7, 2023
377d093
Add test for ALL_LINES.
uhafner Mar 7, 2023
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
18 changes: 13 additions & 5 deletions plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.jvnet.hudson.plugins</groupId>
<artifactId>analysis-pom</artifactId>
<version>6.0.0</version>
<version>6.1.0</version>
<relativePath />
</parent>

Expand Down Expand Up @@ -35,11 +35,17 @@
<job-dsl.version>1.81</job-dsl.version>
<xmlunit.version>2.9.0</xmlunit.version>

<coverage-model.version>0.13.0</coverage-model.version>
<coverage-model.version>0.15.0</coverage-model.version>
<echarts-api.version>5.4.0-2-rc759.8b_4e78286216</echarts-api.version>
<prism-api.version>1.29.0-3-rc207.f000c20b_dea_5</prism-api.version>
<plugin-util-api.version>3.0.0-rc679.e40704a_a_f29f</plugin-util-api.version>
<git-forensics.version>1.11.0</git-forensics.version>

<jquery3-api.version>3.6.3-1-rc365.70899fb_d9e1d</jquery3-api.version>
<plugin-util-api.version>3.0.0-rc693.c098b_871ea_49</plugin-util-api.version>
<bootstrap5-api.version>5.2.2-1-rc442.6631330fec41</bootstrap5-api.version>
<font-awesome-api.version>6.3.0-1-rc517.f6b_6e5a_dd4ef</font-awesome-api.version>

<forensics-api.version>2.0.0-rc1380.c93c627cd828</forensics-api.version>
</properties>

<developers>
Expand Down Expand Up @@ -139,11 +145,12 @@
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>bootstrap5-api</artifactId>
<version>5.2.0-3</version>
<version>${bootstrap5-api.version}</version>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>jquery3-api</artifactId>
<version>${jquery3-api.version}</version>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
Expand All @@ -152,7 +159,7 @@
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>forensics-api</artifactId>
<version>2.0.0-rc1380.c93c627cd828</version>
<version>${forensics-api.version}</version>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
Expand All @@ -162,6 +169,7 @@
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>font-awesome-api</artifactId>
<version>${font-awesome-api.version}</version>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.jenkins.plugins.coverage.metrics.charts;

import java.util.Optional;

import edu.hm.hafner.echarts.ItemStyle;
import edu.hm.hafner.echarts.Label;
import edu.hm.hafner.echarts.LabeledTreeMapNode;
Expand Down Expand Up @@ -38,7 +40,8 @@ public class TreeMapNodeConverter {
*/
public LabeledTreeMapNode toTreeChartModel(final Node node, final Metric metric, final ColorProvider colorProvider) {
var tree = mergePackages(node);
LabeledTreeMapNode root = toTreeMapNode(tree, metric, colorProvider);
LabeledTreeMapNode root = toTreeMapNode(tree, metric, colorProvider).orElse(
new LabeledTreeMapNode(node.getPath(), node.getName()));
for (LabeledTreeMapNode child : root.getChildren()) {
child.collapseEmptyPackages();
}
Expand All @@ -55,18 +58,18 @@ private Node mergePackages(final Node node) {
return node;
}

private LabeledTreeMapNode toTreeMapNode(final Node node, final Metric metric,
private Optional<LabeledTreeMapNode> toTreeMapNode(final Node node, final Metric metric,
final ColorProvider colorProvider) {
var value = node.getValue(metric);
if (value.isPresent()) {
var rootValue = value.get();
if (rootValue instanceof Coverage) {
return createCoverageTree((Coverage) rootValue, colorProvider, node, metric);
return Optional.of(createCoverageTree((Coverage) rootValue, colorProvider, node, metric));
}
// TODO: does it make sense to render the other metrics?
}

return new LabeledTreeMapNode(node.getPath(), node.getName());
return Optional.empty();
}

private LabeledTreeMapNode createCoverageTree(final Coverage coverage, final ColorProvider colorProvider, final Node node,
Expand All @@ -91,6 +94,7 @@ private LabeledTreeMapNode createCoverageTree(final Coverage coverage, final Col

node.getChildren().stream()
.map(n -> toTreeMapNode(n, metric, colorProvider))
.flatMap(Optional::stream)
.forEach(treeNode::insertNode);

return treeNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,23 @@ public enum Baseline {
* Coverage of the modified lines (e.g., within the modified lines of a pull or merge request) will focus on new or
* modified code only.
*/
MODIFIED_LINES(Messages._Baseline_MODIFIED_LINES(), "changeCoverage", CoverageLevel::getDisplayColorsOfCoverageLevel),
MODIFIED_LINES(Messages._Baseline_MODIFIED_LINES(), "modifiedLinesCoverage", CoverageLevel::getDisplayColorsOfCoverageLevel),
/**
* Difference between the project coverage and the modified lines coverage of the current build. Teams can use this delta
* value to ensure that the coverage of pull requests is better than the whole project coverage.
*/
MODIFIED_LINES_DELTA(Messages._Baseline_MODIFIED_LINES_DELTA(), "changeCoverage",
MODIFIED_LINES_DELTA(Messages._Baseline_MODIFIED_LINES_DELTA(), "modifiedLinesCoverage",
CoverageChangeTendency::getDisplayColorsForTendency),
/**
* Coverage of the modified files (e.g., within the files that have been touched in a pull or merge request) will
* focus on new or modified code only.
*/
MODIFIED_FILES(Messages._Baseline_MODIFIED_FILES(), "fileCoverage", CoverageLevel::getDisplayColorsOfCoverageLevel),
MODIFIED_FILES(Messages._Baseline_MODIFIED_FILES(), "modifiedFilesCoverage", CoverageLevel::getDisplayColorsOfCoverageLevel),
/**
* Difference between the project coverage and the modified file coverage of the current build. Teams can use this delta
* value to ensure that the coverage of pull requests is better than the whole project coverage.
*/
MODIFIED_FILES_DELTA(Messages._Baseline_MODIFIED_FILES_DELTA(), "fileCoverage", CoverageChangeTendency::getDisplayColorsForTendency),
MODIFIED_FILES_DELTA(Messages._Baseline_MODIFIED_FILES_DELTA(), "modifiedFilesCoverage", CoverageChangeTendency::getDisplayColorsForTendency),
Copy link
Member

@uhafner uhafner Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While looking at the results I think I made a mistake here. When I am developing a PR normally I am interested in the coverage of my changes.

That means we need the totals (this is already working correctly):

  • coverage overall project
  • changed files
  • changed lines

But when looking at the delta we need:

  • delta overall project - delta overall reference (typically not interesting for large projects)
  • delta changed files - delta changed files reference (how is the coverage of the changed files affected)? Currently we check how it changes with respect to the overall coverage.
  • delta changed lines: here I am not sure whether it makes more sense to compare vs. the whole project or the changed files. What do you think? Or do we need both?

Bildschirm­foto 2023-02-28 um 12 00 31

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that makes sense.
Regarding the delta changed lines: I guess we should compare only against the modified files coverage. The whole project has modules with higher and with lower coverage. When we compare the changes of a module with lower coverage against the whole project, there will be a negative trend, even if the modified files are covered quiet good compared to the rest of their module. Therefore, comparing against the changed files would keep the context hence it more accurate, in my opinion.

/**
* Indirect changes of the overall code coverage that are not part of the changed code. These changes might occur,
* if new tests will be added without touching the underlying code under test.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package io.jenkins.plugins.coverage.metrics.model;

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;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.Fraction;
Expand All @@ -11,6 +15,7 @@
import edu.hm.hafner.metric.FractionValue;
import edu.hm.hafner.metric.IntegerValue;
import edu.hm.hafner.metric.Metric;
import edu.hm.hafner.metric.Node;
import edu.hm.hafner.metric.Percentage;
import edu.hm.hafner.metric.Value;

Expand Down Expand Up @@ -134,6 +139,7 @@ public String formatDetails(final Value value, final Locale locale) {
*
* @param value
* the value to format
*
* @return the formatted value as plain text
*/
public String formatAdditionalInformation(final Value value) {
Expand Down Expand Up @@ -184,10 +190,11 @@ public boolean showColors(final Value value) {
public DisplayColors getDisplayColors(final Baseline baseline, final Value value) {
var defaultColorProvider = ColorProviderFactory.createDefaultColorProvider();
if (value instanceof Coverage) {
return baseline.getDisplayColors(((Coverage)value).getCoveredPercentage().toDouble(), defaultColorProvider);
return baseline.getDisplayColors(((Coverage) value).getCoveredPercentage().toDouble(),
defaultColorProvider);
}
else if (value instanceof FractionValue) {
return baseline.getDisplayColors(((FractionValue)value).getFraction().doubleValue(), defaultColorProvider);
return baseline.getDisplayColors(((FractionValue) value).getFraction().doubleValue(), defaultColorProvider);
}
return ColorProvider.DEFAULT_COLOR;
}
Expand Down Expand Up @@ -370,6 +377,48 @@ public String getDisplayName(final Metric metric) {
}
}

/**
* Gets the display names of the existing {@link Metric coverage metrics}, sorted by the metrics ordinal.
*
* @return the sorted metric display names
*/
public List<String> getSortedCoverageDisplayNames() {
return Metric.getCoverageMetrics().stream()
.map(this::getDisplayName)
.collect(Collectors.toList());
}

/**
* Formats a stream of values to their display representation by using the given locale.
*
* @param values
* The values to be formatted
* @param locale
* The locale to be used for formatting
*
* @return the formatted values in the origin order of the stream
*/
public List<String> getFormattedValues(final Stream<? extends Value> values, final Locale locale) {
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<Coverage> 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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ File createFileInBuildFolder(final File buildResults, final String id, final Str
}

/**
* Filters the sourcecode coverage highlighting for analyzing the change coverage only.
* Filters the sourcecode coverage highlighting for analyzing the modified lines coverage only.
*
* @param content
* The original HTML content
Expand All @@ -172,9 +172,9 @@ File createFileInBuildFolder(final File buildResults, final String id, final Str
*
* @return the filtered HTML sourcecode view
*/
public String calculateChangeCoverageSourceCode(final String content, final FileNode fileNode) {
public String calculateModifiedLinesCoverageSourceCode(final String content, final FileNode fileNode) {
Set<Integer> lines = fileNode.getLinesWithCoverage();
lines.retainAll(fileNode.getChangedLines());
lines.retainAll(fileNode.getModifiedLines());
Set<String> linesAsText = lines.stream().map(String::valueOf).collect(Collectors.toSet());
Document doc = Jsoup.parse(content, Parser.xmlParser());
int maxLine = Integer.parseInt(Objects.requireNonNull(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import org.apache.commons.io.FileUtils;

import edu.hm.hafner.metric.FileNode;
import edu.hm.hafner.metric.Metric;
import edu.hm.hafner.metric.Mutation;
import edu.hm.hafner.util.FilteredLog;
import edu.umd.cs.findbugs.annotations.NonNull;

Expand Down Expand Up @@ -328,29 +328,33 @@ private enum Type {
private final int[] linesToPaint;
private final int[] coveredPerLine;
private final int[] missedPerLine;
private final Type type;
private final int[] survivedPerLine;
private final int[] killedPerLine;

PaintedNode(final FileNode file) {
path = file.getPath();

linesToPaint = file.getLinesWithCoverage().stream().mapToInt(i -> i).toArray();
coveredPerLine = file.getCoveredCounters();
missedPerLine = file.getMissedCounters();
if (file.containsMetric(Metric.MUTATION)) { // FIXME: this needs to be generalized
type = Type.MUTATION;
}
else {
type = Type.COVERAGE;

survivedPerLine = new int[linesToPaint.length];
killedPerLine = new int[linesToPaint.length];

for (Mutation mutation : file.getMutations()) { // FIXME: this needs to be generalized
if (mutation.hasSurvived()) {
survivedPerLine[findLine(mutation.getLine())]++;
}
else if (mutation.isKilled()) {
killedPerLine[findLine(mutation.getLine())]++;
}
}
}

public String getPath() {
return path;
}

public boolean isMutation() {
return type == Type.MUTATION;
}

public boolean isPainted(final int line) {
return findLine(line) >= 0;
}
Expand All @@ -367,6 +371,14 @@ public int getMissed(final int line) {
return getCounter(line, missedPerLine);
}

public int getSurvived(final int line) {
return getCounter(line, survivedPerLine);
}

public int getKilled(final int line) {
return getCounter(line, killedPerLine);
}

private int getCounter(final int line, final int[] counters) {
var index = findLine(line);
if (index >= 0) {
Expand Down
Loading