The route helper functions are fairly well isolated from the rest of BaseService, with a few convenient entry points. They are easier to test in isolation. The way the code was written before, `pathToRegexp` was invoked once for every request, which seems inefficient. `route` was validated when it was used, though it seems more helpful to validate it up front. This breaks out `_makeFullUrl`, `_regex`, `_regexFromPath` into new helper functions `makeFullUrl`, `assertValidRoute`, `prepareRoute`, and `namedParamsForMatch`. It adds validation to route, and updates the services without patterns to include one, in order to pass the new validation rules.
229 lines
6.2 KiB
JavaScript
229 lines
6.2 KiB
JavaScript
'use strict'
|
|
|
|
const LegacyService = require('../legacy-service')
|
|
const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
|
|
const { makeLogo: getLogo } = require('../../lib/logos')
|
|
const { metric } = require('../../lib/text-formatters')
|
|
const {
|
|
documentation,
|
|
checkErrorResponse: githubCheckErrorResponse,
|
|
} = require('./github-helpers')
|
|
|
|
// 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 GithubDownloads extends LegacyService {
|
|
static get category() {
|
|
return 'downloads'
|
|
}
|
|
|
|
static get route() {
|
|
return {
|
|
base: 'github',
|
|
pattern: '',
|
|
}
|
|
}
|
|
|
|
static get examples() {
|
|
return [
|
|
{
|
|
title: 'GitHub All Releases',
|
|
pattern: 'downloads/:user/:repo/total',
|
|
namedParams: {
|
|
user: 'atom',
|
|
repo: 'atom',
|
|
},
|
|
staticPreview: {
|
|
label: 'downloads',
|
|
message: '857k total',
|
|
color: 'brightgreen',
|
|
},
|
|
documentation,
|
|
},
|
|
{
|
|
title: 'GitHub Releases',
|
|
pattern: 'downloads/:user/:repo/:tag/total',
|
|
namedParams: {
|
|
user: 'atom',
|
|
repo: 'atom',
|
|
tag: 'latest',
|
|
},
|
|
staticPreview: {
|
|
label: 'downloads',
|
|
message: '27k',
|
|
color: 'brightgreen',
|
|
},
|
|
documentation,
|
|
},
|
|
{
|
|
title: 'GitHub Pre-Releases',
|
|
pattern: 'downloads-pre/:user/:repo/:tag/total',
|
|
namedParams: {
|
|
user: 'atom',
|
|
repo: 'atom',
|
|
tag: 'latest',
|
|
},
|
|
staticPreview: {
|
|
label: 'downloads',
|
|
message: '2k',
|
|
color: 'brightgreen',
|
|
},
|
|
documentation,
|
|
},
|
|
{
|
|
title: 'GitHub Releases (by Release)',
|
|
pattern: 'downloads/:user/:repo/:tag/total',
|
|
namedParams: {
|
|
user: 'atom',
|
|
repo: 'atom',
|
|
tag: 'v0.190.0',
|
|
},
|
|
staticPreview: {
|
|
label: 'downloads',
|
|
message: '490k v0.190.0',
|
|
color: 'brightgreen',
|
|
},
|
|
documentation,
|
|
},
|
|
{
|
|
title: 'GitHub Releases (by Asset)',
|
|
pattern: 'downloads/:user/:repo/:tag/:path',
|
|
namedParams: {
|
|
user: 'atom',
|
|
repo: 'atom',
|
|
tag: 'latest',
|
|
path: 'atom-amd64.deb',
|
|
},
|
|
staticPreview: {
|
|
label: 'downloads',
|
|
message: '3k [atom-amd64.deb]',
|
|
color: 'brightgreen',
|
|
},
|
|
documentation,
|
|
},
|
|
{
|
|
title: 'GitHub Pre-Releases (by Asset)',
|
|
pattern: 'downloads-pre/:user/:repo/:tag/:path',
|
|
namedParams: {
|
|
user: 'atom',
|
|
repo: 'atom',
|
|
tag: 'latest',
|
|
path: 'atom-amd64.deb',
|
|
},
|
|
staticPreview: {
|
|
label: 'downloads',
|
|
message: '237 [atom-amd64.deb]',
|
|
color: 'brightgreen',
|
|
},
|
|
documentation,
|
|
},
|
|
]
|
|
}
|
|
|
|
static registerLegacyRouteHandler({ camp, cache, githubApiProvider }) {
|
|
camp.route(
|
|
/^\/github\/(downloads|downloads-pre)\/([^/]+)\/([^/]+)(\/.+)?\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
|
cache((data, match, sendBadge, request) => {
|
|
const type = match[1] // downloads or downloads-pre
|
|
const user = match[2] // eg, qubyte/rubidium
|
|
const repo = match[3]
|
|
|
|
let tag = match[4] // eg, v0.190.0, latest, null if querying all releases
|
|
const assetName = match[5].toLowerCase() // eg. total, atom-amd64.deb, atom.x86_64.rpm
|
|
const format = match[6]
|
|
|
|
if (tag) {
|
|
tag = tag.slice(1)
|
|
}
|
|
|
|
let total = true
|
|
if (tag) {
|
|
total = false
|
|
}
|
|
|
|
let apiUrl = `/repos/${user}/${repo}/releases`
|
|
if (!total) {
|
|
const releasePath =
|
|
tag === 'latest'
|
|
? type === 'downloads'
|
|
? 'latest'
|
|
: ''
|
|
: `tags/${tag}`
|
|
if (releasePath) {
|
|
apiUrl = `${apiUrl}/${releasePath}`
|
|
}
|
|
}
|
|
const badgeData = getBadgeData('downloads', data)
|
|
if (badgeData.template === 'social') {
|
|
badgeData.logo = getLogo('github', data)
|
|
}
|
|
githubApiProvider.request(request, apiUrl, {}, (err, res, buffer) => {
|
|
if (
|
|
githubCheckErrorResponse(
|
|
badgeData,
|
|
err,
|
|
res,
|
|
'repo or release not found'
|
|
)
|
|
) {
|
|
sendBadge(format, badgeData)
|
|
return
|
|
}
|
|
try {
|
|
let data = JSON.parse(buffer)
|
|
if (type === 'downloads-pre' && tag === 'latest') {
|
|
data = data[0]
|
|
}
|
|
let downloads = 0
|
|
|
|
const labelWords = []
|
|
if (total) {
|
|
data.forEach(tagData => {
|
|
tagData.assets.forEach(asset => {
|
|
if (
|
|
assetName === 'total' ||
|
|
assetName === asset.name.toLowerCase()
|
|
) {
|
|
downloads += asset.download_count
|
|
}
|
|
})
|
|
})
|
|
|
|
labelWords.push('total')
|
|
if (assetName !== 'total') {
|
|
labelWords.push(`[${assetName}]`)
|
|
}
|
|
} else {
|
|
data.assets.forEach(asset => {
|
|
if (
|
|
assetName === 'total' ||
|
|
assetName === asset.name.toLowerCase()
|
|
) {
|
|
downloads += asset.download_count
|
|
}
|
|
})
|
|
|
|
if (tag !== 'latest') {
|
|
labelWords.push(tag)
|
|
}
|
|
if (assetName !== 'total') {
|
|
labelWords.push(`[${assetName}]`)
|
|
}
|
|
}
|
|
labelWords.unshift(metric(downloads))
|
|
badgeData.text[1] = labelWords.join(' ')
|
|
badgeData.colorscheme = 'brightgreen'
|
|
sendBadge(format, badgeData)
|
|
} catch (e) {
|
|
badgeData.text[1] = 'none'
|
|
sendBadge(format, badgeData)
|
|
}
|
|
})
|
|
})
|
|
)
|
|
}
|
|
}
|