Refactor [Coveralls] (#3130)

* refactor(coveralls)

* chore: added comment with link to api

* doc: updated coveralls api doc comment

* doc: updated coveralls api doc comment
This commit is contained in:
Caleb Cartwright
2019-03-02 04:48:38 -06:00
committed by Pierre-Yves B
parent f0eac60191
commit cad3ea434f
2 changed files with 64 additions and 207 deletions

View File

@@ -1,54 +1,63 @@
'use strict'
const LegacyService = require('../legacy-service')
const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
const {
coveragePercentage: coveragePercentageColor,
} = require('../color-formatters')
const Joi = require('joi')
const { BaseJsonService } = require('..')
const { coveragePercentage } = require('../color-formatters')
// This legacy service should be rewritten to use e.g. BaseJsonService.
//
// Tips for rewriting:
// https://github.com/badges/shields/blob/master/doc/rewriting-services.md
//
// Do not base new services on this code.
module.exports = class Coveralls extends LegacyService {
const schema = Joi.object({
covered_percent: Joi.number()
.min(0)
.max(100)
.required(),
}).required()
module.exports = class Coveralls extends BaseJsonService {
static get category() {
return 'coverage'
}
static get defaultBadgeData() {
return { label: 'coverage' }
}
static render({ coverage }) {
return {
message: `${coverage.toFixed(0)}%`,
color: coveragePercentage(coverage),
}
}
static get route() {
return {
base: 'coveralls',
pattern: '',
pattern: ':vcsType(github|bitbucket)?/:user/:repo/:branch*',
}
}
static get examples() {
const { staticPreview } = this
return [
{
title: 'Coveralls github',
pattern: ':vcsType/:user/:repo',
namedParams: { vcsType: 'github', user: 'jekyll', repo: 'jekyll' },
staticPreview,
staticPreview: this.render({ coverage: 86 }),
},
{
title: 'Coveralls github branch',
pattern: ':vcsType/:user/:repo/:branch',
namedParams: {
vcsType: 'github',
user: 'jekyll',
repo: 'jekyll',
user: 'lemurheavy',
repo: 'coveralls-ruby',
branch: 'master',
},
staticPreview,
staticPreview: this.render({ coverage: 91.81 }),
},
{
title: 'Coveralls bitbucket',
pattern: ':vcsType/:user/:repo',
namedParams: { vcsType: 'bitbucket', user: 'pyKLIP', repo: 'pyklip' },
staticPreview,
staticPreview: this.render({ coverage: 86 }),
},
{
title: 'Coveralls bitbucket branch',
@@ -59,68 +68,39 @@ module.exports = class Coveralls extends LegacyService {
repo: 'pyklip',
branch: 'master',
},
staticPreview,
staticPreview: this.render({ coverage: 96 }),
},
]
}
static get staticPreview() {
return { message: '83%', color: 'yellowgreen' }
}
static get defaultBadgeData() {
return {
label: 'coverage',
async fetch({ vcsType, user, repo, branch }) {
// https://docs.coveralls.io/api-introduction#getting-data-from-coveralls
const url = `https://coveralls.io/${vcsType ||
'github'}/${user}/${repo}.json`
const options = {
qs: {
// The API returns the latest result (across any branch) if no branch is explicitly specified,
// whereas the Coveralls native badge (and the Shields.io badges for Coveralls) show
// the coverage for the default branch if no branch is explicitly specified. If the user
// doesn't specify their desired badge, then we can get the Coverage for the latest branch
// from the API by specifying an invalid branch name in which case the API returns the coverage
// for the default branch. This ensures we show the same percentage value.
branch: branch || '@',
},
}
return this._requestJson({
schema,
url,
options,
errorMessages: {
404: 'repository not found',
},
})
}
static registerLegacyRouteHandler({ camp, cache }) {
camp.route(
/^\/coveralls\/(?:(bitbucket|github)\/)?([^/]+\/[^/]+)(?:\/(.+))?\.(svg|png|gif|jpg|json)$/,
cache((data, match, sendBadge, request) => {
const repoService = match[1] ? match[1] : 'github'
const userRepo = match[2] // eg, `jekyll/jekyll`.
const branch = match[3]
const format = match[4]
const apiUrl = {
url: `https://coveralls.io/repos/${repoService}/${userRepo}/badge.svg`,
followRedirect: false,
method: 'HEAD',
}
if (branch) {
apiUrl.url += `?branch=${branch}`
}
const badgeData = getBadgeData('coverage', data)
request(apiUrl, (err, res) => {
if (err != null) {
badgeData.text[1] = 'invalid'
sendBadge(format, badgeData)
return
}
// We should get a 302. Look inside the Location header.
const buffer = res.headers.location
if (!buffer) {
badgeData.text[1] = 'invalid'
sendBadge(format, badgeData)
return
}
try {
const score = buffer.split('_')[1].split('.')[0]
const percentage = parseInt(score)
if (Number.isNaN(percentage)) {
badgeData.text[1] = 'unknown'
sendBadge(format, badgeData)
return
}
badgeData.text[1] = `${score}%`
badgeData.colorscheme = coveragePercentageColor(percentage)
sendBadge(format, badgeData)
} catch (e) {
badgeData.text[1] = 'malformed'
sendBadge(format, badgeData)
}
})
})
)
async handle({ vcsType, user, repo, branch }) {
const json = await this.fetch({ vcsType, user, repo, branch })
return this.constructor.render({ coverage: json.covered_percent })
}
}

View File

@@ -1,143 +1,20 @@
'use strict'
const { isIntegerPercentage } = require('../test-validators')
const { ServiceTester } = require('../tester')
const t = (module.exports = new ServiceTester({
id: 'coveralls',
title: 'Coveralls.io',
}))
t.create('error status code - location header is missing')
.get('/github/not/existed.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/github/not/existed/badge.svg')
.reply(404)
)
.expectBadge({ label: 'coverage', message: 'invalid' })
t.create('malformed location')
.get('/github/user/repository.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/github/user/repository/badge.svg')
.reply(
302,
{},
{
Location:
'https://s3.amazonaws.com/assets.coveralls.io/badges/malformedlocation.svg',
}
)
)
.expectBadge({ label: 'coverage', message: 'malformed' })
t.create('NaN percentage in location')
.get('/github/user/repository.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/github/user/repository/badge.svg')
.reply(
302,
{},
{
Location:
'https://s3.amazonaws.com/assets.coveralls.io/badges/coveralls_notanumber.svg',
}
)
)
.expectBadge({ label: 'coverage', message: 'unknown' })
t.create('connection error')
.get('/github/user/repository.json')
.networkOff()
.expectBadge({ label: 'coverage', message: 'invalid' })
t.create('show coverage')
.get('/github/user/repository.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/github/user/repository/badge.svg')
.reply(
302,
{},
{
Location:
'https://s3.amazonaws.com/assets.coveralls.io/badges/coveralls_50.svg',
}
)
)
.expectBadge({ label: 'coverage', message: '50%' })
t.create('show coverage for legacy github link')
.get('/user/repository.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/github/user/repository/badge.svg')
.reply(
302,
{},
{
Location:
'https://s3.amazonaws.com/assets.coveralls.io/badges/coveralls_50.svg',
}
)
)
.expectBadge({ label: 'coverage', message: '50%' })
t.create('show coverage for branch')
.get('/github/user/repository/branch.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/github/user/repository/badge.svg?branch=branch')
.reply(
302,
{},
{
Location:
'https://s3.amazonaws.com/assets.coveralls.io/badges/coveralls_50.svg',
}
)
)
.expectBadge({ label: 'coverage', message: '50%' })
t.create('show coverage for bitbucket')
.get('/bitbucket/user/repository.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/bitbucket/user/repository/badge.svg')
.reply(
302,
{},
{
Location:
'https://s3.amazonaws.com/assets.coveralls.io/badges/coveralls_50.svg',
}
)
)
.expectBadge({ label: 'coverage', message: '50%' })
t.create('show coverage for bitbucket with branch')
.get('/bitbucket/user/repository/branch.json')
.intercept(nock =>
nock('https://coveralls.io')
.head('/repos/bitbucket/user/repository/badge.svg?branch=branch')
.reply(
302,
{},
{
Location:
'https://s3.amazonaws.com/assets.coveralls.io/badges/coveralls_50.svg',
}
)
)
.expectBadge({ label: 'coverage', message: '50%' })
const t = (module.exports = require('../tester').createServiceTester())
t.create('github coverage')
.get('/github/jekyll/jekyll.json')
.expectBadge({ label: 'coverage', message: isIntegerPercentage })
t.create('nonexistent project')
.get('/github/fake-shields-io/not-a-real-repository.json')
.expectBadge({ label: 'coverage', message: 'repository not found' })
t.create('github branch coverage')
.get('/github/lemurheavy/coveralls-ruby/master.json')
.expectBadge({ label: 'coverage', message: isIntegerPercentage })
t.create('github coverage for legacy link')
.get('/jekyll/jekyll.json')
.expectBadge({ label: 'coverage', message: isIntegerPercentage })