Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 95f2014

Browse files
committedMay 11, 2021
feat(publish): add workspace support
Errors will make things stop altogether, dunno if we want to bikeshed that here or not
1 parent 659751f commit 95f2014

File tree

5 files changed

+263
-29
lines changed

5 files changed

+263
-29
lines changed
 

‎docs/content/commands/npm-publish.md

+7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ by specifying a different default registry or using a
4747
actually publishing to the registry. Reports the details of what would
4848
have been published.
4949
50+
* `[--workspaces]`: Enables workspace context while publishing. All
51+
workspace packages will be published.
52+
53+
* `[--workspace]`: Enables workspaces context and limits results to only
54+
those specified by this config item. Only the packages in the
55+
workspaces given will be published.
56+
5057
The publish will fail if the package name and version combination already
5158
exists in the specified registry.
5259

‎lib/publish.js

+39-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const npmFetch = require('npm-registry-fetch')
1111
const flatten = require('./utils/config/flatten.js')
1212
const otplease = require('./utils/otplease.js')
1313
const { getContents, logTar } = require('./utils/tar.js')
14+
const getWorkspaces = require('./workspaces/get-workspaces.js')
1415

1516
// this is the only case in the CLI where we use the old full slow
1617
// 'read-package-json' module, because we want to pull in all the
@@ -30,7 +31,7 @@ class Publish extends BaseCommand {
3031

3132
/* istanbul ignore next - see test/lib/load-all-commands.js */
3233
static get params () {
33-
return ['tag', 'access', 'dry-run']
34+
return ['tag', 'access', 'dry-run', 'workspace', 'workspaces']
3435
}
3536

3637
/* istanbul ignore next - see test/lib/load-all-commands.js */
@@ -44,6 +45,10 @@ class Publish extends BaseCommand {
4445
this.publish(args).then(() => cb()).catch(cb)
4546
}
4647

48+
execWorkspaces (args, filters, cb) {
49+
this.publishWorkspaces(args, filters).then(() => cb()).catch(cb)
50+
}
51+
4752
async publish (args) {
4853
if (args.length === 0)
4954
args = ['.']
@@ -56,6 +61,7 @@ class Publish extends BaseCommand {
5661
const dryRun = this.npm.config.get('dry-run')
5762
const json = this.npm.config.get('json')
5863
const defaultTag = this.npm.config.get('tag')
64+
const silent = log.level === 'silent'
5965

6066
if (semver.validRange(defaultTag))
6167
throw new Error('Tag name must not be a valid SemVer range: ' + defaultTag.trim())
@@ -77,7 +83,7 @@ class Publish extends BaseCommand {
7783
path: spec.fetchSpec,
7884
stdio: 'inherit',
7985
pkg: manifest,
80-
banner: log.level !== 'silent',
86+
banner: !silent,
8187
})
8288
}
8389

@@ -114,27 +120,51 @@ class Publish extends BaseCommand {
114120
path: spec.fetchSpec,
115121
stdio: 'inherit',
116122
pkg: manifest,
117-
banner: log.level !== 'silent',
123+
banner: !silent,
118124
})
119125

120126
await runScript({
121127
event: 'postpublish',
122128
path: spec.fetchSpec,
123129
stdio: 'inherit',
124130
pkg: manifest,
125-
banner: log.level !== 'silent',
131+
banner: !silent,
126132
})
127133
}
128134

129-
const silent = log.level === 'silent'
130-
if (!silent && json)
131-
this.npm.output(JSON.stringify(pkgContents, null, 2))
132-
else if (!silent)
133-
this.npm.output(`+ ${pkgContents.id}`)
135+
if (!this.workspaces) {
136+
if (!silent && json)
137+
this.npm.output(JSON.stringify(pkgContents, null, 2))
138+
else if (!silent)
139+
this.npm.output(`+ ${pkgContents.id}`)
140+
}
134141

135142
return pkgContents
136143
}
137144

