Skip to content
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

[npm node] support for custom npm registry #1277

Merged
merged 10 commits into from
Nov 21, 2017
28 changes: 28 additions & 0 deletions lib/all-badge-examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -640,13 +640,27 @@ const allBadgeExamples = [
'node'
]
},
{
title: 'npm (custom registry)',
previewUri: '/npm/v/npm.svg?registry_uri=https://registry.npmjs.com',
keywords: [
'node'
]
},
{
title: 'npm (scoped with tag)',
previewUri: '/npm/v/@cycle/core/canary.svg',
keywords: [
'node'
]
},
{
title: 'npm (scoped with tag, custom registry)',
previewUri: '/npm/v/@cycle/core/canary.svg?registry_uri=https://registry.npmjs.com',
keywords: [
'node'
]
},
{
title: 'node',
previewUri: '/node/v/passport.svg',
Expand Down Expand Up @@ -675,6 +689,13 @@ const allBadgeExamples = [
'node'
]
},
{
title: 'node (scoped with tag, custom registry)',
previewUri: '/node/v/@stdlib/stdlib/latest.svg?registry_uri=https://registry.npmjs.com',
keywords: [
'node'
]
},
{
title: 'PyPI',
previewUri: '/pypi/v/nine.svg',
Expand Down Expand Up @@ -1116,6 +1137,13 @@ const allBadgeExamples = [
'node'
]
},
{
title: 'npm (custom registry)',
previewUri: '/npm/l/express.svg?registry_uri=https://registry.npmjs.com',
keywords: [
'node'
]
},
{
title: 'apm',
previewUri: '/apm/l/vim-mode.svg',
Expand Down
7 changes: 7 additions & 0 deletions lib/npm-badge-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

const defaultNpmRegistryUri = 'https://registry.npmjs.org';

module.exports = {
defaultNpmRegistryUri,
};
43 changes: 29 additions & 14 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const {
const {
mapNpmDownloads
} = require('./lib/npm-provider');
const {
defaultNpmRegistryUri
} = require('./lib/npm-badge-helpers');
const {
teamcityBadge
} = require('./lib/teamcity-badge-helpers');
Expand Down Expand Up @@ -1580,13 +1583,17 @@ cache(function (data, match, sendBadge, request) {

// npm version integration.
camp.route(/^\/npm\/v\/(?:@([^/]+))?\/?([^/]*)\/?([^/]*)\.(svg|png|gif|jpg|json)$/,
cache(function(data, match, sendBadge, request) {
cache({
queryParams: ['registry_uri'],
handler: function(queryParams, match, sendBadge, request) {
// e.g. cycle, core, next, svg
const [, scope, packageName, tag, format] = match;
const registryUri = queryParams.registry_uri || defaultNpmRegistryUri;
const pkg = encodeURIComponent(scope ? `@${scope}/${packageName}` : packageName);
const apiUrl = `https://registry.npmjs.org/-/package/${pkg}/dist-tags`;
const apiUrl = `${registryUri}/-/package/${pkg}/dist-tags`;

const name = tag ? `npm@${tag}` : 'npm';
const badgeData = getBadgeData(name, data);
const badgeData = getBadgeData(name, queryParams);
// Using the Accept header because of this bug:
// <https://github.com/npm/npmjs.org/issues/163>
request(apiUrl, { headers: { 'Accept': '*/*' } }, (err, res, buffer) => {
Expand All @@ -1606,27 +1613,30 @@ cache(function(data, match, sendBadge, request) {
sendBadge(format, badgeData);
}
});
}
}));

// npm license integration.
camp.route(/^\/npm\/l\/(?:@([^/]+)\/)?([^/]+)\.(svg|png|gif|jpg|json)$/,
cache(function(data, match, sendBadge, request) {
const scope = match[1]; // "user" (when a scope "@user" is supplied)
const packageName = match[2]; // "express"
const format = match[3]; // "svg"
cache({
queryParams: ['registry_uri'],
handler: function(queryParams, match, sendBadge, request) {
// e.g. cycle, core, svg
const [, scope, packageName, format ] = match;
const registryUri = queryParams.registry_uri || defaultNpmRegistryUri;
let apiUrl;
if (scope === 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.
apiUrl = `https://registry.npmjs.org/${packageName}/latest`;
apiUrl = `${registryUri}/${packageName}/latest`;
} else {
// e.g. https://registry.npmjs.org/@cedx%2Fgulp-david
// because https://registry.npmjs.org/@cedx%2Fgulp-david/latest does not work
const path = encodeURIComponent(`${scope}/${packageName}`);
apiUrl = `https://registry.npmjs.org/@${path}`;
apiUrl = `${registryUri}/@${path}`;
}
const badgeData = getBadgeData('license', data);
const badgeData = getBadgeData('license', queryParams);
request(apiUrl, { headers: { 'Accept': '*/*' } }, function(err, res, buffer) {
if (err != null) {
badgeData.text[1] = 'inaccessible';
Expand Down Expand Up @@ -1655,28 +1665,32 @@ cache(function(data, match, sendBadge, request) {
sendBadge(format, badgeData);
}
});
}
}));

// npm node version integration.
camp.route(/^\/node\/v\/(?:@([^/]+))?\/?([^/]*)\/?([^/]*)\.(svg|png|gif|jpg|json)$/,
cache(function(data, match, sendBadge, request) {
cache({
queryParams: ['registry_uri'],
handler: function(queryParams, match, sendBadge, request) {
// e.g. @stdlib, stdlib, next, svg
const [, scope, packageName, tag, format] = match;
const registryUri = queryParams.registry_uri || defaultNpmRegistryUri;
const registryTag = tag || 'latest';
let apiUrl;
if (scope === 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.
apiUrl = `https://registry.npmjs.org/${packageName}/${registryTag}`;
apiUrl = `${registryUri}/${packageName}/${registryTag}`;
} else {
// e.g. https://registry.npmjs.org/@cedx%2Fgulp-david
// because https://registry.npmjs.org/@cedx%2Fgulp-david/latest does not work
const path = encodeURIComponent(`${scope}/${packageName}`);
apiUrl = `https://registry.npmjs.org/@${path}`;
apiUrl = `${registryUri}/@${path}`;
}
const name = tag ? `node@${tag}` : 'node';
const badgeData = getBadgeData(name, data);
const badgeData = getBadgeData(name, queryParams);
// Using the Accept header because of this bug:
// <https://github.com/npm/npmjs.org/issues/163>
request(apiUrl, { headers: { 'Accept': '*/*' } }, (err, res, buffer) => {
Expand Down Expand Up @@ -1737,6 +1751,7 @@ cache(function(data, match, sendBadge, request) {
sendBadge(format, badgeData);
}
});
}
}));

// Anaconda Cloud / conda package manager integration
Expand Down
5 changes: 5 additions & 0 deletions service-tests/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ t.create("gets the tagged release's node version version of ionic")
.expectJSONTypes(Joi.object({ name: 'node@next' }).unknown())
.afterJSON(json => { assertIsSemverRange(json.value); });

t.create('gets the node version of passport from a custom registry')
.get('/v/passport.json?registry_uri=https://registry.npmjs.com')
.expectJSONTypes(Joi.object({ name: 'node' }).unknown())
.afterJSON(json => { assertIsSemverRange(json.value); });

t.create("gets the tagged release's node version of @cycle/core")
.get('/v/@cycle/core/canary.json')
.expectJSONTypes(Joi.object({ name: 'node@canary' }).unknown())
Expand Down
16 changes: 16 additions & 0 deletions service-tests/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,26 @@ t.create('gets the tagged package version of npm')
.get('/v/npm/next.json')
.expectJSONTypes(Joi.object().keys({ name: 'npm@next', value: isSemver }));

t.create('gets the package version of left-pad from a custom registry')
.get('/v/left-pad.json?registry_uri=https://registry.npmjs.com')
.expectJSONTypes(Joi.object().keys({ name: 'npm', value: isSemver }));

t.create('gets the tagged package version of @cycle/core')
.get('/v/@cycle/core/canary.json')
.expectJSONTypes(Joi.object().keys({ name: 'npm@canary', value: isSemver }));

t.create('gets the tagged package version of @cycle/core from a custom registry')
.get('/v/@cycle/core/canary.json?registry_uri=https://registry.npmjs.com')
.expectJSONTypes(Joi.object().keys({ name: 'npm@canary', value: isSemver }));

t.create('gets the license of express')
.get('/l/express.json')
.expectJSONTypes(Joi.object().keys({ name: 'license', value: 'MIT' }));

t.create('gets the license of express from a custom registry')
.get('/l/express.json?registry_uri=https://registry.npmjs.com')
.expectJSONTypes(Joi.object().keys({ name: 'license', value: 'MIT' }));

t.create('invalid package name')
.get('/v/frodo-is-not-a-package.json')
.expectJSON({ name: 'npm', value: 'invalid' });