Skip to content

Commit cdaa79a

Browse files
committed
feat(version): reify on workspace version change
Adds a minimalistic reify step that updates the installed tree after a version change within one of the configured workspaces when using any of the workspaces config options. It's also possible to use the `--save` config option in order to auto update semver ranges of dependencies declarations accross dependent `package.json` files. Fixes: #3403 Relates to: npm/rfcs#556 Relates to: #3757 Relates to: #4193
1 parent 362831c commit cdaa79a

File tree

10 files changed

+287
-10
lines changed

10 files changed

+287
-10
lines changed

docs/content/commands/npm-version.md

+11
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,17 @@ This value is not exported to the environment for child processes.
144144
<!-- automatically generated, do not edit manually -->
145145
<!-- see lib/utils/config/definitions.js -->
146146

147+
#### `workspaces-update`
148+
149+
* Default: true
150+
* Type: Boolean
151+
152+
If set to true, the npm cli will run an update after operations that may
153+
possibly change the workspaces installed to the `node_modules` folder.
154+
155+
<!-- automatically generated, do not edit manually -->
156+
<!-- see lib/utils/config/definitions.js -->
157+
147158
#### `include-workspace-root`
148159

149160
* Default: false

lib/commands/version.js

+35
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ const { resolve } = require('path')
33
const { promisify } = require('util')
44
const readFile = promisify(require('fs').readFile)
55

6+
const Arborist = require('@npmcli/arborist')
7+
const reifyFinish = require('../utils/reify-finish.js')
8+
69
const BaseCommand = require('../base-command.js')
710

811
class Version extends BaseCommand {
@@ -17,6 +20,7 @@ class Version extends BaseCommand {
1720
'sign-git-tag',
1821
'workspace',
1922
'workspaces',
23+
'workspaces-update',
2024
'include-workspace-root',
2125
]
2226

@@ -81,15 +85,18 @@ class Version extends BaseCommand {
8185
async changeWorkspaces (args, filters) {
8286
const prefix = this.npm.config.get('tag-version-prefix')
8387
await this.setWorkspaces(filters)
88+
const updatedWorkspaces = []
8489
for (const [name, path] of this.workspaces) {
8590
this.npm.output(name)
8691
const version = await libnpmversion(args[0], {
8792
...this.npm.flatOptions,
8893
'git-tag-version': false,
8994
path,
9095
})
96+
updatedWorkspaces.push(name)
9197
this.npm.output(`${prefix}${version}`)
9298
}
99+
return this.update(updatedWorkspaces)
93100
}
94101

95102
async list (results = {}) {
@@ -129,6 +136,34 @@ class Version extends BaseCommand {
129136
}
130137
return this.list(results)
131138
}
139+
140+
async update(args) {
141+
if (!this.npm.flatOptions.workspacesUpdate || !args.length) {
142+
return
143+
}
144+
145+
// default behavior is to not save by default in order to avoid
146+
// race condition problems when publishing multiple workspaces
147+
// that have dependencies on one another, it might still be useful
148+
// in some cases, which then need to set --save
149+
const save = this.npm.config.isDefault('save')
150+
? false
151+
: this.npm.config.get('save')
152+
153+
// runs a minimalistic reify update, targetting only the workspaces
154+
// that had version updates and skipping fund/audit/save
155+
const opts = {
156+
...this.npm.flatOptions,
157+
audit: false,
158+
fund: false,
159+
path: this.npm.localPrefix,
160+
save,
161+
}
162+
const arb = new Arborist(opts)
163+
164+
await arb.reify({ ...opts, update: args })
165+
await reifyFinish(this.npm, arb)
166+
}
132167
}
133168

134169
module.exports = Version

lib/utils/config/definitions.js

+10
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,16 @@ define('workspaces', {
22702270
},
22712271
})
22722272

