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 9, 2022
1 parent 21b823e commit 6eb06ed
Show file tree
Hide file tree
Showing 10 changed files with 235 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
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
12 changes: 10 additions & 2 deletions workspaces/arborist/lib/arborist/reify.js
Expand Up @@ -716,8 +716,16 @@ 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.hostname === 'registry.npmjs.org')
|| 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
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()
})
130 changes: 130 additions & 0 deletions workspaces/arborist/test/arborist/reify.js
Expand Up @@ -2,6 +2,7 @@ const { 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 @@ -2865,3 +2866,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
@@ -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 6eb06ed

Please sign in to comment.