145+
async publishWorkspaces (args, filters) {
146+
// Suppresses JSON output in publish() so we can handle it here
147+
this.workspaces = true
148+
149+
const results = {}
150+
const json = this.npm.config.get('json')
151+
const silent = log.level === 'silent'
152+
const workspaces =
153+
await getWorkspaces(filters, { path: this.npm.localPrefix })
154+
for (const [name, workspace] of workspaces.entries()) {
155+
const pkgContents = await this.publish([workspace])
156+
// This needs to be in-line w/ the rest of the output that non-JSON
157+
// publish generates
158+
if (!silent && !json)
159+
this.npm.output(`+ ${pkgContents.id}`)
160+
else
161+
results[name] = pkgContents
162+
}
163+
164+
if (!silent && json)
165+
this.npm.output(JSON.stringify(results, null, 2))
166+
}
167+
138168
// if it's a directory, read it from the file system
139169
// otherwise, get the full metadata from whatever it is
140170
getManifest (spec, opts) {

‎tap-snapshots/test/lib/publish.js.test.cjs

+103
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,109 @@ npm publish [<folder>]
1515
1616
Options:
1717
[--tag <tag>] [--access <restricted|public>] [--dry-run]
18+
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
19+
[-ws|--workspaces]
1820
1921
Run "npm help publish" for more info
2022
`
23+
24+
exports[`test/lib/publish.js TAP workspaces all workspaces > should output all publishes 1`] = `
25+
Array [
26+
"+ workspace-a@1.2.3-a",
27+
"+ workspace-b@1.2.3-n",
28+
]
29+
`
30+
31+
exports[`test/lib/publish.js TAP workspaces all workspaces > should publish all workspaces 1`] = `
32+
Array [
33+
Object {
34+
"_id": "workspace-a@1.2.3-a",
35+
"name": "workspace-a",
36+
"readme": "ERROR: No README data found!",
37+
"repository": Object {
38+
"type": "git",
39+
"url": "http://repo.workspace-a/",
40+
},
41+
"version": "1.2.3-a",
42+
},
43+
Object {
44+
"_id": "workspace-b@1.2.3-n",
45+
"bugs": Object {
46+
"url": "https://github.com/npm/workspace-b/issues",
47+
},
48+
"homepage": "https://github.com/npm/workspace-b#readme",
49+
"name": "workspace-b",
50+
"readme": "ERROR: No README data found!",
51+
"repository": Object {
52+
"type": "git",
53+
"url": "git+https://github.com/npm/workspace-b.git",
54+
},
55+
"version": "1.2.3-n",
56+
},
57+
]
58+
`
59+
60+
exports[`test/lib/publish.js TAP workspaces json > should output all publishes as json 1`] = `
61+
Array [
62+
String(
63+
{
64+
"workspace-a": {
65+
"id": "workspace-a@1.2.3-a"
66+
},
67+
"workspace-b": {
68+
"id": "workspace-b@1.2.3-n"
69+
}
70+
}
71+
),
72+
]
73+
`
74+
75+
exports[`test/lib/publish.js TAP workspaces json > should publish all workspaces 1`] = `
76+
Array [
77+
Object {
78+
"_id": "workspace-a@1.2.3-a",
79+
"name": "workspace-a",
80+
"readme": "ERROR: No README data found!",
81+
"repository": Object {
82+
"type": "git",
83+
"url": "http://repo.workspace-a/",
84+
},
85+
"version": "1.2.3-a",
86+
},
87+
Object {
88+
"_id": "workspace-b@1.2.3-n",
89+
"bugs": Object {
90+
"url": "https://github.com/npm/workspace-b/issues",
91+
},
92+
"homepage": "https://github.com/npm/workspace-b#readme",
93+
"name": "workspace-b",
94+
"readme": "ERROR: No README data found!",
95+
"repository": Object {
96+
"type": "git",
97+
"url": "git+https://github.com/npm/workspace-b.git",
98+
},
99+
"version": "1.2.3-n",
100+
},
101+
]
102+
`
103+
104+
exports[`test/lib/publish.js TAP workspaces one workspace > should output one publish 1`] = `
105+
Array [
106+
"+ workspace-a@1.2.3-a",
107+
]
108+
`
109+
110+
exports[`test/lib/publish.js TAP workspaces one workspace > should publish given workspace 1`] = `
111+
Array [
112+
Object {
113+
"_id": "workspace-a@1.2.3-a",
114+
"name": "workspace-a",
115+
"readme": "ERROR: No README data found!",
116+
"repository": Object {
117+
"type": "git",
118+
"url": "http://repo.workspace-a/",
119+
},
120+
"version": "1.2.3-a",
121+
},
122+
]
123+
`

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

+2
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,8 @@ All commands:
697697
698698
Options:
699699
[--tag <tag>] [--access <restricted|public>] [--dry-run]
700+
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
701+
[-ws|--workspaces]
700702
701703
Run "npm help publish" for more info
702704
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.