'use strict' const Joi = require('@hapi/joi') const { coveragePercentage: coveragePercentageColor, } = require('../color-formatters') const AzureDevOpsBase = require('./azure-devops-base') const { keywords } = require('./azure-devops-helpers') const documentation = `

To obtain your own badge, you need to get 3 pieces of information: ORGANIZATION, PROJECT and DEFINITION_ID.

First, you need to select your build definition and look at the url:

ORGANIZATION is after the dev.azure.com part, PROJECT is right after that, DEFINITION_ID is at the end after the id= part.

Your badge will then have the form: https://img.shields.io/azure-devops/coverage/ORGANIZATION/PROJECT/DEFINITION_ID.svg.

Optionally, you can specify a named branch: https://img.shields.io/azure-devops/coverage/ORGANIZATION/PROJECT/DEFINITION_ID/NAMED_BRANCH.svg.

` const buildCodeCoverageSchema = Joi.object({ coverageData: Joi.array() .items( Joi.object({ coverageStats: Joi.array() .items( Joi.object({ label: Joi.string().required(), total: Joi.number().required(), covered: Joi.number().required(), }) ) .min(1) .required(), }) ) .required(), }).required() module.exports = class AzureDevOpsCoverage extends AzureDevOpsBase { static get category() { return 'coverage' } static get route() { return { base: 'azure-devops/coverage', pattern: ':organization/:project/:definitionId/:branch*', } } static get examples() { return [ { title: 'Azure DevOps coverage', pattern: ':organization/:project/:definitionId', namedParams: { organization: 'swellaby', project: 'opensource', definitionId: '25', }, staticPreview: this.render({ coverage: 100 }), keywords, documentation, }, { title: 'Azure DevOps coverage (branch)', pattern: ':organization/:project/:definitionId/:branch', namedParams: { organization: 'swellaby', project: 'opensource', definitionId: '25', branch: 'master', }, staticPreview: this.render({ coverage: 100 }), keywords, documentation, }, ] } static get defaultBadgeData() { return { label: 'coverage' } } static render({ coverage }) { return { message: `${coverage.toFixed(0)}%`, color: coveragePercentageColor(coverage), } } async handle({ organization, project, definitionId, branch }) { const auth = this.authHelper.basicAuth const errorMessages = { 404: 'build pipeline or coverage not found', } const buildId = await this.getLatestCompletedBuildId( organization, project, definitionId, branch, auth, errorMessages ) // Microsoft documentation: https://docs.microsoft.com/en-us/rest/api/azure/devops/test/code%20coverage/get%20build%20code%20coverage?view=azure-devops-rest-5.0 const url = `https://dev.azure.com/${organization}/${project}/_apis/test/codecoverage` const options = { qs: { buildId, 'api-version': '5.0-preview.1', }, auth, } const json = await this.fetch({ url, options, schema: buildCodeCoverageSchema, errorMessages, }) let covered = 0 let total = 0 json.coverageData.forEach(cd => { cd.coverageStats.forEach(coverageStat => { if (coverageStat.label === 'Line' || coverageStat.label === 'Lines') { covered += coverageStat.covered total += coverageStat.total } }) }) const coverage = covered ? (covered / total) * 100 : 0 return this.constructor.render({ coverage }) } }