Skip to content

Commit 6e31df4

Browse files
committed
feat(pack): add workspace support
PR-URL: #3033 Credit: @wraithgar Close: #3033 Reviewed-by: @darcyclarke
1 parent 1f3e88e commit 6e31df4

File tree

7 files changed

+161
-8
lines changed

7 files changed

+161
-8
lines changed

docs/content/commands/npm-pack.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,25 @@ description: Create a tarball from a package
1010
npm pack [[<@scope>/]<pkg>...] [--dry-run]
1111
```
1212

13+
### Configuration
14+
15+
#### dry-run
16+
17+
Do everything that pack usually does without actually packing anything.
18+
That is, report on what would have gone into the tarball, but nothing
19+
else.
20+
21+
#### workspaces
22+
23+
Enables workspaces context while creating tarballs. Tarballs for each
24+
workspaces will be generated.
25+
26+
#### workspace
27+
28+
Enables workspaces context and limits results to only those specified by
29+
this config item. Tarballs will only be generated for the packages
30+
named in the workspaces given here.
31+
1332
### Description
1433

1534
For anything that's installable (that is, a package folder, tarball,
@@ -23,10 +42,6 @@ overwritten the second time.
2342

2443
If no arguments are supplied, then npm packs the current package folder.
2544

26-
The `--dry-run` argument will do everything that pack usually does without
27-
actually packing anything. That is, it reports on what would have gone
28-
into the tarball, but nothing else.
29-
3045
### See Also
3146

3247
* [npm-packlist package](http://npm.im/npm-packlist)

lib/pack.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const log = require('npmlog')
33
const pacote = require('pacote')
44
const libpack = require('libnpmpack')
55
const npa = require('npm-package-arg')
6+
const getWorkspaces = require('./workspaces/get-workspaces.js')
67

78
const { getContents, logTar } = require('./utils/tar.js')
89

@@ -23,7 +24,7 @@ class Pack extends BaseCommand {
2324

2425
/* istanbul ignore next - see test/lib/load-all-commands.js */
2526
static get params () {
26-
return ['dry-run']
27+
return ['dry-run', 'workspace', 'workspaces']
2728
}
2829

2930
/* istanbul ignore next - see test/lib/load-all-commands.js */
@@ -35,6 +36,10 @@ class Pack extends BaseCommand {
3536
this.pack(args).then(() => cb()).catch(cb)
3637
}
3738

39+
execWorkspaces (args, filters, cb) {
40+
this.packWorkspaces(args, filters).then(() => cb()).catch(cb)
41+
}
42+
3843
async pack (args) {
3944
if (args.length === 0)
4045
args = ['.']
@@ -62,5 +67,21 @@ class Pack extends BaseCommand {
6267
this.npm.output(tar.filename.replace(/^@/, '').replace(/\//, '-'))
6368
}
6469
}
70+
71+
async packWorkspaces (args, filters) {
72+
// If they either ask for nothing, or explicitly include '.' in the args,
73+
// we effectively translate that into each workspace requested
74+
75+
const useWorkspaces = args.length === 0 || args.includes('.')
76+
77+
if (!useWorkspaces) {
78+
this.npm.log.warn('Ignoring workspaces for specified package(s)')
79+
return this.pack(args)
80+
}
81+
82+
const workspaces =
83+
await getWorkspaces(filters, { path: this.npm.localPrefix })
84+
return this.pack([...workspaces.values(), ...args.filter(a => a !== '.')])
85+
}
6586
}
6687
module.exports = Pack

lib/view.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ class View extends BaseCommand {
151151

152152
const local = /^\.@/.test(pkg) || pkg === '.'
153153
if (!local) {
154-
this.npm.log.warn('Ignoring workspaces for remote package')
154+
this.npm.log.warn('Ignoring workspaces for specified package(s)')
155155
return this.view([pkg, ...args])
156156
}
157157
let wholePackument = false

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ All commands:
625625
npm pack [[<@scope>/]<pkg>...]
626626
627627
Options:
628-
[--dry-run]
628+
[--dry-run] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces]
629629
630630
Run "npm help pack" for more info
631631

tap-snapshots/test-lib-view.js-TAP.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ dist-tags:
450450
`
451451

452452
exports[`test/lib/view.js TAP workspaces remote package name > must match snapshot 1`] = `
453-
Ignoring workspaces for remote package
453+
Ignoring workspaces for specified package(s)
454454
`
455455