2273+
define('workspaces-update', {
2274+
default: true,
2275+
type: Boolean,
2276+
description: `
2277+
If set to true, the npm cli will run an update after operations that may
2278+
possibly change the workspaces installed to the \`node_modules\` folder.
2279+
`,
2280+
flatten,
2281+
})
2282+
22732283
define('yes', {
22742284
default: null,
22752285
type: [null, Boolean],

tap-snapshots/test/lib/commands/config.js.test.cjs

+2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna
155155
"which": null,
156156
"workspace": [],
157157
"workspaces": null,
158+
"workspaces-update": true,
158159
"yes": null,
159160
"metrics-registry": "https://registry.npmjs.org/"
160161
}
@@ -308,6 +309,7 @@ viewer = "{VIEWER}"
308309
which = null
309310
workspace = []
310311
workspaces = null
312+
workspaces-update = true
311313
yes = null
312314
313315
; "global" config from {GLOBALPREFIX}/npmrc
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* IMPORTANT
2+
* This snapshot file is auto-generated, but designed for humans.
3+
* It should be checked into source control and tracked carefully.
4+
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
5+
* Make sure to inspect the output below. Do not ignore changes!
6+
*/
7+
'use strict'
8+
exports[`test/lib/commands/version.js TAP empty versions workspaces with one arg, all workspaces > must match snapshot 1`] = `
9+
{
10+
"name": "workspaces-test",
11+
"version": "1.0.0",
12+
"lockfileVersion": 2,
13+
"requires": true,
14+
"packages": {
15+
"": {
16+
"name": "workspaces-test",
17+
"version": "1.0.0",
18+
"workspaces": [
19+
"workspace-a",
20+
"workspace-b"
21+
]
22+
},
23+
"node_modules/workspace-a": {
24+
"resolved": "workspace-a",
25+
"link": true
26+
},
27+
"node_modules/workspace-b": {
28+
"resolved": "workspace-b",
29+
"link": true
30+
},
31+
"workspace-a": {
32+
"version": "2.0.0"
33+
},
34+
"workspace-b": {
35+
"version": "2.0.0"
36+
}
37+
},
38+
"dependencies": {
39+
"workspace-a": {
40+
"version": "file:workspace-a"
41+
},
42+
"workspace-b": {
43+
"version": "file:workspace-b"
44+
}
45+
}
46+
}
47+
48+
`
49+
50+
exports[`test/lib/commands/version.js TAP empty versions workspaces with one arg, all workspaces, saves package.json > must match snapshot 1`] = `
51+
{
52+
"name": "workspaces-test",
53+
"version": "1.0.0",
54+
"lockfileVersion": 2,
55+
"requires": true,
56+
"packages": {
57+
"": {
58+
"name": "workspaces-test",
59+
"version": "1.0.0",
60+
"workspaces": [
61+
"workspace-a",
62+
"workspace-b"
63+
],
64+
"dependencies": {
65+
"workspace-a": "^2.0.0",
66+
"workspace-b": "^2.0.0"
67+
}
68+
},
69+
"node_modules/workspace-a": {
70+
"resolved": "workspace-a",
71+
"link": true
72+
},
73+
"node_modules/workspace-b": {
74+
"resolved": "workspace-b",
75+
"link": true
76+
},
77+
"workspace-a": {
78+
"version": "2.0.0"
79+
},
80+
"workspace-b": {
81+
"version": "2.0.0"
82+
}
83+
},
84+
"dependencies": {
85+
"workspace-a": {
86+
"version": "file:workspace-a"
87+
},
88+
"workspace-b": {
89+
"version": "file:workspace-b"
90+
}
91+
}
92+
}
93+
94+
`

tap-snapshots/test/lib/load-all-commands.js.test.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ Options:
10921092
[--allow-same-version] [--no-commit-hooks] [--no-git-tag-version] [--json]
10931093
[--preid prerelease-id] [--sign-git-tag]
10941094
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
1095-
[-ws|--workspaces] [--include-workspace-root]
1095+
[-ws|--workspaces] [--no-workspaces-update] [--include-workspace-root]
10961096
10971097
alias: verison
10981098

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

+11
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ Array [
151151
"which",
152152
"workspace",
153153
"workspaces",
154+
"workspaces-update",
154155
"yes",
155156
]
156157
`
@@ -1915,6 +1916,16 @@ _unless_ one or more workspaces are specified in the \`workspace\` config.
19151916
This value is not exported to the environment for child processes.
19161917
`
19171918

1919+
exports[`test/lib/utils/config/definitions.js TAP > config description for workspaces-update 1`] = `
1920+
#### \`workspaces-update\`
1921+
1922+
* Default: true
1923+
* Type: Boolean
1924+
1925+
If set to true, the npm cli will run an update after operations that may
1926+
possibly change the workspaces installed to the \`node_modules\` folder.
1927+
`
1928+
19181929
exports[`test/lib/utils/config/definitions.js TAP > config description for yes 1`] = `
19191930
#### \`yes\`
19201931

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

+11
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,17 @@ This value is not exported to the environment for child processes.
16971697
<!-- automatically generated, do not edit manually -->
16981698
<!-- see lib/utils/config/definitions.js -->
16991699
1700+
#### \`workspaces-update\`
1701+
1702+
* Default: true
1703+
* Type: Boolean
1704+
1705+
If set to true, the npm cli will run an update after operations that may
1706+
possibly change the workspaces installed to the \`node_modules\` folder.
1707+
1708+
<!-- automatically generated, do not edit manually -->
1709+
<!-- see lib/utils/config/definitions.js -->
1710+
17001711
#### \`yes\`
17011712
17021713
* Default: null

tap-snapshots/test/lib/utils/npm-usage.js.test.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ All commands:
11251125
[--allow-same-version] [--no-commit-hooks] [--no-git-tag-version] [--json]
11261126
[--preid prerelease-id] [--sign-git-tag]
11271127
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
1128-
[-ws|--workspaces] [--include-workspace-root]
1128+
[-ws|--workspaces] [--no-workspaces-update] [--include-workspace-root]
11291129
11301130
alias: verison
11311131

0 commit comments

Comments
 (0)