diff --git a/lib/commands/pack.js b/lib/commands/pack.js index 3918c77f8f53c..dfdaff49703d2 100644 --- a/lib/commands/pack.js +++ b/lib/commands/pack.js @@ -46,6 +46,7 @@ class Pack extends BaseCommand { const manifest = await pacote.manifest(spec, { ...options, ...(spec.type === 'directory' && { allowDirectory: 'all' }), + ...(spec.type === 'file' && { allowFile: 'all' }), Arborist, preferOnline: true, _isRoot: true, diff --git a/lib/commands/publish.js b/lib/commands/publish.js index a18b6f0c81bcc..f2c4a10124500 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -312,6 +312,7 @@ class Publish extends BaseCommand { } else { manifest = await pacote.manifest(spec, { ...opts, + ...(spec.type === 'file' && { allowFile: 'all' }), fullMetadata: true, fullReadJson: true, }) diff --git a/test/lib/commands/pack.js b/test/lib/commands/pack.js index fa53c4da7853a..ea903e1bc2004 100644 --- a/test/lib/commands/pack.js +++ b/test/lib/commands/pack.js @@ -2,6 +2,8 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const { cleanZlib } = require('../../fixtures/clean-snapshot') const MockRegistry = require('@npmcli/mock-registry') +const pacote = require('pacote') +const Arborist = require('@npmcli/arborist') const path = require('node:path') const fs = require('node:fs') @@ -131,6 +133,27 @@ for (const allowDirectory of ['none', 'root']) { }) } +for (const allowFile of ['none', 'root']) { + t.test(`dry run of a tarball with allow-file=${allowFile}`, async t => { + const { npm, outputs, prefix } = await loadMockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-package', + version: '1.0.0', + }), + }, + config: { + 'allow-file': allowFile, + 'dry-run': true, + }, + }) + const tarFilename = path.join(prefix, 'tarball.tgz') + fs.writeFileSync(tarFilename, await pacote.tarball(prefix, { Arborist })) + await npm.exec('pack', [tarFilename]) + t.strictSame(outputs, ['test-package-1.0.0.tgz']) + }) +} + t.test('foreground-scripts defaults to true', async t => { const { npm, outputs, logs } = await loadMockNpm(t, { prefixDir: { diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index 9ddca285488a7..351b3dda28a35 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -353,6 +353,27 @@ t.test('tarball', async t => { t.matchSnapshot(joinedOutput(), 'new package json') }) +for (const allowFile of ['none', 'root']) { + t.test(`tarball with allow-file=${allowFile}`, async t => { + const { npm, joinedOutput, home, registry } = await loadNpmWithRegistry(t, { + config: { + 'allow-file': allowFile, + 'dry-run': true, + ...auth, + }, + homeDir: { + 'package.json': JSON.stringify(pkgJson, null, 2), + }, + authorization: token, + }) + const tarFilename = path.join(home, 'tarball.tgz') + fs.writeFileSync(tarFilename, await pacote.tarball(home, { Arborist })) + registry.publish(pkg, { noPut: true }) + await npm.exec('publish', [tarFilename]) + t.equal(joinedOutput(), `+ ${pkg}@1.0.0`) + }) +} + t.test('no auth default registry', async t => { const { npm } = await loadNpmWithRegistry(t, { prefixDir: { diff --git a/workspaces/libnpmpack/lib/index.js b/workspaces/libnpmpack/lib/index.js index 8bf68e2a400e9..b9598ac90d8d3 100644 --- a/workspaces/libnpmpack/lib/index.js +++ b/workspaces/libnpmpack/lib/index.js @@ -12,9 +12,11 @@ async function pack (spec = 'file:.', opts = {}) { // gets spec spec = npa(spec) - // An explicit directory is the package being packed, not a dependency fetch. + // An explicit directory or tarball is the package being packed, not a dependency fetch. if (spec.type === 'directory') { opts = { ...opts, allowDirectory: 'all' } + } else if (spec.type === 'file') { + opts = { ...opts, allowFile: 'all' } } const manifest = await pacote.manifest(spec, { ...opts, Arborist, _isRoot: true }) diff --git a/workspaces/libnpmpack/test/index.js b/workspaces/libnpmpack/test/index.js index c6518b09b6570..3e82fd526fcbb 100644 --- a/workspaces/libnpmpack/test/index.js +++ b/workspaces/libnpmpack/test/index.js @@ -50,6 +50,22 @@ for (const allowDirectory of ['none', 'root']) { }) } +for (const allowFile of ['none', 'root']) { + t.test(`packs an explicit local tarball with allow-file=${allowFile}`, async t => { + const testDir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'my-cool-pkg', + version: '1.0.0', + }, null, 2), + }) + const tarFilename = path.join(testDir, 'my-cool-pkg-1.0.0.tgz') + fs.writeFileSync(tarFilename, await pack(testDir)) + + const tarball = await pack(tarFilename, { allowFile }) + t.ok(tarball) + }) +} + t.test('flattens path separators in name so tarball stays in packDestination', async t => { const testDir = t.testdir({ src: {