fix: [node npm] service has bad colors #4809 (#4810)

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* fix: node service has bad colors #4809

* chore: minor service test rename

Co-authored-by: Caleb Cartwright <calebcartwright@users.noreply.github.com>
This commit is contained in:
Regev Brody
2020-04-05 05:21:08 +03:00
committed by GitHub
parent e92cb574a2
commit 15cbbe828e
13 changed files with 729 additions and 76 deletions

View File

@@ -1,23 +1,24 @@
'use strict'
const NPMBase = require('../npm/npm-base')
const { versionColorForRange } = require('./node-version-color')
const keywords = ['npm']
module.exports = class NodeVersion extends NPMBase {
module.exports = class NodeVersionBase extends NPMBase {
static get category() {
return 'platform-support'
}
static get route() {
return this.buildRoute('node/v', { withTag: true })
return this.buildRoute(`node/${this.path}`, { withTag: true })
}
static get examples() {
const type = this.type
const prefix = `node-${type}`
return [
{
title: 'node',
title: `${prefix}`,
pattern: ':packageName',
namedParams: { packageName: 'passport' },
staticPreview: this.renderStaticPreview({
@@ -26,7 +27,7 @@ module.exports = class NodeVersion extends NPMBase {
keywords,
},
{
title: 'node (scoped)',
title: `${prefix} (scoped)`,
pattern: '@:scope/:packageName',
namedParams: { scope: 'stdlib', packageName: 'stdlib' },
staticPreview: this.renderStaticPreview({
@@ -35,7 +36,7 @@ module.exports = class NodeVersion extends NPMBase {
keywords,
},
{
title: 'node (tag)',
title: `${prefix} (tag)`,
pattern: ':packageName/:tag',
namedParams: { packageName: 'passport', tag: 'latest' },
staticPreview: this.renderStaticPreview({
@@ -45,7 +46,7 @@ module.exports = class NodeVersion extends NPMBase {
keywords,
},
{
title: 'node (scoped with tag)',
title: `${prefix} (scoped with tag)`,
pattern: '@:scope/:packageName/:tag',
namedParams: { scope: 'stdlib', packageName: 'stdlib', tag: 'latest' },
staticPreview: this.renderStaticPreview({
@@ -55,7 +56,7 @@ module.exports = class NodeVersion extends NPMBase {
keywords,
},
{
title: 'node (scoped with tag, custom registry)',
title: `${prefix} (scoped with tag, custom registry)`,
pattern: '@:scope/:packageName/:tag',
namedParams: { scope: 'stdlib', packageName: 'stdlib', tag: 'latest' },
queryParams: { registry_uri: 'https://registry.npmjs.com' },
@@ -68,16 +69,12 @@ module.exports = class NodeVersion extends NPMBase {
]
}
static get defaultBadgeData() {
return { label: 'node' }
}
static renderStaticPreview({ tag, nodeVersionRange }) {
// Since this badge has an async `render()` function, but `get examples()` has to
// be synchronous, this method exists. It should return the same value as the
// real `render()`. There's a unit test to check that.
return {
label: tag ? `node@${tag}` : undefined,
label: tag ? `${this.defaultBadgeData.label}@${tag}` : undefined,
message: nodeVersionRange,
color: 'brightgreen',
}
@@ -86,7 +83,7 @@ module.exports = class NodeVersion extends NPMBase {
static async render({ tag, nodeVersionRange }) {
// Atypically, the `render()` function of this badge is `async` because it needs to pull
// data from the server.
const label = tag ? `node@${tag}` : undefined
const label = tag ? `${this.defaultBadgeData.label}@${tag}` : undefined
if (nodeVersionRange === undefined) {
return {
@@ -98,7 +95,7 @@ module.exports = class NodeVersion extends NPMBase {
return {
label,
message: nodeVersionRange,
color: await versionColorForRange(nodeVersionRange),
color: await this.colorResolver(nodeVersionRange),
}
}
}

View File

@@ -0,0 +1,22 @@
'use strict'
const NodeVersionBase = require('./node-base')
const { versionColorForRangeCurrent } = require('./node-version-color')
module.exports = class NodeCurrentVersion extends NodeVersionBase {
static get path() {
return 'v'
}
static get defaultBadgeData() {
return { label: 'node' }
}
static get type() {
return 'current'
}
static get colorResolver() {
return versionColorForRangeCurrent
}
}

View File

@@ -0,0 +1,23 @@
'use strict'
const { test, given } = require('sazerac')
const NodeVersion = require('./node-current.service')
describe('node static renderStaticPreview', function() {
it('should have parity with render()', async function() {
const nodeVersionRange = '>= 6.0.0'
const expectedNoTag = await NodeVersion.renderStaticPreview({
nodeVersionRange,
})
const expectedLatestTag = await NodeVersion.renderStaticPreview({
nodeVersionRange,
tag: 'latest',
})
test(NodeVersion.renderStaticPreview.bind(NodeVersion), () => {
given({ nodeVersionRange }).expect(expectedNoTag)
given({ nodeVersionRange, tag: 'latest' }).expect(expectedLatestTag)
})
})
})

View File

@@ -0,0 +1,157 @@
'use strict'
const { expect } = require('chai')
const { Range } = require('semver')
const t = (module.exports = require('../tester').createServiceTester())
const { mockPackageData, mockCurrentSha } = require('./testUtils/test-utils')
function expectSemverRange(message) {
expect(() => new Range(message)).not.to.throw()
}
t.create('gets the node version of passport')
.get('/passport.json')
.expectBadge({ label: 'node' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies current node version')
.get('/passport.json')
.intercept(
mockPackageData({
packageName: 'passport',
engines: '>=0.4.0',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({ label: 'node', message: `>=0.4.0`, color: `brightgreen` })
t.create('engines does not satisfy current node version')
.get('/passport.json')
.intercept(
mockPackageData({
packageName: 'passport',
engines: '12',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({ label: 'node', message: `12`, color: `yellow` })
t.create('gets the node version of @stdlib/stdlib')
.get('/@stdlib/stdlib.json')
.expectBadge({ label: 'node' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies current node version - scoped')
.get('/@stdlib/stdlib.json')
.intercept(
mockPackageData({
packageName: 'stdlib',
engines: '>=0.4.0',
scope: '@stdlib',
tag: '',
registry: '',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({ label: 'node', message: `>=0.4.0`, color: `brightgreen` })
t.create('engines does not satisfy current node version - scoped')
.get('/@stdlib/stdlib.json')
.intercept(
mockPackageData({
packageName: 'stdlib',
engines: '12',
scope: '@stdlib',
tag: '',
registry: '',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({ label: 'node', message: `12`, color: `yellow` })
t.create("gets the tagged release's node version version of ionic")
.get('/ionic/testing.json')
.expectBadge({ label: 'node@testing' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies current node version - tagged')
.get('/ionic/testing.json')
.intercept(
mockPackageData({
packageName: 'ionic',
engines: '>=0.4.0',
tag: 'testing',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({
label: 'node@testing',
message: `>=0.4.0`,
color: `brightgreen`,
})
t.create('engines does not satisfy current node version - tagged')
.get('/ionic/testing.json')
.intercept(
mockPackageData({
packageName: 'ionic',
engines: '12',
tag: 'testing',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({ label: 'node@testing', message: `12`, color: `yellow` })
t.create("gets the tagged release's node version of @cycle/core")
.get('/@cycle/core/canary.json')
.expectBadge({ label: 'node@canary' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies current node version - scoped and tagged')
.get('/@cycle/core/canary.json')
.intercept(
mockPackageData({
packageName: 'core',
engines: '>=0.4.0',
scope: '@cycle',
tag: 'canary',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({
label: 'node@canary',
message: `>=0.4.0`,
color: `brightgreen`,
})
t.create('engines does not satisfy current node version - scoped and tagged')
.get('/@cycle/core/canary.json')
.intercept(
mockPackageData({
packageName: 'core',
engines: '12',
scope: '@cycle',
tag: 'canary',
})
)
.intercept(mockCurrentSha(13))
.expectBadge({ label: 'node@canary', message: `12`, color: `yellow` })
t.create('gets the node version of passport from a custom registry')
.get('/passport.json?registry_uri=https://registry.npmjs.com')
.expectBadge({ label: 'node' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('invalid package name')
.get('/frodo-is-not-a-package.json')
.expectBadge({ label: 'node', message: 'package not found' })

View File

@@ -0,0 +1,22 @@
'use strict'
const NodeVersionBase = require('./node-base')
const { versionColorForRangeLts } = require('./node-version-color')
module.exports = class NodeLtsVersion extends NodeVersionBase {
static get path() {
return 'v-lts'
}
static get defaultBadgeData() {
return { label: 'node-lts' }
}
static get type() {
return 'lts'
}
static get colorResolver() {
return versionColorForRangeLts
}
}

View File

@@ -1,9 +1,9 @@
'use strict'
const { test, given } = require('sazerac')
const NodeVersion = require('./node.service')
const NodeVersion = require('./node-lts.service')
describe('renderStaticPreview', function() {
describe('node-lts renderStaticPreview', function() {
it('should have parity with render()', async function() {
const nodeVersionRange = '>= 6.0.0'
@@ -15,7 +15,7 @@ describe('renderStaticPreview', function() {
tag: 'latest',
})
test(NodeVersion.renderStaticPreview, () => {
test(NodeVersion.renderStaticPreview.bind(NodeVersion), () => {
given({ nodeVersionRange }).expect(expectedNoTag)
given({ nodeVersionRange, tag: 'latest' }).expect(expectedLatestTag)
})

View File

@@ -0,0 +1,217 @@
'use strict'
const { expect } = require('chai')
const { Range } = require('semver')
const t = (module.exports = require('../tester').createServiceTester())
const {
mockPackageData,
mockReleaseSchedule,
mockVersionsSha,
} = require('./testUtils/test-utils')
function expectSemverRange(message) {
expect(() => new Range(message)).not.to.throw()
}
t.create('gets the node version of passport')
.get('/passport.json')
.expectBadge({ label: 'node-lts' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies all lts node versions')
.get('/passport.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'passport',
engines: '10 - 12',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts', message: `10 - 12`, color: `brightgreen` })
t.create('engines does not satisfy all lts node versions')
.get('/passport.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'passport',
engines: '8',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts', message: `8`, color: `orange` })
t.create('engines satisfies some lts node versions')
.get('/passport.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'passport',
engines: '10',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts', message: `10`, color: `yellow` })
t.create('gets the node version of @stdlib/stdlib')
.get('/@stdlib/stdlib.json')
.expectBadge({ label: 'node-lts' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies all lts node versions - scoped')
.get('/@stdlib/stdlib.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'stdlib',
engines: '10 - 12',
scope: '@stdlib',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts', message: `10 - 12`, color: `brightgreen` })
t.create('engines does not satisfy all lts node versions - scoped')
.get('/@stdlib/stdlib.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'stdlib',
engines: '8',
scope: '@stdlib',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts', message: `8`, color: `orange` })
t.create('engines satisfies some lts node versions - scoped')
.get('/@stdlib/stdlib.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'stdlib',
engines: '10',
scope: '@stdlib',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts', message: `10`, color: `yellow` })
t.create("gets the tagged release's node version version of ionic")
.get('/ionic/testing.json')
.expectBadge({ label: 'node-lts@testing' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies all lts node versions - tagged')
.get('/ionic/testing.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'ionic',
engines: '10 - 12',
tag: 'testing',
})
)
.intercept(mockVersionsSha())
.expectBadge({
label: 'node-lts@testing',
message: `10 - 12`,
color: `brightgreen`,
})
t.create('engines does not satisfy all lts node versions - tagged')
.get('/ionic/testing.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'ionic',
engines: '8',
tag: 'testing',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts@testing', message: `8`, color: `orange` })
t.create('engines satisfies some lts node versions - tagged')
.get('/ionic/testing.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'ionic',
engines: '10',
tag: 'testing',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts@testing', message: `10`, color: `yellow` })
t.create("gets the tagged release's node version of @cycle/core")
.get('/@cycle/core/canary.json')
.expectBadge({ label: 'node-lts@canary' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('engines satisfies all lts node versions - scoped and tagged')
.get('/@cycle/core/canary.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'core',
engines: '10 - 12',
scope: '@cycle',
tag: 'canary',
})
)
.intercept(mockVersionsSha())
.expectBadge({
label: 'node-lts@canary',
message: `10 - 12`,
color: `brightgreen`,
})
t.create('engines does not satisfy all lts node versions - scoped and tagged')
.get('/@cycle/core/canary.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'core',
engines: '8',
scope: '@cycle',
tag: 'canary',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts@canary', message: `8`, color: `orange` })
t.create('engines satisfies some lts node versions - scoped and tagged')
.get('/@cycle/core/canary.json')
.intercept(mockReleaseSchedule())
.intercept(
mockPackageData({
packageName: 'core',
engines: '10',
scope: '@cycle',
tag: 'canary',
})
)
.intercept(mockVersionsSha())
.expectBadge({ label: 'node-lts@canary', message: `10`, color: `yellow` })
t.create('gets the node version of passport from a custom registry')
.get('/passport.json?registry_uri=https://registry.npmjs.com')
.expectBadge({ label: 'node-lts' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('invalid package name')
.get('/frodo-is-not-a-package.json')
.expectBadge({ label: 'node-lts', message: 'package not found' })

View File

@@ -1,12 +1,19 @@
'use strict'
const { promisify } = require('util')
const moment = require('moment')
const semver = require('semver')
const { regularUpdate } = require('../../core/legacy/regular-update')
function getLatestVersion() {
const dateFormat = 'YYYY-MM-DD'
function getVersion(version) {
let semver = ``
if (version) {
semver = `-${version}.x`
}
return promisify(regularUpdate)({
url: 'https://nodejs.org/dist/latest/SHASUMS256.txt',
url: `https://nodejs.org/dist/latest${semver}/SHASUMS256.txt`,
intervalMillis: 24 * 3600 * 1000,
json: false,
scraper: shasums => {
@@ -14,14 +21,57 @@ function getLatestVersion() {
const taris = shasums.indexOf('node-v')
const tarie = shasums.indexOf('\n', taris)
const tarball = shasums.slice(taris, tarie)
const version = tarball.split('-')[1]
return version
return tarball.split('-')[1]
},
})
}
async function versionColorForRange(range) {
const latestVersion = await getLatestVersion()
function ltsVersionsScraper(versions) {
const currentDate = moment().format(dateFormat)
return Object.keys(versions).filter(function(version) {
const data = versions[version]
return data.lts && data.lts < currentDate && data.end > currentDate
})
}
async function getCurrentVersion() {
return getVersion()
}
async function getLtsVersions() {
const versions = await promisify(regularUpdate)({
url:
'https://raw.githubusercontent.com/nodejs/Release/master/schedule.json',
intervalMillis: 24 * 3600 * 1000,
json: true,
scraper: ltsVersionsScraper,
})
return Promise.all(versions.map(getVersion))
}
async function versionColorForRangeLts(range) {
const ltsVersions = await getLtsVersions()
try {
const matchesAll = ltsVersions.reduce(function(satisfies, version) {
return satisfies && semver.satisfies(version, range)
}, true)
const matchesSome = ltsVersions.reduce(function(satisfies, version) {
return satisfies || semver.satisfies(version, range)
}, false)
if (matchesAll) {
return 'brightgreen'
} else if (matchesSome) {
return 'yellow'
} else {
return 'orange'
}
} catch (e) {
return 'lightgray'
}
}
async function versionColorForRangeCurrent(range) {
const latestVersion = await getCurrentVersion()
try {
if (semver.satisfies(latestVersion, range)) {
return 'brightgreen'
@@ -36,6 +86,6 @@ async function versionColorForRange(range) {
}
module.exports = {
getLatestVersion,
versionColorForRange,
versionColorForRangeCurrent,
versionColorForRangeLts,
}

View File

@@ -1,48 +0,0 @@
'use strict'
const { expect } = require('chai')
const { Range } = require('semver')
const t = (module.exports = require('../tester').createServiceTester())
function expectSemverRange(message) {
expect(() => new Range(message)).not.to.throw()
}
t.create('gets the node version of passport')
.get('/passport.json')
.expectBadge({ label: 'node' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('gets the node version of @stdlib/stdlib')
.get('/@stdlib/stdlib.json')
.expectBadge({ label: 'node' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create("gets the tagged release's node version version of ionic")
.get('/ionic/next.json')
.expectBadge({ label: 'node@next' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('gets the node version of passport from a custom registry')
.get('/passport.json?registry_uri=https://registry.npmjs.com')
.expectBadge({ label: 'node' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create("gets the tagged release's node version of @cycle/core")
.get('/@cycle/core/canary.json')
.expectBadge({ label: 'node@canary' })
.afterJSON(json => {
expectSemverRange(json.message)
})
t.create('invalid package name')
.get('/frodo-is-not-a-package.json')
.expectBadge({ label: 'node', message: 'package not found' })

View File

@@ -0,0 +1,11 @@
{
"engines": {
"node": ">= 0.4.0"
},
"maintainers": [
{
"name": "jaredhanson",
"email": "jaredhanson@gmail.com"
}
]
}

View File

@@ -0,0 +1,29 @@
{
"dist-tags": {
"latest": "0.0.91"
},
"versions": {
"0.0.90": {
"engines": {
"node": ">= 0.4.0"
},
"maintainers": [
{
"name": "jaredhanson",
"email": "jaredhanson@gmail.com"
}
]
},
"0.0.91": {
"engines": {
"node": ">= 0.4.0"
},
"maintainers": [
{
"name": "jaredhanson",
"email": "jaredhanson@gmail.com"
}
]
}
}
}

View File

@@ -0,0 +1,169 @@
'use strict'
const fs = require('fs')
const path = require('path')
const moment = require('moment')
const dateFormat = 'YYYY-MM-DD'
const templates = {
packageJsonVersionsTemplate: fs.readFileSync(
path.join(__dirname, `packageJsonVersionsTemplate.json`),
'utf-8'
),
packageJsonTemplate: fs.readFileSync(
path.join(__dirname, `packageJsonTemplate.json`),
'utf-8'
),
}
const getTemplate = template => JSON.parse(templates[template])
const mockPackageData = ({ packageName, engines, scope, tag }) => nock => {
let packageJson
let urlPath
if (scope || tag) {
if (scope) {
urlPath = `/${scope}%2F${packageName}`
} else {
urlPath = `/${packageName}`
}
packageJson = getTemplate('packageJsonVersionsTemplate')
packageJson['dist-tags'][tag || 'latest'] = '0.0.91'
packageJson.versions['0.0.91'].engines.node = engines
} else {
urlPath = `/${packageName}/latest`
packageJson = getTemplate('packageJsonTemplate')
packageJson.engines.node = engines
}
return nock('https://registry.npmjs.org/')
.get(urlPath)
.reply(200, packageJson)
}
const mockCurrentSha = latestVersion => nock => {
const latestSha = `node-v${latestVersion}.12.0-aix-ppc64.tar.gz`
return nock('https://nodejs.org/dist/')
.get(`/latest/SHASUMS256.txt`)
.reply(200, latestSha)
}
const mockVersionsSha = () => nock => {
let scope = nock('https://nodejs.org/dist/')
for (const version of [10, 12]) {
const latestSha = `node-v${version}.12.0-aix-ppc64.tar.gz`
scope = scope
.get(`/latest-v${version}.x/SHASUMS256.txt`)
.reply(200, latestSha)
}
return scope
}
const mockReleaseSchedule = () => nock => {
const currentDate = moment()
const schedule = {
'v0.10': {
start: '2013-03-11',
end: '2016-10-31',
},
'v0.12': {
start: '2015-02-06',
end: '2016-12-31',
},
v4: {
start: '2015-09-08',
lts: '2015-10-12',
maintenance: '2017-04-01',
end: '2018-04-30',
codename: 'Argon',
},
v5: {
start: '2015-10-29',
maintenance: '2016-04-30',
end: '2016-06-30',
},
v6: {
start: '2016-04-26',
lts: '2016-10-18',
maintenance: '2018-04-30',
end: '2019-04-30',
codename: 'Boron',
},
v7: {
start: '2016-10-25',
maintenance: '2017-04-30',
end: '2017-06-30',
},
v8: {
start: '2017-05-30',
lts: '2017-10-31',
maintenance: '2019-01-01',
end: '2019-12-31',
codename: 'Carbon',
},
v9: {
start: '2017-10-01',
maintenance: '2018-04-01',
end: '2018-06-30',
},
v10: {
start: '2018-04-24',
lts: currentDate
.clone()
.subtract(6, 'month')
.format(dateFormat),
maintenance: '2020-04-30',
end: currentDate
.clone()
.add(1, 'month')
.format(dateFormat),
codename: 'Dubnium',
},
v11: {
start: '2018-10-23',
maintenance: '2019-04-22',
end: '2019-06-01',
},
v12: {
start: '2019-04-23',
lts: currentDate
.clone()
.subtract(1, 'month')
.format(dateFormat),
maintenance: '2020-10-20',
end: currentDate
.clone()
.add(6, 'month')
.format(dateFormat),
codename: 'Erbium',
},
v13: {
start: '2019-10-22',
maintenance: '2020-04-01',
end: '2020-06-01',
},
v14: {
start: '2020-04-21',
lts: currentDate
.clone()
.add(4, 'month')
.format(dateFormat),
maintenance: '2021-10-19',
end: currentDate
.clone()
.add(12, 'month')
.format(dateFormat),
codename: '',
},
}
return nock('https://raw.githubusercontent.com/')
.get(`/nodejs/Release/master/schedule.json`)
.reply(200, schedule)
}
module.exports = {
mockPackageData,
mockCurrentSha,
mockVersionsSha,
mockReleaseSchedule,
}

View File

@@ -98,11 +98,15 @@ module.exports = class NpmBase extends BaseJsonService {
async fetchPackageData({ registryUrl, scope, packageName, tag }) {
registryUrl = registryUrl || this.constructor.defaultRegistryUrl
let url
if (scope === undefined) {
if (scope === undefined && tag === undefined) {
// e.g. https://registry.npmjs.org/express/latest
// Use this endpoint as an optimization. It covers the vast majority of
// these badges, and the response is smaller.
url = `${registryUrl}/${packageName}/latest`
} else if (scope === undefined && tag !== undefined) {
// e.g. https://registry.npmjs.org/express
// because https://registry.npmjs.org/express/canary does not work
url = `${registryUrl}/${packageName}`
} else {
// e.g. https://registry.npmjs.org/@cedx%2Fgulp-david
// because https://registry.npmjs.org/@cedx%2Fgulp-david/latest does not work
@@ -120,7 +124,7 @@ module.exports = class NpmBase extends BaseJsonService {
})
let packageData
if (scope === undefined) {
if (scope === undefined && tag === undefined) {
packageData = json
} else {
const registryTag = tag || 'latest'