Skip to content

Commit

Permalink
Merge branch 'master' into validate-service-data
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmelnikow authored Jan 13, 2019
2 parents f8e1742 + 796d066 commit 66e9176
Show file tree
Hide file tree
Showing 23 changed files with 470 additions and 472 deletions.
2 changes: 1 addition & 1 deletion services/azure-devops/azure-devops-coverage.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ module.exports = class AzureDevOpsCoverage extends AzureDevOpsBase {
},
{
title: 'Azure DevOps coverage (branch)',
pattern: ':organization/:project/:definitionId/:branch*',
pattern: ':organization/:project/:definitionId/:branch',
namedParams: {
organization: 'swellaby',
project: 'opensource',
Expand Down
2 changes: 1 addition & 1 deletion services/azure-devops/azure-devops-tests.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ module.exports = class AzureDevOpsTests extends AzureDevOpsBase {
},
{
title: 'Azure DevOps tests (branch)',
pattern: ':organization/:project/:definitionId/:branch*',
pattern: ':organization/:project/:definitionId/:branch',
namedParams: {
organization: 'azuredevops-powershell',
project: 'azuredevops-powershell',
Expand Down
195 changes: 100 additions & 95 deletions services/dub/dub-download.service.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,114 @@
'use strict'

const LegacyService = require('../legacy-service')
const {
makeBadgeData: getBadgeData,
makeLabel: getLabel,
} = require('../../lib/badge-data')
const { checkErrorResponse } = require('../../lib/error-helper')
const Joi = require('joi')
const BaseJsonService = require('../base-json')
const { metric } = require('../../lib/text-formatters')
const { addv: versionText } = require('../../lib/text-formatters')
const {
downloadCount: downloadCountColor,
} = require('../../lib/color-formatters')
const { nonNegativeInteger } = require('../validators')

// 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 DubDownload extends LegacyService {
static get category() {
return 'downloads'
}
const schema = Joi.object({
downloads: Joi.object({
total: nonNegativeInteger,
monthly: nonNegativeInteger,
weekly: nonNegativeInteger,
daily: nonNegativeInteger,
}).required(),
})

static get route() {
return {
base: 'dub',
function DownloadsForInterval(interval) {
const { base, messageSuffix } = {
daily: {
base: 'dub/dd',
messageSuffix: '/day',
},
weekly: {
base: 'dub/dw',
messageSuffix: '/week',
},
monthly: {
base: 'dub/dm',
messageSuffix: '/month',
},
total: {
base: 'dub/dt',
messageSuffix: '',
},
}[interval]

return class DubDownloads extends BaseJsonService {
static render({ downloads, version }) {
const label = version ? `downloads@${version}` : 'downloads'
return {
label,
message: `${metric(downloads)}${messageSuffix}`,
color: downloadCountColor(downloads),
}
}
}

static get examples() {
return [
{
title: 'DUB',
previewUrl: 'dd/vibe-d',
},
{
title: 'DUB',
previewUrl: 'dw/vibe-d',
},
{
title: 'DUB',
previewUrl: 'dm/vibe-d/latest',
},
{
title: 'DUB',
previewUrl: 'dt/vibe-d/0.8.4',
},
]
}
async fetch({ packageName, version }) {
let url = `https://code.dlang.org/api/packages/${packageName}`
if (version) {
url += `/${version}`
}
url += '/stats'
return this._requestJson({ schema, url })
}

static registerLegacyRouteHandler({ camp, cache }) {
camp.route(
/^\/dub\/(dd|dw|dm|dt)\/([^/]+)(?:\/([^/]+))?\.(svg|png|gif|jpg|json)$/,
cache((data, match, sendBadge, request) => {
const info = match[1] // downloads (dd - daily, dw - weekly, dm - monthly, dt - total)
const pkg = match[2] // package name, e.g. vibe-d
const version = match[3] // version (1.2.3 or latest)
const format = match[4]
let apiUrl = `https://code.dlang.org/api/packages/${pkg}`
if (version) {
apiUrl += `/${version}`
}
apiUrl += '/stats'
const badgeData = getBadgeData('dub', data)
request(apiUrl, (err, res, buffer) => {
if (checkErrorResponse(badgeData, err, res)) {
sendBadge(format, badgeData)
return
}
try {
const parsedData = JSON.parse(buffer)
if (info.charAt(0) === 'd') {
badgeData.text[0] = getLabel('downloads', data)
let downloads
switch (info.charAt(1)) {
case 'm':
downloads = parsedData.downloads.monthly
badgeData.text[1] = `${metric(downloads)}/month`
break
case 'w':
downloads = parsedData.downloads.weekly
badgeData.text[1] = `${metric(downloads)}/week`
break
case 'd':
downloads = parsedData.downloads.daily
badgeData.text[1] = `${metric(downloads)}/day`
break
case 't':
downloads = parsedData.downloads.total
badgeData.text[1] = metric(downloads)
break
}
if (version) {
badgeData.text[1] += ` ${versionText(version)}`
}
badgeData.colorscheme = downloadCountColor(downloads)
sendBadge(format, badgeData)
}
} catch (e) {
badgeData.text[1] = 'invalid'
sendBadge(format, badgeData)
}
})
async handle({ packageName, version }) {
const data = await this.fetch({ packageName, version })
return this.constructor.render({
downloads: data.downloads[interval],
version,
})
)
}

static get defaultBadgeData() {
return { label: 'downloads' }
}

static get category() {
return 'downloads'
}

static get route() {
return {
base,
pattern: ':packageName/:version*',
}
}

static get examples() {
let examples = [
{
title: 'DUB',
pattern: ':packageName',
namedParams: { packageName: 'vibe-d' },
staticPreview: this.render({ downloads: 5000 }),
},
]
if (interval === 'monthly') {
examples = examples.concat([
{
title: 'DUB (version)',
pattern: ':packageName/:version',
namedParams: { packageName: 'vibe-d', version: '0.8.4' },
staticPreview: this.render({ downloads: 100, version: '0.8.4' }),
},
{
title: 'DUB (latest)',
pattern: ':packageName/:version',
namedParams: { packageName: 'vibe-d', version: 'latest' },
staticPreview: this.render({ downloads: 100, version: 'latest' }),
},
])
}
return examples
}
}
}

module.exports = ['daily', 'weekly', 'monthly', 'total'].map(
DownloadsForInterval
)
84 changes: 84 additions & 0 deletions services/dub/dub-download.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'use strict'

const Joi = require('joi')
const ServiceTester = require('../service-tester')
const { colorScheme } = require('../test-helpers')
const { isMetric, isMetricOverTimePeriod } = require('../test-validators')

const isDownloadsColor = Joi.equal(
colorScheme.red,
colorScheme.yellow,
colorScheme.yellowgreen,
colorScheme.green,
colorScheme.brightgreen
)

const t = (module.exports = new ServiceTester({
id: 'dub',
title: 'DubDownloads',
}))

t.create('total downloads (valid)')
.get('/dt/vibe-d.json?style=_shields_test')
.expectJSONTypes(
Joi.object().keys({
name: 'downloads',
value: isMetric,
colorB: isDownloadsColor,
})
)

t.create('total downloads, specific version (valid)')
.get('/dt/vibe-d/0.8.4.json?style=_shields_test')
.expectJSONTypes(
Joi.object().keys({
name: 'downloads@0.8.4',
value: Joi.string().regex(/^[1-9][0-9]*[kMGTPEZY]?$/),
colorB: isDownloadsColor,
})
)
.timeout(15000)

t.create('total downloads, latest version (valid)')
.get('/dt/vibe-d/latest.json?style=_shields_test')
.expectJSONTypes(
Joi.object().keys({
name: 'downloads@latest',
value: Joi.string().regex(/^[1-9][0-9]*[kMGTPEZY]?$/),
colorB: isDownloadsColor,
})
)

t.create('daily downloads (valid)')
.get('/dd/vibe-d.json?style=_shields_test')
.expectJSONTypes(
Joi.object().keys({
name: 'downloads',
value: isMetricOverTimePeriod,
colorB: isDownloadsColor,
})
)

t.create('weekly downloads (valid)')
.get('/dw/vibe-d.json?style=_shields_test')
.expectJSONTypes(
Joi.object().keys({
name: 'downloads',
value: isMetricOverTimePeriod,
colorB: isDownloadsColor,
})
)

t.create('monthly downloads (valid)')
.get('/dm/vibe-d.json?style=_shields_test')
.expectJSONTypes(
Joi.object().keys({
name: 'downloads',
value: isMetricOverTimePeriod,
colorB: isDownloadsColor,
})
)

t.create('total downloads (not found)')
.get('/dt/not-a-package.json')
.expectJSON({ name: 'downloads', value: 'not found' })
Loading

0 comments on commit 66e9176

Please sign in to comment.