Skip to content

Commit 559a99d

Browse files
committed
feat(jenkins): add metric parameter support for apiv4 coverage plugin
The apiv4 format now supports a 'metric' query parameter allowing users to choose which coverage metric to display from the new Jenkins coverage plugin (io.jenkins.plugins.coverage). Supported metrics: line (default), branch, instruction, method, module, file Also updated the description to mention the new Coverage Plugin. Closes #11689
1 parent ef770ac commit 559a99d

File tree

2 files changed

+85
-16
lines changed

2 files changed

+85
-16
lines changed

services/jenkins/jenkins-coverage.service.js

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import Joi from 'joi'
22
import { pathParam, queryParam } from '../index.js'
33
import { coveragePercentage } from '../color-formatters.js'
4+
import { optionalUrl } from '../validators.js'
45
import JenkinsBase from './jenkins-base.js'
5-
import {
6-
buildTreeParamQueryString,
7-
buildUrl,
8-
queryParamSchema,
9-
} from './jenkins-common.js'
6+
import { buildTreeParamQueryString, buildUrl } from './jenkins-common.js'
7+
8+
const queryParamSchema = Joi.object({
9+
jobUrl: optionalUrl,
10+
metric: Joi.string()
11+
.valid('line', 'branch', 'instruction', 'method', 'module', 'file')
12+
.default('line'),
13+
}).required()
1014

1115
const formatMap = {
1216
jacoco: {
@@ -72,17 +76,30 @@ const formatMap = {
7276
projectStatistics: Joi.object({
7377
line: Joi.string()
7478
.pattern(/\d+\.\d+%/)
75-
.required(),
79+
.optional(),
80+
branch: Joi.string()
81+
.pattern(/\d+\.\d+%/)
82+
.optional(),
83+
instruction: Joi.string()
84+
.pattern(/\d+\.\d+%/)
85+
.optional(),
86+
method: Joi.string()
87+
.pattern(/\d+\.\d+%/)
88+
.optional(),
89+
module: Joi.string()
90+
.pattern(/\d+\.\d+%/)
91+
.optional(),
92+
file: Joi.string()
93+
.pattern(/\d+\.\d+%/)
94+
.optional(),
7695
}).required(),
7796
}).required(),
78-
treeQueryParam: 'projectStatistics[line]',
79-
transform: json => {
80-
const lineCoverageStr = json.projectStatistics.line
81-
const lineCoverage = lineCoverageStr.substring(
82-
0,
83-
lineCoverageStr.length - 1,
84-
)
85-
return { coverage: Number.parseFloat(lineCoverage) }
97+
treeQueryParam:
98+
'projectStatistics[line,branch,instruction,method,module,file]',
99+
transform: (json, metric) => {
100+
const raw = json.projectStatistics[metric]
101+
if (!raw) throw new Error(`metric '${metric}' not found`)
102+
return { coverage: Number.parseFloat(raw) }
86103
},
87104
pluginSpecificPath: 'coverage',
88105
},
@@ -95,6 +112,7 @@ We support coverage metrics from a variety of Jenkins plugins:
95112
<li><a href="https://plugins.jenkins.io/jacoco">JaCoCo</a></li>
96113
<li><a href="https://plugins.jenkins.io/cobertura">Cobertura</a></li>
97114
<li>Any plugin which integrates with version 1 or 4+ of the <a href="https://plugins.jenkins.io/code-coverage-api">Code Coverage API</a> (e.g. llvm-cov, Cobertura 1.13+, etc.)</li>
115+
<li>The new <a href="https://plugins.jenkins.io/coverage">Coverage Plugin</a> (use format <code>apiv4</code> with optional <code>metric</code> parameter)</li>
98116
</ul>
99117
`
100118

@@ -124,6 +142,23 @@ export default class JenkinsCoverage extends JenkinsBase {
124142
'https://jenkins-2.sse.uni-hildesheim.de/job/Teaching_SubmissionCheck',
125143
required: true,
126144
}),
145+
queryParam({
146+
name: 'metric',
147+
example: 'line',
148+
description:
149+
'Coverage metric to display (only for apiv4 format). One of: line, branch, instruction, method, module, file. Defaults to line.',
150+
schema: {
151+
type: 'string',
152+
enum: [
153+
'line',
154+
'branch',
155+
'instruction',
156+
'method',
157+
'module',
158+
'file',
159+
],
160+
},
161+
}),
127162
],
128163
},
129164
},
@@ -138,7 +173,7 @@ export default class JenkinsCoverage extends JenkinsBase {
138173
}
139174
}
140175

141-
async handle({ format }, { jobUrl }) {
176+
async handle({ format }, { jobUrl, metric = 'line' }) {
142177
const { schema, transform, treeQueryParam, pluginSpecificPath } =
143178
formatMap[format]
144179
const json = await this.fetch({
@@ -149,7 +184,7 @@ export default class JenkinsCoverage extends JenkinsBase {
149184
404: 'job or coverage not found',
150185
},
151186
})
152-
const { coverage } = transform(json)
187+
const { coverage } = transform(json, metric)
153188
return this.constructor.render({ coverage })
154189
}
155190
}

services/jenkins/jenkins-coverage.tester.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,37 @@ t.create('code coverage API v4+: job found')
103103
t.create('code coverage API v4+: job not found')
104104
.get('/apiv4.json?jobUrl=https://jenkins.mm12.xyz/jenkins/job/does-not-exist')
105105
.expectBadge({ label: 'coverage', message: 'job or coverage not found' })
106+
107+
const coverageApiV4Response = {
108+
_class: 'io.jenkins.plugins.coverage.metrics.restapi.CoverageApi',
109+
projectStatistics: {
110+
branch: '31.39%',
111+
file: '53.27%',
112+
instruction: '70.69%',
113+
line: '70.69%',
114+
method: '65.36%',
115+
module: '100.00%',
116+
},
117+
}
118+
119+
t.create('code coverage API v4+: line coverage (default metric)')
120+
.get('/apiv4.json?jobUrl=https://jenkins.example.com/job/myproject')
121+
.intercept(nock =>
122+
nock('https://jenkins.example.com/job/myproject/lastCompletedBuild')
123+
.get('/coverage/api/json')
124+
.query(true)
125+
.reply(200, coverageApiV4Response),
126+
)
127+
.expectBadge({ label: 'coverage', message: '71%' })
128+
129+
t.create('code coverage API v4+: branch coverage metric')
130+
.get(
131+
'/apiv4.json?jobUrl=https://jenkins.example.com/job/myproject&metric=branch',
132+
)
133+
.intercept(nock =>
134+
nock('https://jenkins.example.com/job/myproject/lastCompletedBuild')
135+
.get('/coverage/api/json')
136+
.query(true)
137+
.reply(200, coverageApiV4Response),
138+
)
139+
.expectBadge({ label: 'coverage', message: '31%' })

0 commit comments

Comments
 (0)