Files
shields/services/codecov/codecov.service.js
Caleb Cartwright 6e84e9b317 Refactor [Codecov] (#3074)
* feat: started refactoring codecov

* tests: removed erroneous test from draft PR

* chore: prettified for prettier

* feat: more codecov updates and tests

* feat: more codecov refactor updates

* feat: added codecov redirect content

* refactor: removed legacy codecov service file

* refactor(codecov): added redirect for legacy token route path

* docs(codecov): added documentation to examples for token info

* docs(codecov): updated vcs param in example patterns

* refactor(codecov): update redirect service date

Co-Authored-By: calebcartwright <calebcartwright@users.noreply.github.com>

* refactor(codecov): various updates based on PR feedback

* chore: added comment to codecov 401 test
2019-03-07 23:11:41 -06:00

140 lines
3.6 KiB
JavaScript

'use strict'
const Joi = require('joi')
const { coveragePercentage } = require('../color-formatters')
const { BaseJsonService } = require('..')
// https://docs.codecov.io/reference#totals
// A new repository that's been added but never had any coverage reports
// uploaded will not have a `commit` object in the response and sometimes
// the `totals` object can also be missing for the latest commit.
// Accordingly the schema is a bit relaxed to support those scenarios
// and then they are handled in the transform and render functions.
const schema = Joi.object({
commit: Joi.object({
totals: Joi.object({
c: Joi.number().required(),
}),
}),
}).required()
const queryParamSchema = Joi.object({
token: Joi.string(),
}).required()
const documentation = `
<p>
You may specify a Codecov token to get coverage for a private repository.
</p>
<p>
See the <a href="https://docs.codecov.io/reference#authorization">Codecov Docs</a>
for more information about creating a token.
</p>
`
module.exports = class Codecov extends BaseJsonService {
static get category() {
return 'coverage'
}
static get defaultBadgeData() {
return { label: 'coverage' }
}
static render({ coverage }) {
if (coverage === 'unknown') {
return {
message: coverage,
color: 'lightgrey',
}
}
return {
message: `${coverage.toFixed(0)}%`,
color: coveragePercentage(coverage),
}
}
static get route() {
return {
base: 'codecov/c',
// https://docs.codecov.io/docs#section-common-questions
// Github, BitBucket, and GitLab are the only supported options (long or short form)
pattern:
':vcsName(github|gh|bitbucket|bb|gl|gitlab)/:user/:repo/:branch*',
queryParamSchema,
}
}
static get examples() {
return [
{
title: 'Codecov',
pattern: ':vcsName(github|gh|bitbucket|bb|gl|gitlab)/:user/:repo',
namedParams: {
vcsName: 'github',
user: 'codecov',
repo: 'example-python',
},
queryParams: {
token: 'abc123def456',
},
staticPreview: this.render({ coverage: 90 }),
documentation,
},
{
title: 'Codecov branch',
pattern:
':vcsName(github|gh|bitbucket|bb|gl|gitlab)/:user/:repo/:branch',
namedParams: {
vcsName: 'github',
user: 'codecov',
repo: 'example-python',
branch: 'master',
},
queryParams: {
token: 'abc123def456',
},
staticPreview: this.render({ coverage: 90 }),
documentation,
},
]
}
async fetch({ vcsName, user, repo, branch, token }) {
// Codecov Docs: https://docs.codecov.io/reference#section-get-a-single-repository
let url = `https://codecov.io/api/${vcsName}/${user}/${repo}`
if (branch) {
url += `/branches/${branch}`
}
const options = {}
if (token) {
options.headers = {
Authorization: `token ${token}`,
}
}
return this._requestJson({
schema,
options,
url,
errorMessages: {
401: 'not authorized to access repository',
404: 'repository not found',
},
})
}
transform({ json }) {
if (!json.commit || !json.commit.totals) {
return { coverage: 'unknown' }
}
return { coverage: +json.commit.totals.c }
}
async handle({ vcsName, user, repo, branch }, { token }) {
const json = await this.fetch({ vcsName, user, repo, branch, token })
const { coverage } = this.transform({ json })
return this.constructor.render({ coverage })
}
}