Skip to content

Commit 71915e8

Browse files
authored
fix: exempt explicit pack targets from allow-directory (#9756)
## Summary - allow explicit directory targets through `npm pack` and `npm publish` when `allow-directory` is `none` or `root` - keep dependency fetch policies unchanged and cover the shared library plus both CLI commands ## Why `allow-directory` restricts directory dependencies, but the local package selected for packing or publishing is the command target. The current flow applies the dependency policy to that target during manifest or tarball preparation. Closes #9755. ## Validation - `node . run test` - passed (123 test files, 100% coverage) - `node . run test -w libnpmpack` - passed (100% coverage) - dry-run `pack` and `publish` smokes with `allow-directory=none|root` - passed Co-authored-by: ychampion <ychampion@users.noreply.github.com>
1 parent 8723f53 commit 71915e8

5 files changed

Lines changed: 58 additions & 0 deletions

File tree

lib/commands/pack.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Pack extends BaseCommand {
4545
) ? { ...this.npm.flatOptions, before: null } : this.npm.flatOptions
4646
const manifest = await pacote.manifest(spec, {
4747
...options,
48+
...(spec.type === 'directory' && { allowDirectory: 'all' }),
4849
Arborist,
4950
preferOnline: true,
5051
_isRoot: true,

test/lib/commands/pack.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,25 @@ t.test('dry run', async t => {
112112
t.throws(() => fs.statSync(path.resolve(npm.prefix, filename)))
113113
})
114114

115+
for (const allowDirectory of ['none', 'root']) {
116+
t.test(`dry run with allow-directory=${allowDirectory}`, async t => {
117+
const { npm, outputs } = await loadMockNpm(t, {
118+
prefixDir: {
119+
'package.json': JSON.stringify({
120+
name: 'test-package',
121+
version: '1.0.0',
122+
}),
123+
},
124+
config: {
125+
'allow-directory': allowDirectory,
126+
'dry-run': true,
127+
},
128+
})
129+
await npm.exec('pack', [])
130+
t.strictSame(outputs, ['test-package-1.0.0.tgz'])
131+
})
132+
}
133+
115134
t.test('foreground-scripts defaults to true', async t => {
116135
const { npm, outputs, logs } = await loadMockNpm(t, {
117136
prefixDir: {

test/lib/commands/publish.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,25 @@ t.test('dry-run', async t => {
151151
t.matchSnapshot(logs.notice)
152152
})
153153

154+
for (const allowDirectory of ['none', 'root']) {
155+
t.test(`dry-run with allow-directory=${allowDirectory}`, async t => {
156+
const { joinedOutput, npm, registry } = await loadNpmWithRegistry(t, {
157+
config: {
158+
'allow-directory': allowDirectory,
159+
'dry-run': true,
160+
...auth,
161+
},
162+
prefixDir: {
163+
'package.json': JSON.stringify(pkgJson, null, 2),
164+
},
165+
authorization: token,
166+
})
167+
registry.publish(pkg, { noPut: true })
168+
await npm.exec('publish', [])
169+
t.equal(joinedOutput(), `+ ${pkg}@1.0.0`)
170+
})
171+
}
172+
154173
t.test('foreground-scripts defaults to true', async t => {
155174
const { outputs, npm, logs, registry } = await loadNpmWithRegistry(t, {
156175
config: {

workspaces/libnpmpack/lib/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ async function pack (spec = 'file:.', opts = {}) {
1212
// gets spec
1313
spec = npa(spec)
1414

15+
// An explicit directory is the package being packed, not a dependency fetch.
16+
if (spec.type === 'directory') {
17+
opts = { ...opts, allowDirectory: 'all' }
18+
}
19+
1520
const manifest = await pacote.manifest(spec, { ...opts, Arborist, _isRoot: true })
1621

1722
if (spec.type === 'directory') {

workspaces/libnpmpack/test/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ t.test('packs from local directory', async t => {
3636
})
3737
})
3838

39+
for (const allowDirectory of ['none', 'root']) {
40+
t.test(`packs an explicit local directory with allow-directory=${allowDirectory}`, async t => {
41+
const testDir = t.testdir({
42+
'package.json': JSON.stringify({
43+
name: 'my-cool-pkg',
44+
version: '1.0.0',
45+
}, null, 2),
46+
})
47+
48+
const tarball = await pack(testDir, { allowDirectory })
49+
t.ok(tarball)
50+
})
51+
}
52+
3953
t.test('flattens path separators in name so tarball stays in packDestination', async t => {
4054
const testDir = t.testdir({
4155
src: {

0 commit comments

Comments
 (0)