Skip to content

Commit 0bd6d2f

Browse files
committed
feat: add --replace-registry-host=<npmjs|always|never>
1 parent 21b823e commit 0bd6d2f

File tree

10 files changed

+234
-2
lines changed

10 files changed

+234
-2
lines changed

docs/content/using-npm/config.md

+16
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,22 @@ The base URL of the npm registry.
13591359
<!-- automatically generated, do not edit manually -->
13601360
<!-- see lib/utils/config/definitions.js -->
13611361

1362+
#### `replace-registry-host`
1363+
1364+
* Default: "npmjs"
1365+
* Type: "npmjs", "never", or "always"
1366+
1367+
Defines behavior for replacing the registry host in a lockfile with the
1368+
configured registry.
1369+
1370+
The default behavior is to replace package dist URLs from the default
1371+
registry (https://registry.npmjs.org) to the configured registry. If set to
1372+
"never", then use the registry value. If set to "always", then replace the
1373+
registry host with the configured host every time.
1374+
1375+
<!-- automatically generated, do not edit manually -->
1376+
<!-- see lib/utils/config/definitions.js -->
1377+
13621378
#### `save`
13631379

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

lib/utils/config/definitions.js

+16
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,22 @@ define('registry', {
16181618
flatten,
16191619
})
16201620

1621+
define('replace-registry-host', {
1622+
default: 'npmjs',
1623+
hint: '<npmjs|never|always>',
1624+
type: ['npmjs', 'never', 'always'],
1625+
description: `
1626+
Defines behavior for replacing the registry host in a lockfile with the
1627+
configured registry.
1628+
1629+
The default behavior is to replace package dist URLs from the default
1630+
registry (https://registry.npmjs.org) to the configured registry. If set to
1631+
"never", then use the registry value. If set to "always", then replace the
1632+
registry host with the configured host every time.
1633+
`,
1634+
flatten,
1635+
})
1636+
16211637
define('save', {
16221638
default: true,
16231639
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
@@ -120,6 +120,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna
120120
"read-only": false,
121121
"rebuild-bundle": true,
122122
"registry": "https://registry.npmjs.org/",
123+
"replace-registry-host": "npmjs",
123124
"save": true,
124125
"save-bundle": false,
125126
"save-dev": false,
@@ -275,6 +276,7 @@ proxy = null
275276
read-only = false
276277
rebuild-bundle = true
277278
registry = "https://registry.npmjs.org/"
279+
replace-registry-host = "npmjs"
278280
save = true
279281
save-bundle = false
280282
save-dev = false

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

+16
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ Array [
115115
"read-only",
116116
"rebuild-bundle",
117117
"registry",
118+
"replace-registry-host",
118119
"save",
119120
"save-bundle",
120121
"save-dev",
@@ -1439,6 +1440,21 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for regis
14391440
The base URL of the npm registry.
14401441
`
14411442

1443+
exports[`test/lib/utils/config/definitions.js TAP > config description for replace-registry-host 1`] = `
1444+
#### \`replace-registry-host\`
1445+
1446+
* Default: "npmjs"
1447+
* Type: "npmjs", "never", or "always"
1448+
1449+
Defines behavior for replacing the registry host in a lockfile with the
1450+
configured registry.
1451+
1452+
The default behavior is to replace package dist URLs from the default
1453+
registry (https://registry.npmjs.org) to the configured registry. If set to
1454+
"never", then use the registry value. If set to "always", then replace the
1455+
registry host with the configured host every time.
1456+
`
1457+
14421458
exports[`test/lib/utils/config/definitions.js TAP > config description for save 1`] = `
14431459
#### \`save\`
14441460

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

+16
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,22 @@ The base URL of the npm registry.
12331233
<!-- automatically generated, do not edit manually -->
12341234
<!-- see lib/utils/config/definitions.js -->
12351235
1236+
#### \`replace-registry-host\`
1237+
1238+
* Default: "npmjs"
1239+
* Type: "npmjs", "never", or "always"
1240+
1241+
Defines behavior for replacing the registry host in a lockfile with the
1242+
configured registry.
1243+
1244+
The default behavior is to replace package dist URLs from the default
1245+
registry (https://registry.npmjs.org) to the configured registry. If set to
1246+
"never", then use the registry value. If set to "always", then replace the
1247+
registry host with the configured host every time.
1248+
1249+
<!-- automatically generated, do not edit manually -->
1250+
<!-- see lib/utils/config/definitions.js -->
1251+
12361252
#### \`save\`
12371253
12381254
* Default: \`true\` unless when using \`npm update\` where it defaults to \`false\`

workspaces/arborist/lib/arborist/index.js

+6
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,14 @@ 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+
if (options.replaceRegistryHost !== 'never'
81+
&& options.replaceRegistryHost !== 'always'
82+
) {
83+
this.options.replaceRegistryHost = 'npmjs'
84+
}
7985

8086
this[_workspacesEnabled] = this.options.workspacesEnabled
8187

workspaces/arborist/lib/arborist/reify.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -716,8 +716,15 @@ module.exports = cls => class Reifier extends cls {
716716
// ${REGISTRY} or something. This has to be threaded through the
717717
// Shrinkwrap and Node classes carefully, so for now, just treat
718718
// the default reg as the magical animal that it has been.
719-
return resolved && resolved
720-
.replace(/^https?:\/\/registry\.npmjs\.org\//, this.registry)
719+
const resolvedURL = new URL(resolved)
720+
if (resolved
721+
&& ((this.options.replaceRegistryHost === 'npmjs'
722+
&& resolvedURL.origin === 'https://registry.npmjs.org')
723+
|| this.options.replaceRegistryHost === 'always')
724+
) {
725+
return new URL(resolvedURL.pathname, this.registry).href
726+
}
727+
return resolved
721728
}
722729

723730
// 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: 'garbage' }).options.replaceRegistryHost, 'npmjs')
242+
t.equal(new Arborist({ replaceRegistryHost: 'npmjs' }).options.replaceRegistryHost, 'npmjs')
243+
t.equal(new Arborist({ replaceRegistryHost: undefined }).options.replaceRegistryHost, 'npmjs')
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 { 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')
@@ -2865,3 +2866,132 @@ t.test('installLinks', (t) => {
28652866

28662867
t.end()
28672868
})
2869+
2870+
t.only('should preserve exact ranges, missing actual tree', async (t) => {
2871+
const Arborist = require('../../lib/index.js')
2872+
const abbrev = resolve(__dirname,
2873+
'../fixtures/registry-mocks/content/abbrev/-/abbrev-1.1.1.tgz')
2874+
const abbrevTGZ = fs.readFileSync(abbrev)
2875+
2876+
const abbrevPackument = JSON.stringify({
2877+
_id: 'abbrev',
2878+
_rev: 'lkjadflkjasdf',
2879+
name: 'abbrev',
2880+
'dist-tags': { latest: '1.1.1' },
2881+
versions: {
2882+
'1.1.1': {
2883+
name: 'abbrev',
2884+
version: '1.1.1',
2885+
dist: {
2886+
tarball: 'https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz',
2887+
},
2888+
},
2889+
},
2890+
})
2891+
2892+
const abbrevPackument2 = JSON.stringify({
2893+
_id: 'abbrev',
2894+
_rev: 'lkjadflkjasdf',
2895+
name: 'abbrev',
2896+
'dist-tags': { latest: '1.1.1' },
2897+
versions: {
2898+
'1.1.1': {
2899+
name: 'abbrev',
2900+
version: '1.1.1',
2901+
dist: {
2902+
tarball: 'https://registry.garbage.org/abbrev/-/abbrev-1.1.1.tgz',
2903+
},
2904+
},
2905+
},
2906+
})
2907+
2908+
t.only('host should not be replaced replaceRegistryHost=never', async (t) => {
2909+
const testdir = t.testdir({
2910+
project: {
2911+
'package.json': JSON.stringify({
2912+
name: 'myproject',
2913+
version: '1.0.0',
2914+
dependencies: {
2915+
abbrev: '1.1.1',
2916+
},
2917+
}),
2918+
},
2919+
})
2920+
2921+
tnock(t, 'https://registry.github.com')
2922+
.get('/abbrev')
2923+
.reply(200, abbrevPackument)
2924+
2925+
tnock(t, 'https://registry.npmjs.org')
2926+
.get('/abbrev/-/abbrev-1.1.1.tgz')
2927+
.reply(200, abbrevTGZ)
2928+
2929+
const arb = new Arborist({
2930+
path: resolve(testdir, 'project'),
2931+
registry: 'https://registry.github.com',
2932+
cache: resolve(testdir, 'cache'),
2933+
replaceRegistryHost: 'never',
2934+
})
2935+
await arb.reify()
2936+
})
2937+
2938+
t.only('host should be replaced replaceRegistryHost=npmjs', async (t) => {
2939+
const testdir = t.testdir({
2940+
project: {
2941+
'package.json': JSON.stringify({
2942+
name: 'myproject',
2943+
version: '1.0.0',
2944+
dependencies: {
2945+
abbrev: '1.1.1',
2946+
},
2947+
}),
2948+
},
2949+
})
2950+
2951+
tnock(t, 'https://registry.github.com')
2952+
.get('/abbrev')
2953+
.reply(200, abbrevPackument)
2954+
2955+
tnock(t, 'https://registry.github.com')
2956+
.get('/abbrev/-/abbrev-1.1.1.tgz')
2957+
.reply(200, abbrevTGZ)
2958+
2959+
const arb = new Arborist({
2960+
path: resolve(testdir, 'project'),
2961+
registry: 'https://registry.github.com',
2962+
cache: resolve(testdir, 'cache'),
2963+
replaceRegistryHost: 'npmjs',
2964+
})
2965+
await arb.reify()
2966+
})
2967+
2968+
t.only('host should be always replaceRegistryHost=always', async (t) => {
2969+
const testdir = t.testdir({
2970+
project: {
2971+
'package.json': JSON.stringify({
2972+
name: 'myproject',
2973+
version: '1.0.0',
2974+
dependencies: {
2975+
abbrev: '1.1.1',
2976+
},
2977+
}),
2978+
},
2979+
})
2980+
2981+
tnock(t, 'https://registry.github.com')
2982+
.get('/abbrev')
2983+
.reply(200, abbrevPackument2)
2984+
2985+
tnock(t, 'https://registry.github.com')
2986+
.get('/abbrev/-/abbrev-1.1.1.tgz')
2987+
.reply(200, abbrevTGZ)
2988+
2989+
const arb = new Arborist({
2990+
path: resolve(testdir, 'project'),
2991+
registry: 'https://registry.github.com',
2992+
cache: resolve(testdir, 'cache'),
2993+
replaceRegistryHost: 'always',
2994+
})
2995+
await arb.reify()
2996+
})
2997+
})
+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)