-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor arch user repositories [aur] service #2086
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,174 @@ | ||
'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 { floorCount: floorCountColor } = require('../../lib/color-formatters') | ||
const { addv: versionText } = require('../../lib/text-formatters') | ||
const BaseJsonService = require('../base-json') | ||
const { NotFound } = require('../errors') | ||
const { nonNegativeInteger } = require('../validators') | ||
|
||
// For the Arch user repository (AUR). | ||
module.exports = class Aur extends LegacyService { | ||
static registerLegacyRouteHandler({ camp, cache }) { | ||
camp.route( | ||
/^\/aur\/(version|votes|license)\/(.*)\.(svg|png|gif|jpg|json)$/, | ||
cache((data, match, sendBadge, request) => { | ||
const info = match[1] | ||
const pkg = match[2] | ||
const format = match[3] | ||
const apiUrl = 'https://aur.archlinux.org/rpc.php?type=info&arg=' + pkg | ||
const badgeData = getBadgeData('aur', data) | ||
request(apiUrl, (err, res, buffer) => { | ||
if (checkErrorResponse(badgeData, err, res)) { | ||
sendBadge(format, badgeData) | ||
return | ||
} | ||
try { | ||
const parsedBuffer = JSON.parse(buffer) | ||
const parsedData = parsedBuffer.results | ||
if (parsedBuffer.resultcount === 0) { | ||
// Note the 'not found' response from Arch Linux is: | ||
// status code = 200, | ||
// body = {"version":1,"type":"info","resultcount":0,"results":[]} | ||
badgeData.text[1] = 'not found' | ||
sendBadge(format, badgeData) | ||
return | ||
} | ||
|
||
if (info === 'version') { | ||
badgeData.text[1] = versionText(parsedData.Version) | ||
if (parsedData.OutOfDate === null) { | ||
badgeData.colorscheme = 'blue' | ||
} else { | ||
badgeData.colorscheme = 'orange' | ||
} | ||
} else if (info === 'votes') { | ||
const votes = parsedData.NumVotes | ||
badgeData.text[0] = getLabel('votes', data) | ||
badgeData.text[1] = votes | ||
badgeData.colorscheme = floorCountColor(votes, 2, 20, 60) | ||
} else if (info === 'license') { | ||
const license = parsedData.License | ||
badgeData.text[0] = getLabel('license', data) | ||
badgeData.text[1] = license | ||
badgeData.colorscheme = 'blue' | ||
} | ||
sendBadge(format, badgeData) | ||
} catch (e) { | ||
badgeData.text[1] = 'invalid' | ||
sendBadge(format, badgeData) | ||
} | ||
}) | ||
}) | ||
) | ||
const aurSchema = Joi.object({ | ||
resultcount: nonNegativeInteger, | ||
results: Joi.alternatives( | ||
Joi.array() | ||
.min(0) | ||
.max(0) | ||
.required(), | ||
Joi.object({ | ||
License: Joi.string().required(), | ||
NumVotes: nonNegativeInteger, | ||
Version: Joi.string().required(), | ||
OutOfDate: nonNegativeInteger.allow(null), | ||
}).required() | ||
), | ||
}).required() | ||
|
||
class BaseAurService extends BaseJsonService { | ||
async fetch({ pkg }) { | ||
return this._requestJson({ | ||
schema: aurSchema, | ||
url: `https://aur.archlinux.org/rpc.php?type=info&arg=${pkg}`, | ||
}) | ||
} | ||
|
||
static get defaultBadgeData() { | ||
return { label: 'aur' } | ||
} | ||
|
||
static _validate(data, schema) { | ||
if (data.resultcount === 0) { | ||
// Note the 'not found' response from Arch Linux is: | ||
// status code = 200, | ||
// body = {"version":1,"type":"info","resultcount":0,"results":[]} | ||
throw new NotFound() | ||
} | ||
return super._validate(data, schema) | ||
} | ||
} | ||
|
||
class AurLicense extends BaseAurService { | ||
static render({ license }) { | ||
return { message: license, color: 'blue' } | ||
PyvesB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
async handle({ pkg }) { | ||
const json = await this.fetch({ pkg }) | ||
return this.constructor.render({ license: json.results.License }) | ||
} | ||
|
||
static get defaultBadgeData() { | ||
return { label: 'license' } | ||
} | ||
|
||
static get category() { | ||
return 'license' | ||
} | ||
|
||
static get url() { | ||
return { | ||
base: 'aur/license', | ||
format: '(.+)', | ||
capture: ['pkg'], | ||
} | ||
} | ||
|
||
static get examples() { | ||
return [ | ||
{ | ||
title: `AUR license`, | ||
urlPattern: ':package', | ||
exampleUrl: 'yaourt', | ||
staticExample: this.render({ license: 'GPL' }), | ||
}, | ||
] | ||
} | ||
} | ||
|
||
class AurVotes extends BaseAurService { | ||
static render({ votes }) { | ||
return { | ||
message: votes, | ||
color: floorCountColor(votes, 2, 20, 60), | ||
} | ||
} | ||
|
||
async handle({ pkg }) { | ||
const json = await this.fetch({ pkg }) | ||
return this.constructor.render({ votes: json.results.NumVotes }) | ||
} | ||
|
||
static get defaultBadgeData() { | ||
return { label: 'votes' } | ||
} | ||
|
||
static get category() { | ||
return 'rating' | ||
} | ||
|
||
static get url() { | ||
return { | ||
base: 'aur/votes', | ||
format: '(.+)', | ||
capture: ['pkg'], | ||
} | ||
} | ||
|
||
static get examples() { | ||
return [ | ||
{ | ||
title: `AUR votes`, | ||
urlPattern: ':package', | ||
exampleUrl: 'yaourt', | ||
staticExample: this.render({ license: '3029' }), | ||
}, | ||
] | ||
} | ||
} | ||
|
||
class AurVersion extends BaseAurService { | ||
static render({ version, outOfDate }) { | ||
const color = outOfDate === null ? 'blue' : 'orange' | ||
return { message: versionText(version), color: color } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've intentionally not used |
||
} | ||
|
||
async handle({ pkg }) { | ||
const json = await this.fetch({ pkg }) | ||
return this.constructor.render({ | ||
version: json.results.Version, | ||
outOfDate: json.results.OutOfDate, | ||
}) | ||
} | ||
|
||
static get defaultBadgeData() { | ||
return { label: 'version' } | ||
} | ||
|
||
static get category() { | ||
return 'version' | ||
} | ||
|
||
static get url() { | ||
return { | ||
base: 'aur/version', | ||
format: '(.+)', | ||
capture: ['pkg'], | ||
} | ||
} | ||
|
||
static get examples() { | ||
return [ | ||
{ | ||
title: `AUR version`, | ||
urlPattern: ':package', | ||
exampleUrl: 'yaourt', | ||
staticExample: this.render({ version: 'v1.9-1', outOfDate: null }), | ||
}, | ||
] | ||
} | ||
} | ||
|
||
module.exports = { | ||
AurLicense, | ||
AurVersion, | ||
AurVotes, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ const ServiceTester = require('../service-tester') | |
const { | ||
isVPlusDottedVersionNClausesWithOptionalSuffix, | ||
} = require('../test-validators') | ||
const { invalidJSON } = require('../response-fixtures') | ||
|
||
const t = new ServiceTester({ id: 'aur', title: 'Arch Linux AUR' }) | ||
module.exports = t | ||
|
@@ -16,7 +15,7 @@ t.create('version (valid)') | |
.get('/version/yaourt.json?style=_shields_test') | ||
.expectJSONTypes( | ||
Joi.object().keys({ | ||
name: 'aur', | ||
name: 'version', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm somewhat confused here. Why has the label changed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question. Looking over the examples we usually use the platform name as the label on version badges so I shouldn't have changed this. |
||
value: isVPlusDottedVersionNClausesWithOptionalSuffix, | ||
colorB: '#007ec6', | ||
}) | ||
|
@@ -26,38 +25,15 @@ t.create('version (valid, out of date)') | |
.get('/version/gog-gemini-rue.json?style=_shields_test') | ||
.expectJSONTypes( | ||
Joi.object().keys({ | ||
name: 'aur', | ||
name: 'version', | ||
value: isVPlusDottedVersionNClausesWithOptionalSuffix, | ||
colorB: '#fe7d37', | ||
}) | ||
) | ||
|
||
t.create('version (not found)') | ||
.get('/version/not-a-package.json') | ||
.expectJSON({ name: 'aur', value: 'not found' }) | ||
|
||
t.create('version (connection error)') | ||
.get('/version/yaourt.json') | ||
.networkOff() | ||
.expectJSON({ name: 'aur', value: 'inaccessible' }) | ||
|
||
t.create('version (unexpected response)') | ||
.get('/version/yaourt.json') | ||
.intercept(nock => | ||
nock('https://aur.archlinux.org') | ||
.get('/rpc.php?type=info&arg=yaourt') | ||
.reply(invalidJSON) | ||
) | ||
.expectJSON({ name: 'aur', value: 'invalid' }) | ||
|
||
t.create('version (error response)') | ||
.get('/version/yaourt.json') | ||
.intercept(nock => | ||
nock('https://aur.archlinux.org') | ||
.get('/rpc.php?type=info&arg=yaourt') | ||
.reply(500, '{"error":"oh noes!!"}') | ||
) | ||
.expectJSON({ name: 'aur', value: 'invalid' }) | ||
.expectJSON({ name: 'version', value: 'not found' }) | ||
|
||
// votes tests | ||
|
||
|
@@ -72,30 +48,7 @@ t.create('votes (valid)') | |
|
||
t.create('votes (not found)') | ||
.get('/votes/not-a-package.json') | ||
.expectJSON({ name: 'aur', value: 'not found' }) | ||
|
||
t.create('votes (connection error)') | ||
.get('/votes/yaourt.json') | ||
.networkOff() | ||
.expectJSON({ name: 'aur', value: 'inaccessible' }) | ||
|
||
t.create('votes (unexpected response)') | ||
.get('/votes/yaourt.json') | ||
.intercept(nock => | ||
nock('https://aur.archlinux.org') | ||
.get('/rpc.php?type=info&arg=yaourt') | ||
.reply(invalidJSON) | ||
) | ||
.expectJSON({ name: 'aur', value: 'invalid' }) | ||
|
||
t.create('votes (error response)') | ||
.get('/votes/yaourt.json') | ||
.intercept(nock => | ||
nock('https://aur.archlinux.org') | ||
.get('/rpc.php?type=info&arg=yaourt') | ||
.reply(500, '{"error":"oh noes!!"}') | ||
) | ||
.expectJSON({ name: 'aur', value: 'invalid' }) | ||
.expectJSON({ name: 'votes', value: 'not found' }) | ||
|
||
// license tests | ||
|
||
|
@@ -105,27 +58,4 @@ t.create('license (valid)') | |
|
||
t.create('license (not found)') | ||
.get('/license/not-a-package.json') | ||
.expectJSON({ name: 'aur', value: 'not found' }) | ||
|
||
t.create('license (connection error)') | ||
.get('/license/yaourt.json') | ||
.networkOff() | ||
.expectJSON({ name: 'aur', value: 'inaccessible' }) | ||
|
||
t.create('license (unexpected response)') | ||
.get('/license/yaourt.json') | ||
.intercept(nock => | ||
nock('https://aur.archlinux.org') | ||
.get('/rpc.php?type=info&arg=yaourt') | ||
.reply(invalidJSON) | ||
) | ||
.expectJSON({ name: 'aur', value: 'invalid' }) | ||
|
||
t.create('license (error response)') | ||
.get('/license/yaourt.json') | ||
.intercept(nock => | ||
nock('https://aur.archlinux.org') | ||
.get('/rpc.php?type=info&arg=yaourt') | ||
.reply(500, '{"error":"oh noes!!"}') | ||
) | ||
.expectJSON({ name: 'aur', value: 'invalid' }) | ||
.expectJSON({ name: 'license', value: 'not found' }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you could simply use
length(0)
here.