Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.

Commit 01f9a42

Browse files
authored
Merge pull request #615 from jenkinsci/method-coverage
Bump version of coverage-model to 0.20.0
2 parents 30d77c5 + 53c68f5 commit 01f9a42

File tree

21 files changed

+273
-76
lines changed

21 files changed

+273
-76
lines changed

Jenkinsfile

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ def configurations = [
55

66
def params = [
77
failFast: false,
8+
pit: true,
89
configurations: configurations,
910
checkstyle: [qualityGates: [[threshold: 1, type: 'NEW', unstable: true]],
1011
filters:[includePackage('io.jenkins.plugins.coverage.metrics')]],
@@ -86,7 +87,6 @@ def params = [
8687
if (doArchiveArtifacts) {
8788
archivedArtifacts = true
8889
}
89-
9090
boolean incrementals // cf. JEP-305
9191

9292
stage("Checkout (${stageIdentifier})") {
@@ -96,7 +96,8 @@ def params = [
9696
readFile('.mvn/extensions.xml').contains('git-changelist-maven-extension')
9797
final String gitUnavailableMessage = '[buildPlugin] Git CLI may not be available'
9898
withEnv(["GITUNAVAILABLEMESSAGE=${gitUnavailableMessage}"]) {
99-
if (incrementals) { // Incrementals needs 'git status -s' to be empty at start of job
99+
if (incrementals) {
100+
// Incrementals needs 'git status -s' to be empty at start of job
100101
if (isUnix()) {
101102
sh 'git clean -xffd || echo "$GITUNAVAILABLEMESSAGE"'
102103
} else {
@@ -135,9 +136,11 @@ def params = [
135136
if (isUnix()) {
136137
mavenOptions += '-Penable-jacoco'
137138
}
138-
if (incrementals) { // set changelist and activate produce-incrementals profile
139+
if (incrementals) {
140+
// set changelist and activate produce-incrementals profile
139141
mavenOptions += '-Dset.changelist'
140-
if (doArchiveArtifacts) { // ask Maven for the value of -rc999.abc123def456
142+
if (doArchiveArtifacts) {
143+
// ask Maven for the value of -rc999.abc123def456
141144
changelistF = "${pwd tmp: true}/changelist"
142145
mavenOptions += "help:evaluate -Dexpression=changelist -Doutput=$changelistF"
143146
}
@@ -149,8 +152,12 @@ def params = [
149152
mavenOptions += '-DskipTests'
150153
}
151154
mavenOptions += 'clean install'
155+
def pit = params.containsKey('pit') ? params.pit : false
156+
if (pit && first) {
157+
mavenOptions += '-Ppit'
158+
}
152159
try {
153-
infra.runMaven(mavenOptions, jdk, null, null, addToolEnv, useArtifactCachingProxy)
160+
infra.runMaven(mavenOptions, jdk, null, addToolEnv, useArtifactCachingProxy)
154161
} finally {
155162
if (!skipTests) {
156163
junit('**/target/surefire-reports/**/*.xml,**/target/failsafe-reports/**/*.xml,**/target/invoker-reports/**/*.xml')
@@ -163,7 +170,13 @@ def params = [
163170
jacocoArguments.putAll(params.jacoco as Map)
164171
}
165172
recordCoverage jacocoArguments
166-
173+
if (pit) {
174+
recordCoverage(
175+
tools: [[parser: 'PIT', pattern: '**/pit-reports/mutations.xml']],
176+
id: 'pit',
177+
name: 'Mutation Coverage',
178+
checksName: 'Mutation Coverage')
179+
}
167180
}
168181
}
169182
}
@@ -198,7 +211,8 @@ def params = [
198211
}
199212

200213
if (first) {
201-
if (skipTests) { // otherwise the reference build has been computed already
214+
if (skipTests) {
215+
// otherwise the reference build has been computed already
202216
discoverReferenceBuild()
203217
}
204218
echo "Recording static analysis results on '${stageIdentifier}'"
@@ -271,6 +285,19 @@ def params = [
271285
if (failFast && currentBuild.result == 'UNSTABLE') {
272286
error 'Static analysis quality gates not passed; halting early'
273287
}
288+
/*
289+
* If the current build was successful, we send the commits to Launchable so that
290+
* the result can be consumed by a Launchable build in the future. We do not
291+
* attempt to record commits for non-incrementalified plugins because such
292+
* plugins' PR builds could not be consumed by anything else anyway, and all
293+
* plugins currently in the BOM are incrementalified. We do not attempt to record
294+
* commits on Windows because our Windows agents do not have Python installed.
295+
*/
296+
if (incrementals && platform != 'windows' && currentBuild.currentResult == 'SUCCESS') {
297+
launchable.install()
298+
launchable('verify')
299+
launchable('record commit')
300+
}
274301
} else {
275302
echo "Skipping static analysis results for ${stageIdentifier}"
276303
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The Jenkins code coverage plug-in collects reports of code coverage or mutation
1313
- [Cobertura](https://cobertura.github.io/cobertura/)
1414
- [PIT](https://pitest.org/)
1515

16-
If your coverage tool is not yet supported by the code coverage plugin you can provide a pull request for the [Coverage Model](https://github.com/uhafner/coverage-model/pulls).
16+
If your coverage tool is not yet supported by the code coverage plugin you can provide a pull request for the [Coverage Model](https://github.com/jenkinsci/coverage-model/pulls).
1717

1818
The plugin publishes a report of the code coverage and mutation coverage in your build, so you can navigate to a summary report from the main build page. From there you can also dive into the details:
1919
- tree charts that show the distribution of coverage by type (line, instruction, branch, method, class, etc.)

plugin/pom.xml

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<testcontainers.version>1.17.6</testcontainers.version>
3333
<job-dsl.version>1.83</job-dsl.version>
3434

35-
<coverage-model.version>0.19.1</coverage-model.version>
35+
<coverage-model.version>0.21.0</coverage-model.version>
3636
<git-forensics.version>2.0.0</git-forensics.version>
3737
<prism-api.version>1.29.0-4</prism-api.version>
3838
<pull-request-monitoring.version>1.7.8</pull-request-monitoring.version>
@@ -363,6 +363,25 @@
363363
<entryPointClassPackage>io.jenkins.plugins.coverage.metrics</entryPointClassPackage>
364364
</configuration>
365365
</plugin>
366+
<plugin>
367+
<groupId>org.pitest</groupId>
368+
<artifactId>pitest-maven</artifactId>
369+
<configuration>
370+
<targetClasses>
371+
<param>io.jenkins.plugins.coverage.metrics.*</param>
372+
</targetClasses>
373+
<targetTests>
374+
<param>io.jenkins.plugins.coverage.metrics.*</param>
375+
</targetTests>
376+
<excludedTestClasses>
377+
<param>*Assert</param>
378+
<param>*Assertions</param>
379+
<param>*ArchitectureTest</param>
380+
<param>*ITest</param>
381+
<param>*jmh_generated*</param>
382+
</excludedTestClasses>
383+
</configuration>
384+
</plugin>
366385
<plugin>
367386
<groupId>org.revapi</groupId>
368387
<artifactId>revapi-maven-plugin</artifactId>
@@ -373,6 +392,28 @@
373392
</plugins>
374393
</build>
375394

395+
<profiles>
396+
<profile>
397+
<id>pit</id>
398+
<build>
399+
<plugins>
400+
<plugin>
401+
<groupId>org.pitest</groupId>
402+
<artifactId>pitest-maven</artifactId>
403+
<executions>
404+
<execution>
405+
<id>test</id>
406+
<goals>
407+
<goal>mutationCoverage</goal>
408+
</goals>
409+
</execution>
410+
</executions>
411+
</plugin>
412+
</plugins>
413+
</build>
414+
</profile>
415+
</profiles>
416+
376417
<scm>
377418
<connection>scm:git:https://github.com/${gitHubRepo}.git</connection>
378419
<developerConnection>scm:git:[email protected]:${gitHubRepo}.git</developerConnection>

plugin/src/main/java/io/jenkins/plugins/coverage/metrics/model/ElementFormatter.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
*
3030
* @author Florian Orendi
3131
*/
32+
// TODO: create instances for the different types
3233
@SuppressWarnings({"PMD.GodClass", "PMD.CyclomaticComplexity"})
3334
public final class ElementFormatter {
3435
private static final Fraction HUNDRED = Fraction.getFraction("100.0");
@@ -342,7 +343,9 @@ public String formatPercentage(final int covered, final int total, final Locale
342343
* @return the formatted delta percentage as plain text with a leading sign
343344
*/
344345
public String formatDelta(final Fraction fraction, final Metric metric, final Locale locale) {
345-
if (metric.equals(Metric.COMPLEXITY) || metric.equals(Metric.LOC)) { // TODO: move to metric?
346+
if (metric.equals(Metric.COMPLEXITY)
347+
|| metric.equals(Metric.COMPLEXITY_MAXIMUM)
348+
|| metric.equals(Metric.LOC)) {
346349
return String.format(locale, "%+d", fraction.intValue());
347350
}
348351
return String.format(locale, "%+.2f%%", fraction.multiplyBy(HUNDRED).doubleValue());
@@ -381,6 +384,8 @@ public String getDisplayName(final Metric metric) {
381384
return Messages.Metric_MUTATION();
382385
case COMPLEXITY:
383386
return Messages.Metric_COMPLEXITY();
387+
case COMPLEXITY_MAXIMUM:
388+
return Messages.Metric_COMPLEXITY_MAXIMUM();
384389
case COMPLEXITY_DENSITY:
385390
return Messages.Metric_COMPLEXITY_DENSITY();
386391
case LOC:
@@ -448,6 +453,8 @@ public String getLabel(final Metric metric) {
448453
return Messages.Metric_Short_MUTATION();
449454
case COMPLEXITY:
450455
return Messages.Metric_Short_COMPLEXITY();
456+
case COMPLEXITY_MAXIMUM:
457+
return Messages.Metric_Short_COMPLEXITY_MAXIMUM();
451458
case COMPLEXITY_DENSITY:
452459
return Messages.Metric_Short_COMPLEXITY_DENSITY();
453460
case LOC:
@@ -503,6 +510,7 @@ public ListBoxModel getMetricItems() {
503510
add(options, Metric.INSTRUCTION);
504511
add(options, Metric.MUTATION);
505512
add(options, Metric.COMPLEXITY);
513+
add(options, Metric.COMPLEXITY_MAXIMUM);
506514
add(options, Metric.LOC);
507515
return options;
508516
}

plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildAction.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.apache.commons.lang3.math.Fraction;
1717

1818
import edu.hm.hafner.coverage.Metric;
19+
import edu.hm.hafner.coverage.Metric.MetricTendency;
1920
import edu.hm.hafner.coverage.Node;
2021
import edu.hm.hafner.coverage.Value;
2122
import edu.hm.hafner.echarts.ChartModelConfiguration;
@@ -429,6 +430,29 @@ public boolean hasDelta(final Baseline baseline, final Metric metric) {
429430
throw new NoSuchElementException("No such baseline: " + baseline);
430431
}
431432

433+
/**
434+
* Returns whether a delta metric for the specified metric exists.
435+
*
436+
* @param baseline
437+
* the baseline to use
438+
* @param metric
439+
* the metric to check
440+
*
441+
* @return {@code true} if a delta is available for the specified metric, {@code false} otherwise
442+
*/
443+
public Optional<Fraction> getDelta(final Baseline baseline, final Metric metric) {
444+
if (baseline == Baseline.PROJECT) {
445+
return Optional.ofNullable(difference.get(metric));
446+
}
447+
if (baseline == Baseline.MODIFIED_LINES) {
448+
return Optional.ofNullable(modifiedLinesCoverageDifference.get(metric));
449+
}
450+
if (baseline == Baseline.MODIFIED_FILES) {
451+
return Optional.ofNullable(modifiedFilesCoverageDifference.get(metric));
452+
}
453+
return Optional.empty();
454+
}
455+
432456
/**
433457
* Returns whether a value for the specified metric exists.
434458
*
@@ -486,6 +510,27 @@ public String formatDelta(final Baseline baseline, final Metric metric) {
486510
return Messages.Coverage_Not_Available();
487511
}
488512

513+
/**
514+
* Returns whether the trend of the values for the specific metric is positive or negative.
515+
*
516+
* @param baseline
517+
* the baseline to use
518+
* @param metric
519+
* the metric to check
520+
*
521+
* @return {@code true} if the trend is positive, {@code false} otherwise
522+
*/
523+
public boolean isPositiveTrend(final Baseline baseline, final Metric metric) {
524+
var delta = getDelta(baseline, metric);
525+
if (delta.isPresent()) {
526+
if (delta.get().compareTo(Fraction.ZERO) > 0) {
527+
return metric.getTendency() == MetricTendency.LARGER_IS_BETTER;
528+
}
529+
return metric.getTendency() == MetricTendency.SMALLER_IS_BETTER;
530+
}
531+
return true;
532+
}
533+
489534
/**
490535
* Returns the visible metrics for the project summary.
491536
*

plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,10 @@ private Collection<? extends ChecksAnnotation> getPartiallyCoveredLines(final Fi
297297

298298
private String createBranchMessage(final int line, final int missed) {
299299
if (missed == 1) {
300-
return "Line " + line + " is only partially covered, one branch is missing";
300+
return String.format("Line %d is only partially covered, one branch is missing", line);
301301

302302
}
303-
return "Line " + line + " is only partially covered, %d branches are missing.";
303+
return String.format("Line %d is only partially covered, %d branches are missing", line, missed);
304304
}
305305

306306
private ChecksAnnotationBuilder createAnnotationBuilder(final FileNode fileNode) {

plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGateEvaluator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ protected void evaluate(final CoverageQualityGate qualityGate, final QualityGate
3131
if (possibleValue.isPresent()) {
3232
var actualValue = possibleValue.get();
3333

34-
var status = actualValue.isBelowThreshold(
34+
var status = actualValue.isOutOfValidRange(
3535
qualityGate.getThreshold()) ? qualityGate.getStatus() : QualityGateStatus.PASSED;
3636
result.add(qualityGate, status, FORMATTER.format(actualValue, Locale.ENGLISH));
3737
}

plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ public void setChecksName(final String checksName) {
205205
}
206206

207207
public String getChecksName() {
208-
return StringUtils.defaultIfBlank(checksName, CHECKS_DEFAULT_NAME);
208+
return StringUtils.defaultIfBlank(checksName,
209+
StringUtils.defaultIfBlank(getName(), CHECKS_DEFAULT_NAME));
209210
}
210211

211212
/**
@@ -399,7 +400,7 @@ private void perform(final Run<?, ?> run, final FilePath workspace, final TaskLi
399400
.stream()
400401
.filter(ModuleNode.class::isInstance)
401402
.map(ModuleNode.class::cast)
402-
.map(ModuleNode::getSources)
403+
.map(ModuleNode::getSourceFolders)
403404
.flatMap(Collection::stream)
404405
.collect(Collectors.toSet());
405406
sources.addAll(getSourceDirectoriesPaths());

plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageTableModel.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ public List<TableColumn> getColumns() {
128128
.build();
129129
columns.add(complexity);
130130
}
131+
if (root.containsMetric(Metric.COMPLEXITY_MAXIMUM)) {
132+
TableColumn maxComplexity = new ColumnBuilder().withHeaderLabel(Messages.Column_MaxComplexity())
133+
.withDataPropertyKey("maxComplexity")
134+
.withResponsivePriority(900)
135+
.withType(ColumnType.NUMBER)
136+
.build();
137+
columns.add(maxComplexity);
138+
}
131139
if (root.containsMetric(Metric.COMPLEXITY_DENSITY)) {
132140
TableColumn complexity = new ColumnBuilder().withHeaderLabel(Messages.Column_ComplexityDensity())
133141
.withDataPropertyKey("density")
@@ -253,6 +261,10 @@ public int getComplexity() {
253261
return file.getTypedValue(Metric.COMPLEXITY, ZERO_COMPLEXITY).getValue();
254262
}
255263

264+
public int getMaxComplexity() {
265+
return file.getTypedValue(Metric.COMPLEXITY_MAXIMUM, ZERO_COMPLEXITY).getValue();
266+
}
267+
256268
public DetailedCell<?> getDensity() {
257269
double complexityDensity = file.getTypedValue(Metric.COMPLEXITY_DENSITY, ZERO_DENSITY)
258270
.getFraction()

plugin/src/main/resources/coverage/coverage-summary.jelly

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,15 @@
5959
<j:forEach var="value" items="${it.getValues(baseline)}">
6060
<li>${formatter.formatValueWithMetric(value)}
6161
<j:if test="${it.hasDelta(baseline, value.metric)}">
62-
<j:set var="delta" value="${it.formatDelta(baseline, value.metric)}"/>
6362
<j:choose>
64-
<j:when test="${delta.startsWith('-')}">
65-
<j:set var="color" value="var(--red)"/>
63+
<j:when test="${it.isPositiveTrend(baseline, value.metric)}">
64+
<j:set var="color" value="var(--green)"/>
6665
</j:when>
6766
<j:otherwise>
68-
<j:set var="color" value="var(--green)"/>
67+
<j:set var="color" value="var(--red)"/>
6968
</j:otherwise>
7069
</j:choose>
71-
<span style="color: ${color}">(${delta})</span>
70+
<span style="color: ${color}">(${it.formatDelta(baseline, value.metric)})</span>
7271
</j:if>
7372
</li>
7473
</j:forEach>

0 commit comments

Comments
 (0)