refactor [hexpm] service (#2203)
This commit is contained in:
@@ -632,18 +632,6 @@ const allBadgeExamples = [
|
||||
previewUrl: '/packagist/dt/doctrine/orm.svg',
|
||||
keywords: ['PHP'],
|
||||
},
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
previewUrl: '/hexpm/dw/plug.svg',
|
||||
},
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
previewUrl: '/hexpm/dd/plug.svg',
|
||||
},
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
previewUrl: '/hexpm/dt/plug.svg',
|
||||
},
|
||||
{
|
||||
title: 'WordPress plugin',
|
||||
previewUrl: '/wordpress/plugin/dt/akismet.svg',
|
||||
@@ -986,10 +974,6 @@ const allBadgeExamples = [
|
||||
title: 'Bower',
|
||||
previewUrl: '/bower/l/bootstrap.svg',
|
||||
},
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
previewUrl: '/hexpm/l/plug.svg',
|
||||
},
|
||||
{
|
||||
title: 'CocoaPods',
|
||||
previewUrl: '/cocoapods/l/AFNetworking.svg',
|
||||
@@ -1218,10 +1202,6 @@ const allBadgeExamples = [
|
||||
title: 'Pub',
|
||||
previewUrl: '/pub/v/box2d.svg',
|
||||
},
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
previewUrl: '/hexpm/v/plug.svg',
|
||||
},
|
||||
{
|
||||
title: 'GitHub tag (latest SemVer)',
|
||||
previewUrl: '/github/tag/expressjs/express.svg',
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const LegacyService = require('../legacy-service')
|
||||
const {
|
||||
makeBadgeData: getBadgeData,
|
||||
makeLabel: getLabel,
|
||||
} = require('../../lib/badge-data')
|
||||
const Joi = require('joi')
|
||||
const BaseJsonService = require('../base-json')
|
||||
const {
|
||||
metric,
|
||||
addv: versionText,
|
||||
@@ -14,69 +11,176 @@ const {
|
||||
downloadCount: downloadCountColor,
|
||||
version: versionColor,
|
||||
} = require('../../lib/color-formatters')
|
||||
const { nonNegativeInteger } = require('../validators')
|
||||
|
||||
module.exports = class Hexpm extends LegacyService {
|
||||
static registerLegacyRouteHandler({ camp, cache }) {
|
||||
camp.route(
|
||||
/^\/hexpm\/([^/]+)\/(.*)\.(svg|png|gif|jpg|json)$/,
|
||||
cache((queryParams, match, sendBadge, request) => {
|
||||
const info = match[1]
|
||||
const repo = match[2] // eg, `httpotion`.
|
||||
const format = match[3]
|
||||
const apiUrl = 'https://hex.pm/api/packages/' + repo
|
||||
const badgeData = getBadgeData('hex', queryParams)
|
||||
request(apiUrl, (err, res, buffer) => {
|
||||
if (err != null) {
|
||||
badgeData.text[1] = 'inaccessible'
|
||||
sendBadge(format, badgeData)
|
||||
return
|
||||
}
|
||||
try {
|
||||
const data = JSON.parse(buffer)
|
||||
if (info.charAt(0) === 'd') {
|
||||
badgeData.text[0] = getLabel('downloads', queryParams)
|
||||
let downloads
|
||||
switch (info.charAt(1)) {
|
||||
case 'w':
|
||||
downloads = data.downloads.week
|
||||
badgeData.text[1] = metric(downloads) + '/week'
|
||||
break
|
||||
case 'd':
|
||||
downloads = data.downloads.day
|
||||
badgeData.text[1] = metric(downloads) + '/day'
|
||||
break
|
||||
case 't':
|
||||
downloads = data.downloads.all
|
||||
badgeData.text[1] = metric(downloads)
|
||||
break
|
||||
}
|
||||
badgeData.colorscheme = downloadCountColor(downloads)
|
||||
sendBadge(format, badgeData)
|
||||
} else if (info === 'v') {
|
||||
const version = data.releases[0].version
|
||||
badgeData.text[1] = versionText(version)
|
||||
badgeData.colorscheme = versionColor(version)
|
||||
sendBadge(format, badgeData)
|
||||
} else if (info === 'l') {
|
||||
const license = (data.meta.licenses || []).join(', ')
|
||||
badgeData.text[0] = getLabel(
|
||||
maybePluralize('license', data.meta.licenses),
|
||||
queryParams
|
||||
)
|
||||
if (license === '') {
|
||||
badgeData.text[1] = 'Unknown'
|
||||
} else {
|
||||
badgeData.text[1] = license
|
||||
badgeData.colorscheme = 'blue'
|
||||
}
|
||||
sendBadge(format, badgeData)
|
||||
}
|
||||
} catch (e) {
|
||||
badgeData.text[1] = 'invalid'
|
||||
sendBadge(format, badgeData)
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
const hexSchema = Joi.object({
|
||||
downloads: Joi.object({
|
||||
all: nonNegativeInteger,
|
||||
week: nonNegativeInteger,
|
||||
day: nonNegativeInteger,
|
||||
}).required(),
|
||||
meta: Joi.object({
|
||||
licenses: Joi.array().required(),
|
||||
}).required(),
|
||||
releases: Joi.array()
|
||||
.items(Joi.object({ version: Joi.string().required() }).required())
|
||||
.required(),
|
||||
}).required()
|
||||
|
||||
class BaseHexPmService extends BaseJsonService {
|
||||
async fetch({ pkg }) {
|
||||
return this._requestJson({
|
||||
schema: hexSchema,
|
||||
url: `https://hex.pm/api/packages/${pkg}`,
|
||||
})
|
||||
}
|
||||
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'hex' }
|
||||
}
|
||||
}
|
||||
|
||||
class HexPmLicense extends BaseHexPmService {
|
||||
static render({ licenses }) {
|
||||
if (licenses.length === 0) {
|
||||
return {
|
||||
label: 'license',
|
||||
message: 'Unknown',
|
||||
color: 'lightgrey',
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: maybePluralize('license', licenses),
|
||||
message: licenses.join(', '),
|
||||
color: 'blue',
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ pkg }) {
|
||||
const json = await this.fetch({ pkg })
|
||||
return this.constructor.render({ licenses: json.meta.licenses })
|
||||
}
|
||||
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'license' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'license'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'hexpm/l',
|
||||
format: '(.+)',
|
||||
capture: ['pkg'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
urlPattern: ':package',
|
||||
exampleUrl: 'plug',
|
||||
staticExample: this.render({ licenses: ['Apache 2'] }),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class HexPmVersion extends BaseHexPmService {
|
||||
static render({ version }) {
|
||||
return { message: versionText(version), color: versionColor(version) }
|
||||
}
|
||||
|
||||
async handle({ pkg }) {
|
||||
const json = await this.fetch({ pkg })
|
||||
return this.constructor.render({ version: json.releases[0].version })
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'version'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'hexpm/v',
|
||||
format: '(.+)',
|
||||
capture: ['pkg'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
urlPattern: ':package',
|
||||
exampleUrl: 'plug',
|
||||
staticExample: this.render({ version: '1.6.4' }),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function DownloadsForInterval(interval) {
|
||||
const { base, messageSuffix } = {
|
||||
day: {
|
||||
base: 'hexpm/dd',
|
||||
messageSuffix: '/day',
|
||||
},
|
||||
week: {
|
||||
base: 'hexpm/dw',
|
||||
messageSuffix: '/week',
|
||||
},
|
||||
all: {
|
||||
base: 'hexpm/dt',
|
||||
messageSuffix: '',
|
||||
},
|
||||
}[interval]
|
||||
|
||||
return class HexPmDownloads extends BaseHexPmService {
|
||||
static render({ downloads }) {
|
||||
return {
|
||||
message: `${metric(downloads)}${messageSuffix}`,
|
||||
color: downloadCountColor(downloads),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ pkg }) {
|
||||
const json = await this.fetch({ pkg })
|
||||
return this.constructor.render({ downloads: json.downloads[interval] })
|
||||
}
|
||||
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'downloads' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'downloads'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: base,
|
||||
format: '(.+)',
|
||||
capture: ['pkg'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Hex.pm',
|
||||
urlPattern: ':package',
|
||||
exampleUrl: 'plug',
|
||||
staticExample: this.render({ downloads: 85000 }),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const downloadsServices = ['day', 'week', 'all'].map(DownloadsForInterval)
|
||||
|
||||
module.exports = [...downloadsServices, HexPmLicense, HexPmVersion]
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const Joi = require('joi')
|
||||
const ServiceTester = require('../service-tester')
|
||||
const { isMetric, isMetricOverTimePeriod } = require('../test-validators')
|
||||
const { colorScheme } = require('../test-helpers')
|
||||
|
||||
const isHexpmVersion = Joi.string().regex(/^v\d+.\d+.?\d?$/)
|
||||
|
||||
@@ -30,19 +31,45 @@ t.create('version')
|
||||
.expectJSONTypes(Joi.object().keys({ name: 'hex', value: isHexpmVersion }))
|
||||
|
||||
t.create('license')
|
||||
.get('/l/cowboy.json')
|
||||
.get('/l/cowboy.json?style=_shields_test')
|
||||
.expectJSONTypes(
|
||||
Joi.object().keys({
|
||||
name: 'license',
|
||||
value: Joi.string().required(),
|
||||
colorB: colorScheme.blue,
|
||||
})
|
||||
)
|
||||
|
||||
t.create('unknown repo')
|
||||
.get('/l/this-repo-does-not-exist.json')
|
||||
.expectJSON({ name: 'hex', value: 'invalid' })
|
||||
t.create('license (multiple licenses)')
|
||||
.get('/l/cowboy.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://hex.pm/')
|
||||
.get('/api/packages/cowboy')
|
||||
.reply(200, {
|
||||
downloads: { all: 0, week: 0, day: 0 },
|
||||
releases: [{ version: '1.0' }],
|
||||
meta: { licenses: ['GPLv2', 'MIT'] },
|
||||
})
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'licenses',
|
||||
value: 'GPLv2, MIT',
|
||||
colorB: colorScheme.blue,
|
||||
})
|
||||
|
||||
t.create('connection error')
|
||||
.get('/l/cowboy.json')
|
||||
.networkOff()
|
||||
.expectJSON({ name: 'hex', value: 'inaccessible' })
|
||||
t.create('license (no license)')
|
||||
.get('/l/cowboy.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://hex.pm/')
|
||||
.get('/api/packages/cowboy')
|
||||
.reply(200, {
|
||||
downloads: { all: 0, week: 0, day: 0 },
|
||||
releases: [{ version: '1.0' }],
|
||||
meta: { licenses: [] },
|
||||
})
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'license',
|
||||
value: 'Unknown',
|
||||
colorB: colorScheme.lightgrey,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user