Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement options affecting resolved value in lock files. #4264

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/content/using-npm/config.md
Expand Up @@ -1161,6 +1161,22 @@ variable will be set to `'production'` for all lifecycle scripts.
<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->

#### `omit-lockfile-registry-resolved`

* Default: false
* Type: Boolean

Set to true to omit 'resolved' key from registry dependencies in lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions. This
option makes installing slower because npm must fetch package manifest to
resolve the package version's tarball. See 'record-default-registry' for an
alternative.

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

#### `otp`

* Default: null
Expand Down Expand Up @@ -1333,6 +1349,22 @@ Rebuild bundled dependencies after installation.
<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->

#### `record-default-registry`

* Default: false
* Type: Boolean

Set to true to replace the actual registry in urls resolved from registires
with the default registry when recording lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions. This
option supports registries that host tarballs at the same path. If even the
path may change see 'omit-lockfile-registry-resolved'.

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

#### `registry`

* Default: "https://registry.npmjs.org/"
Expand Down
30 changes: 30 additions & 0 deletions lib/utils/config/definitions.js
Expand Up @@ -2304,3 +2304,33 @@ define('yes', {
the command line.
`,
})

define('omit-lockfile-registry-resolved', {
default: false,
type: Boolean,
description: `
Set to true to omit 'resolved' key from registry dependencies in lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions.
This option makes installing slower because npm must fetch package manifest
to resolve the package version's tarball.
See 'record-default-registry' for an alternative.
`,
flatten,
})

define('record-default-registry', {
default: false,
type: Boolean,
description: `
Set to true to replace the actual registry in urls resolved from registires
with the default registry when recording lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions.
This option supports registries that host tarballs at the same path. If
even the path may change see 'omit-lockfile-registry-resolved'.
`,
flatten,
})
4 changes: 4 additions & 0 deletions tap-snapshots/test/lib/commands/config.js.test.cjs
Expand Up @@ -158,6 +158,8 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna
"workspaces": null,
"workspaces-update": true,
"yes": null,
"omit-lockfile-registry-resolved": false,
"record-default-registry": false,
"metrics-registry": "https://registry.npmjs.org/"
}
`
Expand Down Expand Up @@ -255,6 +257,7 @@ noproxy = [""]
npm-version = "{NPM-VERSION}"
offline = false
omit = []
omit-lockfile-registry-resolved = false
only = null
optional = null
otp = null
Expand All @@ -272,6 +275,7 @@ progress = true
proxy = null
read-only = false
rebuild-bundle = true
record-default-registry = false
registry = "https://registry.npmjs.org/"
save = true
save-bundle = false
Expand Down
32 changes: 32 additions & 0 deletions tap-snapshots/test/lib/utils/config/definitions.js.test.cjs
Expand Up @@ -154,6 +154,8 @@ Array [
"workspaces",
"workspaces-update",
"yes",
"omit-lockfile-registry-resolved",
"record-default-registry",
]
`

Expand Down Expand Up @@ -1223,6 +1225,21 @@ If the resulting omit list includes \`'dev'\`, then the \`NODE_ENV\` environment
variable will be set to \`'production'\` for all lifecycle scripts.
`

exports[`test/lib/utils/config/definitions.js TAP > config description for omit-lockfile-registry-resolved 1`] = `
#### \`omit-lockfile-registry-resolved\`

* Default: false
* Type: Boolean

Set to true to omit 'resolved' key from registry dependencies in lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions. This
option makes installing slower because npm must fetch package manifest to
resolve the package version's tarball. See 'record-default-registry' for an
alternative.
`

exports[`test/lib/utils/config/definitions.js TAP > config description for only 1`] = `
#### \`only\`

Expand Down Expand Up @@ -1414,6 +1431,21 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for rebui
Rebuild bundled dependencies after installation.
`

exports[`test/lib/utils/config/definitions.js TAP > config description for record-default-registry 1`] = `
#### \`record-default-registry\`

* Default: false
* Type: Boolean

Set to true to replace the actual registry in urls resolved from registires
with the default registry when recording lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions. This
option supports registries that host tarballs at the same path. If even the
path may change see 'omit-lockfile-registry-resolved'.
`

exports[`test/lib/utils/config/definitions.js TAP > config description for registry 1`] = `
#### \`registry\`

Expand Down
32 changes: 32 additions & 0 deletions tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs
Expand Up @@ -1035,6 +1035,22 @@ variable will be set to \`'production'\` for all lifecycle scripts.
<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->

#### \`omit-lockfile-registry-resolved\`

* Default: false
* Type: Boolean

Set to true to omit 'resolved' key from registry dependencies in lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions. This
option makes installing slower because npm must fetch package manifest to
resolve the package version's tarball. See 'record-default-registry' for an
alternative.

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

#### \`otp\`

* Default: null
Expand Down Expand Up @@ -1207,6 +1223,22 @@ Rebuild bundled dependencies after installation.
<!-- automatically generated, do not edit manually -->
<!-- see lib/utils/config/definitions.js -->

#### \`record-default-registry\`

* Default: false
* Type: Boolean

Set to true to replace the actual registry in urls resolved from registires
with the default registry when recording lock files.

This setting is useful in projects that may install dependencies from
different registries but would use a lockfile to lock package versions. This
option supports registries that host tarballs at the same path. If even the
path may change see 'omit-lockfile-registry-resolved'.

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

#### \`registry\`

* Default: "https://registry.npmjs.org/"
Expand Down
2 changes: 2 additions & 0 deletions workspaces/arborist/lib/arborist/build-ideal-tree.js
Expand Up @@ -327,6 +327,7 @@ Try using the package name instead, e.g:
? Shrinkwrap.reset({
path: this.path,
lockfileVersion: this.options.lockfileVersion,
resolveOptions: this.options,
}).then(meta => Object.assign(root, { meta }))
: this.loadVirtual({ root }))

Expand Down Expand Up @@ -386,6 +387,7 @@ Try using the package name instead, e.g:
const meta = new Shrinkwrap({
path: this.path,
lockfileVersion: this.options.lockfileVersion,
resolveOptions: this.options,
})
meta.reset()
root.meta = meta
Expand Down
2 changes: 2 additions & 0 deletions workspaces/arborist/lib/arborist/load-actual.js
Expand Up @@ -147,6 +147,7 @@ module.exports = cls => class ActualLoader extends cls {
const meta = await Shrinkwrap.load({
path: this[_actualTree].path,
hiddenLockfile: true,
resolveOptions: this.options,
})
if (meta.loadedFromDisk) {
this[_actualTree].meta = meta
Expand All @@ -155,6 +156,7 @@ module.exports = cls => class ActualLoader extends cls {
const meta = await Shrinkwrap.load({
path: this[_actualTree].path,
lockfileVersion: this.options.lockfileVersion,
resolveOptions: this.options,
})
this[_actualTree].meta = meta
return this[_loadActualActually]({ root, ignoreMissing })
Expand Down
1 change: 1 addition & 0 deletions workspaces/arborist/lib/arborist/load-virtual.js
Expand Up @@ -57,6 +57,7 @@ module.exports = cls => class VirtualLoader extends cls {
const s = await Shrinkwrap.load({
path: this.path,
lockfileVersion: this.options.lockfileVersion,
resolveOptions: this.options,
})
if (!s.loadedFromDisk && !options.root) {
const er = new Error('loadVirtual requires existing shrinkwrap file')
Expand Down
12 changes: 12 additions & 0 deletions workspaces/arborist/lib/node.js
Expand Up @@ -522,6 +522,18 @@ class Node {
return this === this.root || this === this.root.target
}

get isRegistryDependency () {
if (this.edgesIn.size === 0) {
return false
}
for (const edge of this.edgesIn) {
if (!npa(edge.spec).registry) {
return false
}
}
return true
}

* ancestry () {
for (let anc = this; anc; anc = anc.resolveParent) {
yield anc
Expand Down
52 changes: 52 additions & 0 deletions workspaces/arborist/lib/override-resolves.js
@@ -0,0 +1,52 @@
const npa = require('npm-package-arg')

function overrideResolves (node, resolved, opts = {}) {
const {
omitLockfileRegistryResolved = false,
recordDefaultRegistry = false,
} = opts

const isRegistryDependency = node.isRegistryDependency

// omit the resolved url of registry dependencies. this makes installs slower
// because npm must resolve the url for each package version but it allows
// users to use a lockfile across registries that host tarballs at different
// paths.
if (isRegistryDependency && omitLockfileRegistryResolved) {
return undefined
}

// replace the configured registry with the default registry. the default
// registry is a magic value meaning the current registry, so recording
// resolved with the default registry allows users to switch to a
// different registry without removing their lockfile. The path portion
// of the resolved url is preserved so this trick only works when the
// different registries host tarballs at the same relative paths.
if (isRegistryDependency && recordDefaultRegistry) {
const scope = npa(node.packageName).scope
const registry = scope && opts[`${scope}:registry`]
? opts[`${scope}:registry`]
: opts.registry

// normalize registry url - strip trailing slash.
// TODO improve normalization for both the configured registry and resolved
// url. consider port, protocol, more path normalization.
const normalized = registry.endsWith('/')
? registry.slice(0, -1)
: registry

// only replace the host if the resolved url is for the configured
// registry. registries may host tarballs on another server. return
// undefined so npm will re-resolve the url from the current registry when
// it reads the lockfile.
if (resolved.startsWith(normalized)) {
return 'https://registry.npmjs.org' + resolved.slice(normalized.length)
} else {
return undefined
}
}

return resolved
}

module.exports = { overrideResolves }