Rewrite [NuGet] badges including [myget chocolatey resharper powershellgallery] (#2257)
The NuGet badge examples are straggling in all-badge-examples. Rather than move them as is, I thought it made more sense to refactor the services and see if they could be generated. I didn't take that on here; this is a straight rewrite of the badges. The old implementations were fairly difficult to follow. The new implementations are complicated too, though I hope much more readable. Though the NuGet behaviors could be consolidated into a single flag, I split `withTenant` and `withFeed` into separate flags, thinking naming the behaviors makes the implementations easier to understand. I defaulted these to true, thinking that really this is really a MyGet implementation which is generalized to NuGet. Though maybe it makes more sense to have the MyGet style as the default. Probably it doesn't matter much either way. I added a helper class ServiceUrlBuilder to construct the Shields service URL. It's useful in this complex case where the URL must be built up conditionally. This might be useful in a couple other places. I also wrote a new service to handle the Powershell badges. They've diverged a little bit from the Nuget v2. There's a bit of shared code which I factored out. If the XML Nuget APIs are more reliable, we could consider switching everything else over to them, though for now I would like to get this merged and get #2078 fixed. Fix #2078
This commit is contained in:
119
services/powershellgallery/powershellgallery.service.js
Normal file
119
services/powershellgallery/powershellgallery.service.js
Normal file
@@ -0,0 +1,119 @@
|
||||
'use strict'
|
||||
|
||||
const Joi = require('joi')
|
||||
|
||||
const BaseXmlService = require('../base-xml')
|
||||
const { NotFound } = require('../errors')
|
||||
const { nonNegativeInteger } = require('../validators')
|
||||
const { createFilter } = require('../nuget/nuget-v2-service-family')
|
||||
const {
|
||||
renderVersionBadge,
|
||||
renderDownloadBadge,
|
||||
} = require('../nuget/nuget-helpers')
|
||||
|
||||
const schema = Joi.object({
|
||||
feed: Joi.object({
|
||||
entry: Joi.object({
|
||||
'm:properties': Joi.object({
|
||||
'd:Version': Joi.string(),
|
||||
'd:NormalizedVersion': Joi.string(),
|
||||
'd:DownloadCount': nonNegativeInteger,
|
||||
}),
|
||||
}),
|
||||
}).required(),
|
||||
}).required()
|
||||
|
||||
async function fetch(
|
||||
serviceInstance,
|
||||
{ packageName, includePrereleases = false }
|
||||
) {
|
||||
const data = await serviceInstance._requestXml({
|
||||
schema,
|
||||
url: `https://www.powershellgallery.com/api/v2/Search()`,
|
||||
options: {
|
||||
qs: { $filter: createFilter({ packageName, includePrereleases }) },
|
||||
},
|
||||
})
|
||||
|
||||
const packageData =
|
||||
'entry' in data.feed ? data.feed.entry['m:properties'] : undefined
|
||||
|
||||
if (packageData) {
|
||||
return packageData
|
||||
} else if (!includePrereleases) {
|
||||
return fetch(serviceInstance, {
|
||||
packageName,
|
||||
includePrereleases: true,
|
||||
})
|
||||
} else {
|
||||
throw new NotFound()
|
||||
}
|
||||
}
|
||||
|
||||
class PowershellGalleryVersion extends BaseXmlService {
|
||||
static get category() {
|
||||
return 'version'
|
||||
}
|
||||
|
||||
static get route() {
|
||||
return {
|
||||
base: 'powershellgallery',
|
||||
pattern: ':which(v|vpre)/:packageName',
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return []
|
||||
}
|
||||
|
||||
static get defaultBadgeData() {
|
||||
return {
|
||||
label: 'powershell gallery',
|
||||
}
|
||||
}
|
||||
|
||||
static render(props) {
|
||||
return renderVersionBadge(props)
|
||||
}
|
||||
|
||||
async handle({ which, packageName }) {
|
||||
const packageData = await fetch(this, {
|
||||
packageName,
|
||||
includePrereleases: which === 'vpre',
|
||||
})
|
||||
const version =
|
||||
packageData['d:NormalizedVersion'] || packageData['d:Version']
|
||||
return this.constructor.render({ version })
|
||||
}
|
||||
}
|
||||
|
||||
class PowershellGalleryDownloads extends BaseXmlService {
|
||||
static get category() {
|
||||
return 'downloads'
|
||||
}
|
||||
|
||||
static get route() {
|
||||
return {
|
||||
base: 'powershellgallery',
|
||||
pattern: 'dt/:packageName',
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return []
|
||||
}
|
||||
|
||||
static render(props) {
|
||||
return renderDownloadBadge(props)
|
||||
}
|
||||
|
||||
async handle({ packageName }) {
|
||||
const packageData = await fetch(this, {
|
||||
packageName,
|
||||
})
|
||||
const { 'd:DownloadCount': downloads } = packageData
|
||||
return this.constructor.render({ downloads })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { PowershellGalleryVersion, PowershellGalleryDownloads }
|
||||
@@ -7,13 +7,6 @@ const {
|
||||
isVPlusDottedVersionNClauses,
|
||||
isVPlusDottedVersionNClausesWithOptionalSuffix,
|
||||
} = require('../test-validators')
|
||||
const colorscheme = require('../../lib/colorscheme.json')
|
||||
const {
|
||||
nuGetV2VersionJsonWithDash,
|
||||
nuGetV2VersionJsonFirstCharZero,
|
||||
nuGetV2VersionJsonFirstCharNotZero,
|
||||
} = require('../nuget-fixtures')
|
||||
const { invalidJSON } = require('../response-fixtures')
|
||||
|
||||
const t = new ServiceTester({
|
||||
id: 'powershellgallery',
|
||||
@@ -21,8 +14,6 @@ const t = new ServiceTester({
|
||||
})
|
||||
module.exports = t
|
||||
|
||||
// downloads
|
||||
|
||||
t.create('total downloads (valid)')
|
||||
.get('/dt/ACMESharp.json')
|
||||
.expectJSONTypes(
|
||||
@@ -36,170 +27,28 @@ t.create('total downloads (not found)')
|
||||
.get('/dt/not-a-real-package.json')
|
||||
.expectJSON({ name: 'downloads', value: 'not found' })
|
||||
|
||||
t.create('total downloads (connection error)')
|
||||
.get('/dt/ACMESharp.json')
|
||||
.networkOff()
|
||||
.expectJSON({ name: 'downloads', value: 'inaccessible' })
|
||||
|
||||
t.create('total downloads (unexpected response)')
|
||||
.get('/dt/ACMESharp.json')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(invalidJSON)
|
||||
)
|
||||
.expectJSON({ name: 'downloads', value: 'invalid' })
|
||||
|
||||
// version
|
||||
|
||||
t.create('version (valid)')
|
||||
.get('/v/ACMESharp.json')
|
||||
.expectJSONTypes(
|
||||
Joi.object().keys({
|
||||
name: 'powershellgallery',
|
||||
name: 'powershell gallery',
|
||||
value: isVPlusDottedVersionNClauses,
|
||||
})
|
||||
)
|
||||
|
||||
t.create('version (mocked, yellow badge)')
|
||||
.get('/v/ACMESharp.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(200, nuGetV2VersionJsonWithDash)
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'powershellgallery',
|
||||
value: 'v1.2-beta',
|
||||
colorB: colorscheme.yellow.colorB,
|
||||
})
|
||||
|
||||
t.create('version (mocked, orange badge)')
|
||||
.get('/v/ACMESharp.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(200, nuGetV2VersionJsonFirstCharZero)
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'powershellgallery',
|
||||
value: 'v0.35',
|
||||
colorB: colorscheme.orange.colorB,
|
||||
})
|
||||
|
||||
t.create('version (mocked, blue badge)')
|
||||
.get('/v/ACMESharp.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(200, nuGetV2VersionJsonFirstCharNotZero)
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'powershellgallery',
|
||||
value: 'v1.2.7',
|
||||
colorB: colorscheme.blue.colorB,
|
||||
})
|
||||
|
||||
t.create('version (not found)')
|
||||
.get('/v/not-a-real-package.json')
|
||||
.expectJSON({ name: 'powershellgallery', value: 'not found' })
|
||||
|
||||
t.create('version (connection error)')
|
||||
.get('/v/ACMESharp.json')
|
||||
.networkOff()
|
||||
.expectJSON({ name: 'powershellgallery', value: 'inaccessible' })
|
||||
|
||||
t.create('version (unexpected response)')
|
||||
.get('/v/ACMESharp.json')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(invalidJSON)
|
||||
)
|
||||
.expectJSON({ name: 'powershellgallery', value: 'invalid' })
|
||||
|
||||
// version (pre)
|
||||
.expectJSON({ name: 'powershell gallery', value: 'not found' })
|
||||
|
||||
t.create('version (pre) (valid)')
|
||||
.get('/vpre/ACMESharp.json')
|
||||
.expectJSONTypes(
|
||||
Joi.object().keys({
|
||||
name: 'powershellgallery',
|
||||
name: 'powershell gallery',
|
||||
value: isVPlusDottedVersionNClausesWithOptionalSuffix,
|
||||
})
|
||||
)
|
||||
|
||||
t.create('version (pre) (mocked, yellow badge)')
|
||||
.get('/vpre/ACMESharp.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsAbsoluteLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(200, nuGetV2VersionJsonWithDash)
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'powershellgallery',
|
||||
value: 'v1.2-beta',
|
||||
colorB: colorscheme.yellow.colorB,
|
||||
})
|
||||
|
||||
t.create('version (pre) (mocked, orange badge)')
|
||||
.get('/vpre/ACMESharp.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsAbsoluteLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(200, nuGetV2VersionJsonFirstCharZero)
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'powershellgallery',
|
||||
value: 'v0.35',
|
||||
colorB: colorscheme.orange.colorB,
|
||||
})
|
||||
|
||||
t.create('version (pre) (mocked, blue badge)')
|
||||
.get('/vpre/ACMESharp.json?style=_shields_test')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsAbsoluteLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(200, nuGetV2VersionJsonFirstCharNotZero)
|
||||
)
|
||||
.expectJSON({
|
||||
name: 'powershellgallery',
|
||||
value: 'v1.2.7',
|
||||
colorB: colorscheme.blue.colorB,
|
||||
})
|
||||
|
||||
t.create('version (pre) (not found)')
|
||||
.get('/vpre/not-a-real-package.json')
|
||||
.expectJSON({ name: 'powershellgallery', value: 'not found' })
|
||||
|
||||
t.create('version (pre) (connection error)')
|
||||
.get('/vpre/ACMESharp.json')
|
||||
.networkOff()
|
||||
.expectJSON({ name: 'powershellgallery', value: 'inaccessible' })
|
||||
|
||||
t.create('version (pre) (unexpected response)')
|
||||
.get('/vpre/ACMESharp.json')
|
||||
.intercept(nock =>
|
||||
nock('https://msconfiggallery.cloudapp.net')
|
||||
.get(
|
||||
'/api/v2/Packages()?$filter=Id%20eq%20%27ACMESharp%27%20and%20IsAbsoluteLatestVersion%20eq%20true'
|
||||
)
|
||||
.reply(invalidJSON)
|
||||
)
|
||||
.expectJSON({ name: 'powershellgallery', value: 'invalid' })
|
||||
.expectJSON({ name: 'powershell gallery', value: 'not found' })
|
||||
|
||||
Reference in New Issue
Block a user