Convert vpre routes to include_prereleases param in [bower chocolatey clojars packagist powershellgallery pub resharper] (#4436)

* Convert vpre routes to include_prereleases param
* add .expectRedirect() helper
* test redirects on SVG endpoint
This commit is contained in:
chris48s
2019-12-23 20:47:35 +00:00
committed by GitHub
parent 8056706316
commit 1a98b6bc31
19 changed files with 294 additions and 154 deletions

View File

@@ -51,6 +51,10 @@ const factory = superclass =>
})
}
expectRedirect(location) {
return this.expectStatus(301).expectHeader('Location', location)
}
static _expectField(json, name, expected) {
if (typeof expected === 'undefined') return
if (typeof expected === 'string' || typeof expected === 'number') {

View File

@@ -1,33 +1,38 @@
'use strict'
const Joi = require('@hapi/joi')
const { renderVersionBadge } = require('../version')
const BaseBowerService = require('./bower-base')
const { InvalidResponse } = require('..')
const { InvalidResponse, redirector } = require('..')
module.exports = class BowerVersion extends BaseBowerService {
const queryParamSchema = Joi.object({
include_prereleases: Joi.equal(''),
}).required()
class BowerVersion extends BaseBowerService {
static get category() {
return 'version'
}
static get route() {
return {
base: 'bower',
pattern: ':vtype(v|vpre)/:packageName',
base: 'bower/v',
pattern: ':packageName',
queryParamSchema,
}
}
static get examples() {
return [
{
title: 'Bower',
title: 'Bower Version',
namedParams: { packageName: 'bootstrap' },
pattern: 'v/:packageName',
staticPreview: renderVersionBadge({ version: '4.2.1' }),
},
{
title: 'Bower Pre Release',
title: 'Bower Version (including pre-releases)',
namedParams: { packageName: 'bootstrap' },
pattern: 'vpre/:packageName',
queryParams: { include_prereleases: null },
staticPreview: renderVersionBadge({ version: '4.2.1' }),
},
]
@@ -37,18 +42,34 @@ module.exports = class BowerVersion extends BaseBowerService {
return { label: 'bower' }
}
async handle({ vtype, packageName }) {
async handle({ packageName }, queryParams) {
const data = await this.fetch({ packageName })
const includePrereleases = queryParams.include_prereleases !== undefined
if (vtype === 'v') {
if (data.latest_stable_release) {
return renderVersionBadge({ version: data.latest_stable_release.name })
}
} else {
if (includePrereleases) {
if (data.latest_release_number) {
return renderVersionBadge({ version: data.latest_release_number })
}
} else {
if (data.latest_stable_release) {
return renderVersionBadge({ version: data.latest_stable_release.name })
}
}
throw new InvalidResponse({ prettyMessage: 'no releases' })
}
}
const BowerVersionRedirect = redirector({
category: 'version',
route: {
base: 'bower/vpre',
pattern: ':packageName',
},
transformPath: ({ packageName }) => `/bower/v/${packageName}`,
transformQueryParams: params => ({
include_prereleases: null,
}),
dateAdded: new Date('2019-12-15'),
})
module.exports = { BowerVersion, BowerVersionRedirect }

View File

@@ -2,7 +2,12 @@
const Joi = require('@hapi/joi')
const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
const t = (module.exports = require('../tester').createServiceTester())
const { ServiceTester } = require('../tester')
const t = (module.exports = new ServiceTester({
id: 'BowerVersion',
title: 'Bower Version',
pathPrefix: '/bower',
}))
const isBowerPrereleaseVersion = Joi.string().regex(
/^v\d+(\.\d+)?(\.\d+)?(-?[.\w\d])+?$/
@@ -18,7 +23,7 @@ t.create('version')
t.create('pre version') // e.g. bower|v0.2.5-alpha-rc-pre
.timeout(10000)
.get('/vpre/bootstrap.json')
.get('/v/bootstrap.json?include_prereleases')
.expectBadge({
label: 'bower',
message: isBowerPrereleaseVersion,
@@ -31,7 +36,7 @@ t.create('Version for Invalid Package')
t.create('Pre Version for Invalid Package')
.timeout(10000)
.get('/vpre/it-is-a-invalid-package-should-error.json')
.get('/v/it-is-a-invalid-package-should-error.json?include_prereleases')
.expectBadge({ label: 'bower', message: 'package not found' })
t.create('Version label should be `no releases` if no stable version')
@@ -44,10 +49,14 @@ t.create('Version label should be `no releases` if no stable version')
.expectBadge({ label: 'bower', message: 'no releases' })
t.create('Version label should be `no releases` if no pre-release')
.get('/vpre/bootstrap.json')
.get('/v/bootstrap.json?include_prereleases')
.intercept(nock =>
nock('https://libraries.io')
.get('/api/bower/bootstrap')
.reply(200, { normalized_licenses: [], latest_release_number: null })
)
.expectBadge({ label: 'bower', message: 'no releases' })
t.create('Version (legacy redirect: vpre)')
.get('/vpre/bootstrap.svg', { followRedirect: false })
.expectRedirect('/bower/v/bootstrap.svg?include_prereleases')

View File

@@ -41,12 +41,16 @@ t.create('version (not found)')
// version (pre)
t.create('version (pre) (valid)')
.get('/vpre/scriptcs.json')
.get('/v/scriptcs.json?include_prereleases')
.expectBadge({
label: 'chocolatey',
message: isVPlusDottedVersionNClausesWithOptionalSuffix,
})
t.create('version (pre) (not found)')
.get('/vpre/not-a-real-package.json')
.get('/v/not-a-real-package.json?include_prereleases')
.expectBadge({ label: 'chocolatey', message: 'not found' })
t.create('version (legacy redirect: vpre)')
.get('/vpre/scriptcs.svg', { followRedirect: false })
.expectRedirect('/chocolatey/v/scriptcs.svg?include_prereleases')

View File

@@ -1,7 +1,6 @@
'use strict'
const Joi = require('@hapi/joi')
const { version: versionColor } = require('../color-formatters')
const { nonNegativeInteger } = require('../validators')
const { BaseJsonService } = require('..')
@@ -22,30 +21,4 @@ class BaseClojarsService extends BaseJsonService {
}
}
class BaseClojarsVersionService extends BaseClojarsService {
static get category() {
return 'version'
}
static get examples() {
return [
{
namedParams: { clojar: 'prismic' },
staticPreview: this.render({ clojar: 'clojar', version: '1.2' }),
},
]
}
static get defaultBadgeData() {
return { label: 'clojars' }
}
static render({ clojar, version }) {
return {
message: `[${clojar} "${version}"]`,
color: versionColor(version),
}
}
}
module.exports = { BaseClojarsService, BaseClojarsVersionService }
module.exports = { BaseClojarsService }

View File

@@ -1,20 +0,0 @@
'use strict'
const { BaseClojarsVersionService } = require('./clojars-base')
module.exports = class ClojarsVersionRelease extends BaseClojarsVersionService {
static get route() {
return {
base: 'clojars/v',
pattern: ':clojar+',
}
}
async handle({ clojar }) {
const json = await this.fetch({ clojar })
return this.constructor.render({
clojar,
version: json.latest_release ? json.latest_release : json.latest_version,
})
}
}

View File

@@ -1,14 +0,0 @@
'use strict'
const t = (module.exports = require('../tester').createServiceTester())
t.create('clojars (valid)')
.get('/prismic.json')
.expectBadge({
label: 'clojars',
message: /^\[prismic "([0-9][.]?)+"\]$/, // note: https://github.com/badges/shields/pull/431
})
t.create('clojars (not found)')
.get('/not-a-package.json')
.expectBadge({ label: 'clojars', message: 'not found' })

View File

@@ -1,17 +0,0 @@
'use strict'
const { BaseClojarsVersionService } = require('./clojars-base')
module.exports = class ClojarsVersionSnapshot extends BaseClojarsVersionService {
static get route() {
return {
base: 'clojars/vpre',
pattern: ':clojar+',
}
}
async handle({ clojar }) {
const json = await this.fetch({ clojar })
return this.constructor.render({ clojar, version: json.latest_version })
}
}

View File

@@ -1,14 +0,0 @@
'use strict'
const t = (module.exports = require('../tester').createServiceTester())
t.create('clojars (valid)')
.get('/prismic.json')
.expectBadge({
label: 'clojars',
message: /^\[prismic "([0-9][.]?)+"\]$/, // note: https://github.com/badges/shields/pull/431
})
t.create('clojars (not found)')
.get('/not-a-package.json')
.expectBadge({ label: 'clojars', message: 'not found' })

View File

@@ -0,0 +1,79 @@
'use strict'
const Joi = require('@hapi/joi')
const { version: versionColor } = require('../color-formatters')
const { BaseClojarsService } = require('./clojars-base')
const { redirector } = require('..')
const queryParamSchema = Joi.object({
include_prereleases: Joi.equal(''),
}).required()
class ClojarsVersionService extends BaseClojarsService {
static get category() {
return 'version'
}
static get route() {
return {
base: 'clojars/v',
pattern: ':clojar+',
queryParamSchema,
}
}
static get examples() {
return [
{
title: 'Clojars Version',
namedParams: { clojar: 'prismic' },
staticPreview: this.render({ clojar: 'clojar', version: '1.2' }),
},
{
title: 'Clojars Version (including pre-releases)',
namedParams: { clojar: 'prismic' },
queryParams: { include_prereleases: null },
staticPreview: this.render({ clojar: 'clojar', version: '1.2' }),
},
]
}
static get defaultBadgeData() {
return { label: 'clojars' }
}
static render({ clojar, version }) {
return {
message: `[${clojar} "${version}"]`,
color: versionColor(version),
}
}
async handle({ clojar }, queryParams) {
const json = await this.fetch({ clojar })
const includePrereleases = queryParams.include_prereleases !== undefined
if (includePrereleases) {
return this.constructor.render({ clojar, version: json.latest_version })
}
return this.constructor.render({
clojar,
version: json.latest_release ? json.latest_release : json.latest_version,
})
}
}
const ClojarsVersionRedirector = redirector({
category: 'version',
route: {
base: 'clojars/vpre',
pattern: ':clojar',
},
transformPath: ({ clojar }) => `/clojars/v/${clojar}`,
transformQueryParams: params => ({
include_prereleases: null,
}),
dateAdded: new Date('2019-12-15'),
})
module.exports = { ClojarsVersionService, ClojarsVersionRedirector }

View File

@@ -0,0 +1,30 @@
'use strict'
const { ServiceTester } = require('../tester')
const t = (module.exports = new ServiceTester({
id: 'ClojarsVersion',
title: 'Clojars Version',
pathPrefix: '/clojars',
}))
t.create('clojars version (valid)')
.get('/v/prismic.json')
.expectBadge({
label: 'clojars',
message: /^\[prismic "([0-9][.]?)+"\]$/, // note: https://github.com/badges/shields/pull/431
})
t.create('clojars version (pre) (valid)')
.get('/v/prismic.json?include_prereleases')
.expectBadge({
label: 'clojars',
message: /^\[prismic "([0-9][.]?)+"\]$/, // note: https://github.com/badges/shields/pull/431
})
t.create('clojars version (not found)')
.get('/v/not-a-package.json')
.expectBadge({ label: 'clojars', message: 'not found' })
t.create('version (legacy redirect: vpre)')
.get('/vpre/prismic.svg', { followRedirect: false })
.expectRedirect('/clojars/v/prismic.svg?include_prereleases')

View File

@@ -7,7 +7,7 @@ const {
renderDownloadBadge,
odataToObject,
} = require('./nuget-helpers')
const { BaseJsonService, BaseXmlService, NotFound } = require('..')
const { BaseJsonService, BaseXmlService, NotFound, redirector } = require('..')
function createFilter({ packageName, includePrereleases }) {
const releaseTypeFilter = includePrereleases
@@ -44,6 +44,10 @@ const xmlSchema = Joi.object({
}).required(),
}).required()
const queryParamSchema = Joi.object({
include_prereleases: Joi.equal(''),
}).required()
async function fetch(
serviceInstance,
{ odataFormat, baseUrl, packageName, includePrereleases = false }
@@ -127,8 +131,9 @@ function createServiceFamily({
static get route() {
return {
base: serviceBaseUrl,
pattern: ':variant(v|vpre)/:packageName',
base: `${serviceBaseUrl}/v`,
pattern: ':packageName',
queryParamSchema,
}
}
@@ -137,15 +142,14 @@ function createServiceFamily({
return [
{
title,
pattern: 'v/:packageName',
title: `${title} Version`,
namedParams: { packageName: examplePackageName },
staticPreview: this.render({ version: exampleVersion }),
},
{
title: `${title} (with prereleases)`,
pattern: 'vpre/:packageName',
title: `${title} Version (including pre-releases)`,
namedParams: { packageName: examplePackageName },
queryParams: { include_prereleases: null },
staticPreview: this.render({ version: examplePrereleaseVersion }),
},
]
@@ -161,18 +165,31 @@ function createServiceFamily({
return renderVersionBadge(props)
}
async handle({ variant, packageName }) {
async handle({ packageName }, queryParams) {
const packageData = await fetch(this, {
odataFormat,
baseUrl: apiBaseUrl,
packageName,
includePrereleases: variant === 'vpre',
includePrereleases: queryParams.include_prereleases !== undefined,
})
const version = packageData.NormalizedVersion || packageData.Version
return this.constructor.render({ version })
}
}
const NugetVersionRedirector = redirector({
category: 'version',
route: {
base: `${serviceBaseUrl}/vpre`,
pattern: ':packageName',
},
transformPath: ({ packageName }) => `/${serviceBaseUrl}/v/${packageName}`,
transformQueryParams: params => ({
include_prereleases: null,
}),
dateAdded: new Date('2019-12-15'),
})
class NugetDownloadService extends Base {
static get name() {
return `${name}Downloads`
@@ -216,7 +233,7 @@ function createServiceFamily({
}
}
return { NugetVersionService, NugetDownloadService }
return { NugetVersionService, NugetVersionRedirector, NugetDownloadService }
}
module.exports = {

View File

@@ -10,7 +10,7 @@ const {
BasePackagistService,
customServerDocumentationFragment,
} = require('./packagist-base')
const { NotFound } = require('..')
const { NotFound, redirector } = require('..')
const packageSchema = Joi.object()
.pattern(
@@ -32,17 +32,18 @@ const schema = Joi.object({
const queryParamSchema = Joi.object({
server: optionalUrl,
include_prereleases: Joi.equal(''),
}).required()
module.exports = class PackagistVersion extends BasePackagistService {
class PackagistVersion extends BasePackagistService {
static get category() {
return 'version'
}
static get route() {
return {
base: 'packagist',
pattern: ':type(v|vpre)/:user/:repo',
base: 'packagist/v',
pattern: ':user/:repo',
queryParamSchema,
}
}
@@ -51,7 +52,6 @@ module.exports = class PackagistVersion extends BasePackagistService {
return [
{
title: 'Packagist Version',
pattern: 'v/:user/:repo',
namedParams: {
user: 'symfony',
repo: 'symfony',
@@ -60,18 +60,17 @@ module.exports = class PackagistVersion extends BasePackagistService {
keywords,
},
{
title: 'Packagist Pre Release Version',
pattern: 'vpre/:user/:repo',
title: 'Packagist Version (including pre-releases)',
namedParams: {
user: 'symfony',
repo: 'symfony',
},
queryParams: { include_prereleases: null },
staticPreview: renderVersionBadge({ version: '4.3-dev' }),
keywords,
},
{
title: 'Packagist Version (custom server)',
pattern: 'v/:user/:repo',
namedParams: {
user: 'symfony',
repo: 'symfony',
@@ -99,7 +98,7 @@ module.exports = class PackagistVersion extends BasePackagistService {
return renderVersionBadge({ version })
}
transform({ type, json, user, repo }) {
transform({ includePrereleases, json, user, repo }) {
const versionsData = json.packages[this.getPackageName(user, repo)]
let versions = Object.keys(versionsData)
const aliasesMap = {}
@@ -124,7 +123,7 @@ module.exports = class PackagistVersion extends BasePackagistService {
versions = versions.filter(version => !/^dev-/.test(version))
if (type === 'vpre') {
if (includePrereleases) {
return { version: latest(versions) }
} else {
const stableVersion = latest(versions.filter(isStable))
@@ -132,14 +131,28 @@ module.exports = class PackagistVersion extends BasePackagistService {
}
}
async handle({ type, user, repo }, { server }) {
async handle({ user, repo }, { include_prereleases, server }) {
const includePrereleases = include_prereleases !== undefined
const json = await this.fetch({
user,
repo,
schema: type === 'v' ? allVersionsSchema : schema,
schema: includePrereleases ? schema : allVersionsSchema,
server,
})
const { version } = this.transform({ type, json, user, repo })
const { version } = this.transform({ includePrereleases, json, user, repo })
return this.constructor.render({ version })
}
}
const PackagistVersionRedirector = redirector({
category: 'version',
route: {
base: 'packagist/vpre',
pattern: ':user/:repo',
},
transformPath: ({ user, repo }) => `/packagist/v/${user}/${repo}`,
transformQueryParams: params => ({ include_prereleases: null }),
dateAdded: new Date('2019-12-15'),
})
module.exports = { PackagistVersion, PackagistVersionRedirector }

View File

@@ -4,7 +4,12 @@ const Joi = require('@hapi/joi')
const {
isVPlusDottedVersionNClausesWithOptionalSuffix,
} = require('../test-validators')
const t = (module.exports = require('../tester').createServiceTester())
const { ServiceTester } = require('../tester')
const t = (module.exports = new ServiceTester({
id: 'packagist',
title: 'Packagist Version',
pathPrefix: '/packagist',
}))
/*
validator for a packagist version number
@@ -35,7 +40,7 @@ t.create('version (invalid package name)')
.expectBadge({ label: 'packagist', message: 'not found' })
t.create('pre-release version (valid)')
.get('/vpre/symfony/symfony.json')
.get('/v/symfony/symfony.json?include_prereleases')
.expectBadge({
label: 'packagist',
message: isVPlusDottedVersionNClausesWithOptionalSuffix,
@@ -51,3 +56,15 @@ t.create('version (valid custom server)')
t.create('version (invalid custom server)')
.get('/v/symfony/symfony.json?server=https%3A%2F%2Fpackagist.com')
.expectBadge({ label: 'packagist', message: 'not found' })
t.create('version (legacy redirect: vpre)')
.get('/vpre/symfony/symfony.svg', { followRedirect: false })
.expectRedirect('/packagist/v/symfony/symfony.svg?include_prereleases')
t.create('version (legacy redirect: vpre) (custom server)')
.get('/vpre/symfony/symfony.svg?server=https%3A%2F%2Fpackagist.org', {
followRedirect: false,
})
.expectRedirect(
'/packagist/v/symfony/symfony.svg?include_prereleases&server=https%3A%2F%2Fpackagist.org'
)

View File

@@ -14,6 +14,7 @@ const apiBaseUrl = 'https://www.powershellgallery.com/api/v2'
const {
NugetVersionService: PowershellGalleryVersion,
NugetVersionRedirector: PowershellGalleryVersionRedirector,
NugetDownloadService: PowershellGalleryDownloads,
} = createServiceFamily({
name: 'PowershellGallery',
@@ -106,6 +107,7 @@ class PowershellGalleryPlatformSupport extends BaseXmlService {
module.exports = {
PowershellGalleryVersion,
PowershellGalleryVersionRedirector,
PowershellGalleryDownloads,
PowershellGalleryPlatformSupport,
}

View File

@@ -40,16 +40,20 @@ t.create('version (not found)')
.expectBadge({ label: 'powershell gallery', message: 'not found' })
t.create('version (pre) (valid)')
.get('/vpre/ACMESharp.json')
.get('/v/ACMESharp.json?include_prereleases')
.expectBadge({
label: 'powershell gallery',
message: isVPlusDottedVersionNClausesWithOptionalSuffix,
})
t.create('version (pre) (not found)')
.get('/vpre/not-a-real-package.json')
.get('/v/not-a-real-package.json?include_prereleases')
.expectBadge({ label: 'powershell gallery', message: 'not found' })
t.create('version (legacy redirect: vpre)')
.get('/vpre/ACMESharp.svg', { followRedirect: false })
.expectRedirect('/powershellgallery/v/ACMESharp.svg?include_prereleases')
t.create('platform (valid')
.get('/p/DNS.1.1.1.1.json')
.expectBadge({

View File

@@ -2,7 +2,7 @@
const Joi = require('@hapi/joi')
const { latest, renderVersionBadge } = require('../version')
const { BaseJsonService } = require('..')
const { BaseJsonService, redirector } = require('..')
const schema = Joi.object({
versions: Joi.array()
@@ -10,31 +10,35 @@ const schema = Joi.object({
.required(),
}).required()
module.exports = class PubVersion extends BaseJsonService {
const queryParamSchema = Joi.object({
include_prereleases: Joi.equal(''),
}).required()
class PubVersion extends BaseJsonService {
static get category() {
return 'version'
}
static get route() {
return {
base: 'pub',
pattern: ':variant(v|vpre)/:packageName',
base: 'pub/v',
pattern: ':packageName',
queryParamSchema,
}
}
static get examples() {
return [
{
title: 'Pub',
pattern: 'v/:packageName',
title: 'Pub Version',
namedParams: { packageName: 'box2d' },
staticPreview: renderVersionBadge({ version: 'v0.4.0' }),
keywords: ['dart', 'dartlang'],
},
{
title: 'Pub',
pattern: 'vpre/:packageName',
title: 'Pub Version (including pre-releases)',
namedParams: { packageName: 'box2d' },
queryParams: { include_prereleases: null },
staticPreview: renderVersionBadge({ version: 'v0.4.0' }),
keywords: ['dart', 'dartlang'],
},
@@ -52,11 +56,26 @@ module.exports = class PubVersion extends BaseJsonService {
})
}
async handle({ variant, packageName }) {
async handle({ packageName }, queryParams) {
const data = await this.fetch({ packageName })
const includePre = variant === 'vpre'
const includePre = queryParams.include_prereleases !== undefined
const versions = data.versions
const version = latest(versions, { pre: includePre })
return renderVersionBadge({ version })
}
}
const PubVersionRedirector = redirector({
category: 'version',
route: {
base: 'pub/vpre',
pattern: ':packageName',
},
transformPath: ({ packageName }) => `/pub/v/${packageName}`,
transformQueryParams: params => ({
include_prereleases: null,
}),
dateAdded: new Date('2019-12-15'),
})
module.exports = { PubVersion, PubVersionRedirector }

View File

@@ -1,7 +1,12 @@
'use strict'
const { isVPlusTripleDottedVersion } = require('../test-validators')
const t = (module.exports = require('../tester').createServiceTester())
const { ServiceTester } = require('../tester')
const t = (module.exports = new ServiceTester({
id: 'PubVersion',
title: 'Pub Version',
pathPrefix: '/pub',
}))
t.create('package version')
.get('/v/box2d.json')
@@ -11,7 +16,7 @@ t.create('package version')
})
t.create('package pre-release version')
.get('/vpre/box2d.json')
.get('/v/box2d.json?include_prereleases')
.expectBadge({
label: 'pub',
message: isVPlusTripleDottedVersion,
@@ -23,3 +28,7 @@ t.create('package not found')
label: 'pub',
message: 'not found',
})
t.create('package version (legacy redirect: vpre)')
.get('/vpre/box2d.svg', { followRedirect: false })
.expectRedirect('/pub/v/box2d.svg?include_prereleases')

View File

@@ -41,12 +41,16 @@ t.create('version (not found)')
// version (pre)
t.create('version (pre) (valid)')
.get('/vpre/ReSharper.Nuke.json')
.get('/v/ReSharper.Nuke.json?include_prereleases')
.expectBadge({
label: 'resharper',
message: isVPlusDottedVersionNClausesWithOptionalSuffix,
})
t.create('version (pre) (not found)')
.get('/vpre/not-a-real-package.json')
.get('/v/not-a-real-package.json?include_prereleases')
.expectBadge({ label: 'resharper', message: 'not found' })
t.create('version (legacy redirect: vpre)')
.get('/vpre/ReSharper.Nuke.svg', { followRedirect: false })
.expectRedirect('/resharper/v/ReSharper.Nuke.svg?include_prereleases')