Skip to content

Commit 703dbbf

Browse files
authored
feat: add --replace-registry-host=<npmjs|always|never> (#4860)
feat: add --replace-registry-host=<npmjs|always|never>|<hostname>
1 parent fd030c8 commit 703dbbf

File tree

10 files changed

+239
-2
lines changed

10 files changed

+239
-2
lines changed

docs/content/using-npm/config.md

+18
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,24 @@ The base URL of the npm registry.
13931393
<!-- automatically generated, do not edit manually -->
13941394
<!-- see lib/utils/config/definitions.js -->
13951395

1396+
#### `replace-registry-host`
1397+
1398+
* Default: "npmjs"
1399+
* Type: "npmjs", "never", "always", or String
1400+
1401+
Defines behavior for replacing the registry host in a lockfile with the
1402+
configured registry.
1403+
1404+
The default behavior is to replace package dist URLs from the default
1405+
registry (https://registry.npmjs.org) to the configured registry. If set to
1406+
"never", then use the registry value. If set to "always", then replace the
1407+
registry host with the configured host every time.
1408+
1409+
You may also specify a bare hostname (e.g., "registry.npmjs.org").
1410+
1411+
<!-- automatically generated, do not edit manually -->
1412+
<!-- see lib/utils/config/definitions.js -->
1413+
13961414
#### `save`
13971415

13981416
* Default: `true` unless when using `npm update` where it defaults to `false`

lib/utils/config/definitions.js

+18
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,24 @@ define('registry', {
16491649
flatten,
16501650
})
16511651

1652+
define('replace-registry-host', {
1653+
default: 'npmjs',
1654+
hint: '<npmjs|never|always> | hostname',
1655+
type: ['npmjs', 'never', 'always', String],
1656+
description: `
1657+
Defines behavior for replacing the registry host in a lockfile with the
1658+
configured registry.
1659+
1660+
The default behavior is to replace package dist URLs from the default
1661+
registry (https://registry.npmjs.org) to the configured registry. If set to
1662+
"never", then use the registry value. If set to "always", then replace the
1663+
registry host with the configured host every time.
1664+
1665+
You may also specify a bare hostname (e.g., "registry.npmjs.org").
1666+
`,
1667+
flatten,
1668+
})
1669+
16521670
define('save', {
16531671
default: true,
16541672
defaultDescription: `\`true\` unless when using \`npm update\` where it

tap-snapshots/test/lib/commands/config.js.test.cjs

+2
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna
121121
"read-only": false,
122122
"rebuild-bundle": true,
123123
"registry": "https://registry.npmjs.org/",
124+
"replace-registry-host": "npmjs",
124125
"save": true,
125126
"save-bundle": false,
126127
"save-dev": false,
@@ -277,6 +278,7 @@ proxy = null
277278
read-only = false
278279
rebuild-bundle = true
279280
registry = "https://registry.npmjs.org/"
281+
replace-registry-host = "npmjs"
280282
save = true
281283
save-bundle = false
282284
save-dev = false

tap-snapshots/test/lib/utils/config/definitions.js.test.cjs

+18
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ Array [
116116
"read-only",
117117
"rebuild-bundle",
118118
"registry",
119+
"replace-registry-host",
119120
"save",
120121
"save-bundle",
121122
"save-dev",
@@ -1460,6 +1461,23 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for regis
14601461
The base URL of the npm registry.
14611462
`
14621463

1464+
exports[`test/lib/utils/config/definitions.js TAP > config description for replace-registry-host 1`] = `
1465+
#### \`replace-registry-host\`
1466+
1467+
* Default: "npmjs"
1468+
* Type: "npmjs", "never", "always", or String
1469+
1470+
Defines behavior for replacing the registry host in a lockfile with the
1471+
configured registry.
1472+
1473+
The default behavior is to replace package dist URLs from the default
1474+
registry (https://registry.npmjs.org) to the configured registry. If set to
1475+
"never", then use the registry value. If set to "always", then replace the
1476+
registry host with the configured host every time.
1477+
1478+
You may also specify a bare hostname (e.g., "registry.npmjs.org").
1479+
`
1480+
14631481
exports[`test/lib/utils/config/definitions.js TAP > config description for save 1`] = `
14641482
#### \`save\`
14651483

tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs

+18
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,24 @@ The base URL of the npm registry.
12661266
<!-- automatically generated, do not edit manually -->
12671267
<!-- see lib/utils/config/definitions.js -->
12681268
1269+
#### \`replace-registry-host\`
1270+
1271+
* Default: "npmjs"
1272+
* Type: "npmjs", "never", "always", or String
1273+
1274+
Defines behavior for replacing the registry host in a lockfile with the
1275+
configured registry.
1276+
1277+
The default behavior is to replace package dist URLs from the default
1278+
registry (https://registry.npmjs.org) to the configured registry. If set to
1279+
"never", then use the registry value. If set to "always", then replace the
1280+
registry host with the configured host every time.
1281+
1282+
You may also specify a bare hostname (e.g., "registry.npmjs.org").
1283+
1284+
<!-- automatically generated, do not edit manually -->
1285+
<!-- see lib/utils/config/definitions.js -->
1286+
12691287
#### \`save\`
12701288
12711289
* Default: \`true\` unless when using \`npm update\` where it defaults to \`false\`

workspaces/arborist/lib/arborist/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,12 @@ class Arborist extends Base {
7474
cache: options.cache || `${homedir()}/.npm/_cacache`,
7575
packumentCache: options.packumentCache || new Map(),
7676
workspacesEnabled: options.workspacesEnabled !== false,
77+
replaceRegistryHost: options.replaceRegistryHost,
7778
lockfileVersion: lockfileVersion(options.lockfileVersion),
7879
}
80+
this.replaceRegistryHost = this.options.replaceRegistryHost =
81+
(!this.options.replaceRegistryHost || this.options.replaceRegistryHost === 'npmjs') ?
82+
'registry.npmjs.org' : this.options.replaceRegistryHost
7983

8084
this[_workspacesEnabled] = this.options.workspacesEnabled
8185

workspaces/arborist/lib/arborist/reify.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -712,13 +712,19 @@ module.exports = cls => class Reifier extends cls {
712712
[_registryResolved] (resolved) {
713713
// the default registry url is a magic value meaning "the currently
714714
// configured registry".
715+
// `resolved` must never be falsey.
715716
//
716717
// XXX: use a magic string that isn't also a valid value, like
717718
// ${REGISTRY} or something. This has to be threaded through the
718719
// Shrinkwrap and Node classes carefully, so for now, just treat
719720
// the default reg as the magical animal that it has been.
720-
return resolved && resolved
721-
.replace(/^https?:\/\/registry\.npmjs\.org\//, this.registry)
721+
const resolvedURL = new URL(resolved)
722+
if ((this.options.replaceRegistryHost === resolvedURL.hostname)
723+
|| this.options.replaceRegistryHost === 'always') {
724+
// this.registry always has a trailing slash
725+
resolved = `${this.registry.slice(0, -1)}${resolvedURL.pathname}${resolvedURL.searchParams}`
726+
}
727+
return resolved
722728
}
723729

724730
// bundles are *sort of* like shrinkwraps, in that the branch is defined

workspaces/arborist/test/arborist/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,12 @@ t.test('lockfileVersion config validation', async t => {
236236
message: 'Invalid lockfileVersion config: banana',
237237
})
238238
})
239+
240+
t.test('valid replaceRegistryHost values', t => {
241+
t.equal(new Arborist({ replaceRegistryHost: 'registry.garbage.com' }).options.replaceRegistryHost, 'registry.garbage.com')
242+
t.equal(new Arborist({ replaceRegistryHost: 'npmjs' }).options.replaceRegistryHost, 'registry.npmjs.org')
243+
t.equal(new Arborist({ replaceRegistryHost: undefined }).options.replaceRegistryHost, 'registry.npmjs.org')
244+
t.equal(new Arborist({ replaceRegistryHost: 'always' }).options.replaceRegistryHost, 'always')
245+
t.equal(new Arborist({ replaceRegistryHost: 'never' }).options.replaceRegistryHost, 'never')
246+
t.end()
247+
})

workspaces/arborist/test/arborist/reify.js

+130
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const { join, resolve, basename } = require('path')
22
const t = require('tap')
33
const runScript = require('@npmcli/run-script')
44
const localeCompare = require('@isaacs/string-locale-compare')('en')
5+
const tnock = require('../fixtures/tnock')
56

67
// mock rimraf so we can make it fail in rollback tests
78
const realRimraf = require('rimraf')
@@ -2923,3 +2924,132 @@ t.test('installLinks', (t) => {
29232924

29242925
t.end()
29252926
})
2927+
2928+
t.only('should preserve exact ranges, missing actual tree', async (t) => {
2929+
const Arborist = require('../../lib/index.js')
2930+
const abbrev = resolve(__dirname,
2931+
'../fixtures/registry-mocks/content/abbrev/-/abbrev-1.1.1.tgz')
2932+
const abbrevTGZ = fs.readFileSync(abbrev)
2933+
2934+
const abbrevPackument = JSON.stringify({
2935+
_id: 'abbrev',
2936+
_rev: 'lkjadflkjasdf',
2937+
name: 'abbrev',
2938+
'dist-tags': { latest: '1.1.1' },
2939+
versions: {
2940+
'1.1.1': {
2941+
name: 'abbrev',
2942+
version: '1.1.1',
2943+
dist: {
2944+
tarball: 'https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz',
2945+
},
2946+
},
2947+
},
2948+
})
2949+
2950+
const abbrevPackument2 = JSON.stringify({
2951+
_id: 'abbrev',
2952+
_rev: 'lkjadflkjasdf',
2953+
name: 'abbrev',
2954+
'dist-tags': { latest: '1.1.1' },
2955+
versions: {
2956+
'1.1.1': {
2957+
name: 'abbrev',
2958+
version: '1.1.1',
2959+
dist: {
2960+
tarball: 'https://registry.garbage.org/abbrev/-/abbrev-1.1.1.tgz',
2961+
},
2962+
},
2963+
},
2964+
})
2965+
2966+
t.only('host should not be replaced replaceRegistryHost=never', async (t) => {
2967+
const testdir = t.testdir({
2968+
project: {
2969+
'package.json': JSON.stringify({
2970+
name: 'myproject',
2971+
version: '1.0.0',
2972+
dependencies: {
2973+
abbrev: '1.1.1',
2974+
},
2975+
}),
2976+
},
2977+
})
2978+
2979+
tnock(t, 'https://registry.github.com')
2980+
.get('/abbrev')
2981+
.reply(200, abbrevPackument)
2982+
2983+
tnock(t, 'https://registry.npmjs.org')
2984+
.get('/abbrev/-/abbrev-1.1.1.tgz')
2985+
.reply(200, abbrevTGZ)
2986+
2987+
const arb = new Arborist({
2988+
path: resolve(testdir, 'project'),
2989+
registry: 'https://registry.github.com',
2990+
cache: resolve(testdir, 'cache'),
2991+
replaceRegistryHost: 'never',
2992+
})
2993+
await arb.reify()
2994+
})
2995+
2996+
t.only('host should be replaced replaceRegistryHost=npmjs', async (t) => {
2997+
const testdir = t.testdir({
2998+
project: {
2999+
'package.json': JSON.stringify({
3000+
name: 'myproject',
3001+
version: '1.0.0',
3002+
dependencies: {
3003+
abbrev: '1.1.1',
3004+
},
3005+
}),
3006+
},
3007+
})
3008+
3009+
tnock(t, 'https://registry.github.com')
3010+
.get('/abbrev')
3011+
.reply(200, abbrevPackument)
3012+
3013+
tnock(t, 'https://registry.github.com')
3014+
.get('/abbrev/-/abbrev-1.1.1.tgz')
3015+
.reply(200, abbrevTGZ)
3016+
3017+
const arb = new Arborist({
3018+
path: resolve(testdir, 'project'),
3019+
registry: 'https://registry.github.com',
3020+
cache: resolve(testdir, 'cache'),
3021+
replaceRegistryHost: 'npmjs',
3022+
})
3023+
await arb.reify()
3024+
})
3025+
3026+
t.only('host should be always replaceRegistryHost=always', async (t) => {
3027+
const testdir = t.testdir({
3028+
project: {
3029+
'package.json': JSON.stringify({
3030+
name: 'myproject',
3031+
version: '1.0.0',
3032+
dependencies: {
3033+
abbrev: '1.1.1',
3034+
},
3035+
}),
3036+
},
3037+
})
3038+
3039+
tnock(t, 'https://registry.github.com')
3040+
.get('/abbrev')
3041+
.reply(200, abbrevPackument2)
3042+
3043+
tnock(t, 'https://registry.github.com')
3044+
.get('/abbrev/-/abbrev-1.1.1.tgz')
3045+
.reply(200, abbrevTGZ)
3046+
3047+
const arb = new Arborist({
3048+
path: resolve(testdir, 'project'),
3049+
registry: 'https://registry.github.com',
3050+
cache: resolve(testdir, 'cache'),
3051+
replaceRegistryHost: 'always',
3052+
})
3053+
await arb.reify()
3054+
})
3055+
})
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict'
2+
3+
const nock = require('nock')
4+
5+
module.exports = tnock
6+
function tnock (t, host) {
7+
const server = nock(host)
8+
nock.disableNetConnect()
9+
t.teardown(function () {
10+
nock.enableNetConnect()
11+
server.done()
12+
})
13+
return server
14+
}

0 commit comments

Comments
 (0)