Skip to content

Commit

Permalink
feat: add --replace-registry-host=<npmjs|always|never>
Browse files Browse the repository at this point in the history
  • Loading branch information
fritzy committed May 5, 2022
1 parent 21b823e commit 0bbdecb
Show file tree
Hide file tree
Showing 11 changed files with 374 additions and 2 deletions.
16 changes: 16 additions & 0 deletions docs/content/using-npm/config.md
Expand Up @@ -1359,6 +1359,22 @@ The base URL of the npm registry.
<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->

#### `replace-registry-host`

* Default: "npmjs"
* Type: "npmjs", "never", or "always"

Defines behavior for replacing the registry host in a lockfile with the
configured registry.

The default behavior is to replace package dist URLs from the default
registry (https://registry.npmjs.org) to the configured registry. If set to
"never", then use the registry value. If set to "always", then replace the
registry host with the configured host every time.

<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->

#### `save`

* Default: `true` unless when using `npm update` where it defaults to `false`
Expand Down
16 changes: 16 additions & 0 deletions lib/utils/config/definitions.js
Expand Up @@ -1618,6 +1618,22 @@ define('registry', {
flatten,
})

define('replace-registry-host', {
default: 'npmjs',
hint: '<npmjs|never|always>',
type: ['npmjs', 'never', 'always'],
description: `
Defines behavior for replacing the registry host in a lockfile with the
configured registry.
The default behavior is to replace package dist URLs from the default
registry (https://registry.npmjs.org) to the configured registry. If set to
"never", then use the registry value. If set to "always", then replace the
registry host with the configured host every time.
`,
flatten,
})

define('save', {
default: true,
defaultDescription: `\`true\` unless when using \`npm update\` where it
Expand Down
2 changes: 2 additions & 0 deletions tap-snapshots/test/lib/commands/config.js.test.cjs
Expand Up @@ -120,6 +120,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna
"read-only": false,
"rebuild-bundle": true,
"registry": "https://registry.npmjs.org/",
"replace-registry-host": "npmjs",
"save": true,
"save-bundle": false,
"save-dev": false,
Expand Down Expand Up @@ -275,6 +276,7 @@ proxy = null
read-only = false
rebuild-bundle = true
registry = "https://registry.npmjs.org/"
replace-registry-host = "npmjs"
save = true
save-bundle = false
save-dev = false
Expand Down
16 changes: 16 additions & 0 deletions tap-snapshots/test/lib/utils/config/definitions.js.test.cjs
Expand Up @@ -115,6 +115,7 @@ Array [
"read-only",
"rebuild-bundle",
"registry",
"replace-registry-host",
"save",
"save-bundle",
"save-dev",
Expand Down Expand Up @@ -1439,6 +1440,21 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for regis
The base URL of the npm registry.
`

exports[`test/lib/utils/config/definitions.js TAP > config description for replace-registry-host 1`] = `
#### \`replace-registry-host\`
* Default: "npmjs"
* Type: "npmjs", "never", or "always"
Defines behavior for replacing the registry host in a lockfile with the
configured registry.
The default behavior is to replace package dist URLs from the default
registry (https://registry.npmjs.org) to the configured registry. If set to
"never", then use the registry value. If set to "always", then replace the
registry host with the configured host every time.
`

exports[`test/lib/utils/config/definitions.js TAP > config description for save 1`] = `
#### \`save\`
Expand Down
16 changes: 16 additions & 0 deletions tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs
Expand Up @@ -1233,6 +1233,22 @@ The base URL of the npm registry.
<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->
#### \`replace-registry-host\`
* Default: "npmjs"
* Type: "npmjs", "never", or "always"
Defines behavior for replacing the registry host in a lockfile with the
configured registry.
The default behavior is to replace package dist URLs from the default
registry (https://registry.npmjs.org) to the configured registry. If set to
"never", then use the registry value. If set to "always", then replace the
registry host with the configured host every time.
<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->
#### \`save\`
* Default: \`true\` unless when using \`npm update\` where it defaults to \`false\`
Expand Down
140 changes: 140 additions & 0 deletions test/lib/npm.js
@@ -1,5 +1,6 @@
const t = require('tap')
const { resolve, dirname, join } = require('path')
const Arborist = require('@npmcli/arborist')

const { load: loadMockNpm } = require('../fixtures/mock-npm.js')
const mockGlobals = require('../fixtures/mock-globals')
Expand Down Expand Up @@ -654,3 +655,142 @@ t.test('implicit workspace accept', async t => {
})
await t.rejects(mock.npm.exec('org', []), /.*Usage/)
})

t.test('replaceRegistryHost', async t => {
const mock = await loadMockNpm(t, {
prefixDir: {
packages: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
scripts: { test: 'echo test a' },
}),
},
},
'package.json': JSON.stringify({
name: 'root',
version: '1.0.0',
workspaces: ['./packages/a'],
}),
},
globals: {
'process.argv': [
process.execPath,
process.argv[1],
'--color', 'false',
'--workspace', './packages/a',
],
},
})
t.equal(mock.npm.flatOptions.replaceRegistryHost, 'npmjs')
const arb = new Arborist({
...mock.npm.flatOptions,
})
t.equal(arb.options.replaceRegistryHost, 'npmjs')
})

t.test('replaceRegistryHost=garbage', async t => {
const mock = await loadMockNpm(t, {
prefixDir: {
packages: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
scripts: { test: 'echo test a' },
}),
},
},
'package.json': JSON.stringify({
name: 'root',
version: '1.0.0',
workspaces: ['./packages/a'],
}),
},
globals: {
'process.argv': [
process.execPath,
process.argv[1],
'--color', 'false',
'--workspace', './packages/a',
'--replace-registry-host', 'garbage',
],
},
})
t.equal(mock.npm.flatOptions.replaceRegistryHost, 'npmjs')
const arb = new Arborist({
...mock.npm.flatOptions,
})
t.equal(arb.options.replaceRegistryHost, 'npmjs')
})

t.test('replaceRegistryHost=never', async t => {
const mock = await loadMockNpm(t, {
prefixDir: {
packages: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
scripts: { test: 'echo test a' },
}),
},
},
'package.json': JSON.stringify({
name: 'root',
version: '1.0.0',
workspaces: ['./packages/a'],
}),
},
globals: {
'process.argv': [
process.execPath,
process.argv[1],
'--color', 'false',
'--workspace', './packages/a',
'--replace-registry-host', 'never',
],
},
})
t.equal(mock.npm.flatOptions.replaceRegistryHost, 'never')
const arb = new Arborist({
...mock.npm.flatOptions,
})
t.equal(arb.options.replaceRegistryHost, 'never')
})

t.test('replaceRegistryHost=always', async t => {
const mock = await loadMockNpm(t, {
prefixDir: {
packages: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
scripts: { test: 'echo test a' },
}),
},
},
'package.json': JSON.stringify({
name: 'root',
version: '1.0.0',
workspaces: ['./packages/a'],
}),
},
globals: {
'process.argv': [
process.execPath,
process.argv[1],
'--color', 'false',
'--workspace', './packages/a',
'--replace-registry-host', 'always',
],
},
})
t.equal(mock.npm.flatOptions.replaceRegistryHost, 'always')
const arb = new Arborist({
...mock.npm.flatOptions,
})
t.equal(arb.options.replaceRegistryHost, 'always')
})
6 changes: 6 additions & 0 deletions workspaces/arborist/lib/arborist/index.js
Expand Up @@ -74,8 +74,14 @@ class Arborist extends Base {
cache: options.cache || `${homedir()}/.npm/_cacache`,
packumentCache: options.packumentCache || new Map(),
workspacesEnabled: options.workspacesEnabled !== false,
replaceRegistryHost: options.replaceRegistryHost,
lockfileVersion: lockfileVersion(options.lockfileVersion),
}
if (options.replaceRegistryHost !== 'never'
&& options.replaceRegistryHost !== 'always'
) {
this.options.replaceRegistryHost = 'npmjs'
}

this[_workspacesEnabled] = this.options.workspacesEnabled

Expand Down
11 changes: 9 additions & 2 deletions workspaces/arborist/lib/arborist/reify.js
Expand Up @@ -716,8 +716,15 @@ module.exports = cls => class Reifier extends cls {
// ${REGISTRY} or something. This has to be threaded through the
// Shrinkwrap and Node classes carefully, so for now, just treat
// the default reg as the magical animal that it has been.
return resolved && resolved
.replace(/^https?:\/\/registry\.npmjs\.org\//, this.registry)
const resolvedURL = new URL(resolved)
if (resolved
&& ((this.options.replaceRegistryHost === 'npmjs'
&& resolvedURL.origin === 'https://registry.npmjs.org')
|| this.options.replaceRegistryHost === 'always')
) {
return new URL(resolvedURL.pathname, this.registry).href
}
return resolved
}

// bundles are *sort of* like shrinkwraps, in that the branch is defined
Expand Down
9 changes: 9 additions & 0 deletions workspaces/arborist/test/arborist/index.js
Expand Up @@ -236,3 +236,12 @@ t.test('lockfileVersion config validation', async t => {
message: 'Invalid lockfileVersion config: banana',
})
})

t.test('valid replaceRegistryHost values', t => {
t.equal(new Arborist({ replaceRegistryHost: 'garbage' }).options.replaceRegistryHost, 'npmjs')
t.equal(new Arborist({ replaceRegistryHost: 'npmjs' }).options.replaceRegistryHost, 'npmjs')
t.equal(new Arborist({ replaceRegistryHost: undefined }).options.replaceRegistryHost, 'npmjs')
t.equal(new Arborist({ replaceRegistryHost: 'always' }).options.replaceRegistryHost, 'always')
t.equal(new Arborist({ replaceRegistryHost: 'never' }).options.replaceRegistryHost, 'never')
t.end()
})

0 comments on commit 0bbdecb

Please sign in to comment.