456456
exports[`test/lib/view.js TAP workspaces remote package name > must match snapshot 2`] = `

test/fixtures/mock-npm.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,24 @@
22
// npm.config You still need a separate flatOptions but this is the first step
33
// to eventually just using npm itself
44

5+
const mockLog = {
6+
clearProgress: () => {},
7+
disableProgress: () => {},
8+
enableProgress: () => {},
9+
http: () => {},
10+
info: () => {},
11+
levels: [],
12+
notice: () => {},
13+
pause: () => {},
14+
silly: () => {},
15+
verbose: () => {},
16+
warn: () => {},
17+
}
518
const mockNpm = (base = {}) => {
619
const config = base.config || {}
720
const flatOptions = base.flatOptions || {}
821
return {
22+
log: mockLog,
923
...base,
1024
flatOptions,
1125
config: {

test/lib/pack.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const t = require('tap')
22
const requireInject = require('require-inject')
33
const mockNpm = require('../fixtures/mock-npm')
4+
const pacote = require('pacote')
45

56
const OUTPUT = []
67
const output = (...msg) => OUTPUT.push(msg)
@@ -11,6 +12,16 @@ const libnpmpack = async (spec, opts) => {
1112

1213
return ''
1314
}
15+
const mockPacote = {
16+
manifest: (spec) => {
17+
if (spec.type === 'directory')
18+
return pacote.manifest(spec)
19+
return {
20+
name: spec.name || 'test-package',
21+
version: spec.version || '1.0.0-test',
22+
}
23+
},
24+
}
1425

1526
t.afterEach(cb => {
1627
OUTPUT.length = 0
@@ -152,3 +163,95 @@ t.test('should log pack contents', (t) => {
152163
t.end()
153164
})
154165
})
166+
167+
t.test('workspaces', (t) => {
168+
const testDir = t.testdir({
169+
'package.json': JSON.stringify({
170+
name: 'workspaces-test',
171+
version: '1.0.0',
172+
workspaces: ['workspace-a', 'workspace-b'],
173+
}, null, 2),
174+
'workspace-a': {
175+
'package.json': JSON.stringify({
176+
name: 'workspace-a',
177+
version: '1.0.0',
178+
}),
179+
},
180+
'workspace-b': {
181+
'package.json': JSON.stringify({
182+
name: 'workspace-b',
183+
version: '1.0.0',
184+
}),
185+
},
186+
})
187+
const Pack = requireInject('../../lib/pack.js', {
188+
libnpmpack,
189+
pacote: mockPacote,
190+
npmlog: {
191+
notice: () => {},
192+
showProgress: () => {},
193+
clearProgress: () => {},
194+
},
195+
})
196+
const npm = mockNpm({
197+
localPrefix: testDir,
198+
config: {
199+
unicode: false,
200+
json: false,
201+
'dry-run': false,
202+
},
203+
output,
204+
})
205+
const pack = new Pack(npm)
206+
207+
t.test('all workspaces', (t) => {
208+
pack.execWorkspaces([], [], er => {
209+
if (er)
210+
throw er
211+
212+
t.strictSame(OUTPUT, [
213+
['workspace-a-1.0.0.tgz'],
214+
['workspace-b-1.0.0.tgz'],
215+
])
216+
t.end()
217+
})
218+
})
219+
220+
t.test('all workspaces, `.` first arg', (t) => {
221+
pack.execWorkspaces(['.'], [], er => {
222+
if (er)
223+
throw er
224+
225+
t.strictSame(OUTPUT, [
226+
['workspace-a-1.0.0.tgz'],
227+
['workspace-b-1.0.0.tgz'],
228+
])
229+
t.end()
230+
})
231+
})
232+
233+
t.test('one workspace', (t) => {
234+
pack.execWorkspaces([], ['workspace-a'], er => {
235+
if (er)
236+
throw er
237+
238+
t.strictSame(OUTPUT, [
239+
['workspace-a-1.0.0.tgz'],
240+
])
241+
t.end()
242+
})
243+
})
244+
245+
t.test('specific package', (t) => {
246+
pack.execWorkspaces(['abbrev'], [], er => {
247+
if (er)
248+
throw er
249+
250+
t.strictSame(OUTPUT, [
251+
['abbrev-1.0.0-test.tgz'],
252+
])
253+
t.end()
254+
})
255+
})
256+
t.end()
257+
})

0 commit comments

Comments
 (0)