Skip to content

Commit

Permalink
feat: add --replace-registry-host=<npmjs|always|never> (#4860)
Browse files Browse the repository at this point in the history
feat: add --replace-registry-host=<npmjs|always|never>|<hostname>
  • Loading branch information
fritzy authored Aug 2, 2022
1 parent fd030c8 commit 703dbbf
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 2 deletions.
18 changes: 18 additions & 0 deletions docs/content/using-npm/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,24 @@ 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", "always", or String

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.

You may also specify a bare hostname (e.g., "registry.npmjs.org").

<!-- 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
18 changes: 18 additions & 0 deletions lib/utils/config/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,24 @@ define('registry', {
flatten,
})

define('replace-registry-host', {
default: 'npmjs',
hint: '<npmjs|never|always> | hostname',
type: ['npmjs', 'never', 'always', String],
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.
You may also specify a bare hostname (e.g., "registry.npmjs.org").
`,
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
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,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 @@ -277,6 +278,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
18 changes: 18 additions & 0 deletions tap-snapshots/test/lib/utils/config/definitions.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ Array [
"read-only",
"rebuild-bundle",
"registry",
"replace-registry-host",
"save",
"save-bundle",
"save-dev",
Expand Down Expand Up @@ -1460,6 +1461,23 @@ 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", "always", or String
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.
You may also specify a bare hostname (e.g., "registry.npmjs.org").
`

exports[`test/lib/utils/config/definitions.js TAP > config description for save 1`] = `
#### \`save\`
Expand Down
18 changes: 18 additions & 0 deletions tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,24 @@ 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", "always", or String
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.
You may also specify a bare hostname (e.g., "registry.npmjs.org").
<!-- 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
4 changes: 4 additions & 0 deletions workspaces/arborist/lib/arborist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,12 @@ 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),
}
this.replaceRegistryHost = this.options.replaceRegistryHost =
(!this.options.replaceRegistryHost || this.options.replaceRegistryHost === 'npmjs') ?
'registry.npmjs.org' : this.options.replaceRegistryHost

this[_workspacesEnabled] = this.options.workspacesEnabled

Expand Down
10 changes: 8 additions & 2 deletions workspaces/arborist/lib/arborist/reify.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,13 +712,19 @@ module.exports = cls => class Reifier extends cls {
[_registryResolved] (resolved) {
// the default registry url is a magic value meaning "the currently
// configured registry".
// `resolved` must never be falsey.
//
// XXX: use a magic string that isn't also a valid value, like
// ${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 ((this.options.replaceRegistryHost === resolvedURL.hostname)
|| this.options.replaceRegistryHost === 'always') {
// this.registry always has a trailing slash
resolved = `${this.registry.slice(0, -1)}${resolvedURL.pathname}${resolvedURL.searchParams}`
}
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
Original file line number Diff line number Diff line change
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: 'registry.garbage.com' }).options.replaceRegistryHost, 'registry.garbage.com')
t.equal(new Arborist({ replaceRegistryHost: 'npmjs' }).options.replaceRegistryHost, 'registry.npmjs.org')
t.equal(new Arborist({ replaceRegistryHost: undefined }).options.replaceRegistryHost, 'registry.npmjs.org')
t.equal(new Arborist({ replaceRegistryHost: 'always' }).options.replaceRegistryHost, 'always')
t.equal(new Arborist({ replaceRegistryHost: 'never' }).options.replaceRegistryHost, 'never')
t.end()
})
130 changes: 130 additions & 0 deletions workspaces/arborist/test/arborist/reify.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { join, resolve, basename } = require('path')
const t = require('tap')
const runScript = require('@npmcli/run-script')
const localeCompare = require('@isaacs/string-locale-compare')('en')
const tnock = require('../fixtures/tnock')

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

t.end()
})

t.only('should preserve exact ranges, missing actual tree', async (t) => {
const Arborist = require('../../lib/index.js')
const abbrev = resolve(__dirname,
'../fixtures/registry-mocks/content/abbrev/-/abbrev-1.1.1.tgz')
const abbrevTGZ = fs.readFileSync(abbrev)

const abbrevPackument = JSON.stringify({
_id: 'abbrev',
_rev: 'lkjadflkjasdf',
name: 'abbrev',
'dist-tags': { latest: '1.1.1' },
versions: {
'1.1.1': {
name: 'abbrev',
version: '1.1.1',
dist: {
tarball: 'https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz',
},
},
},
})

const abbrevPackument2 = JSON.stringify({
_id: 'abbrev',
_rev: 'lkjadflkjasdf',
name: 'abbrev',
'dist-tags': { latest: '1.1.1' },
versions: {
'1.1.1': {
name: 'abbrev',
version: '1.1.1',
dist: {
tarball: 'https://registry.garbage.org/abbrev/-/abbrev-1.1.1.tgz',
},
},
},
})

t.only('host should not be replaced replaceRegistryHost=never', async (t) => {
const testdir = t.testdir({
project: {
'package.json': JSON.stringify({
name: 'myproject',
version: '1.0.0',
dependencies: {
abbrev: '1.1.1',
},
}),
},
})

tnock(t, 'https://registry.github.com')
.get('/abbrev')
.reply(200, abbrevPackument)

tnock(t, 'https://registry.npmjs.org')
.get('/abbrev/-/abbrev-1.1.1.tgz')
.reply(200, abbrevTGZ)

const arb = new Arborist({
path: resolve(testdir, 'project'),
registry: 'https://registry.github.com',
cache: resolve(testdir, 'cache'),
replaceRegistryHost: 'never',
})
await arb.reify()
})

t.only('host should be replaced replaceRegistryHost=npmjs', async (t) => {
const testdir = t.testdir({
project: {
'package.json': JSON.stringify({
name: 'myproject',
version: '1.0.0',
dependencies: {
abbrev: '1.1.1',
},
}),
},
})

tnock(t, 'https://registry.github.com')
.get('/abbrev')
.reply(200, abbrevPackument)

tnock(t, 'https://registry.github.com')
.get('/abbrev/-/abbrev-1.1.1.tgz')
.reply(200, abbrevTGZ)

const arb = new Arborist({
path: resolve(testdir, 'project'),
registry: 'https://registry.github.com',
cache: resolve(testdir, 'cache'),
replaceRegistryHost: 'npmjs',
})
await arb.reify()
})

t.only('host should be always replaceRegistryHost=always', async (t) => {
const testdir = t.testdir({
project: {
'package.json': JSON.stringify({
name: 'myproject',
version: '1.0.0',
dependencies: {
abbrev: '1.1.1',
},
}),
},
})

tnock(t, 'https://registry.github.com')
.get('/abbrev')
.reply(200, abbrevPackument2)

tnock(t, 'https://registry.github.com')
.get('/abbrev/-/abbrev-1.1.1.tgz')
.reply(200, abbrevTGZ)

const arb = new Arborist({
path: resolve(testdir, 'project'),
registry: 'https://registry.github.com',
cache: resolve(testdir, 'cache'),
replaceRegistryHost: 'always',
})
await arb.reify()
})
})
14 changes: 14 additions & 0 deletions workspaces/arborist/test/fixtures/tnock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict'

const nock = require('nock')

module.exports = tnock
function tnock (t, host) {
const server = nock(host)
nock.disableNetConnect()
t.teardown(function () {
nock.enableNetConnect()
server.done()
})
return server
}

0 comments on commit 703dbbf

Please sign in to comment.