Skip to content

Commit

Permalink
fix!: publishing prerelease requires explicit tag (npm#7910)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: When publishing a package with a pre-release version,
you must explicitly specify a tag.
 
ref: npm/statusboard#898
  • Loading branch information
reggi authored Nov 25, 2024
1 parent 6995303 commit 16b7367
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
7 changes: 7 additions & 0 deletions lib/commands/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ class Publish extends BaseCommand {
// note that publishConfig might have changed as well!
manifest = await this.#getManifest(spec, opts, true)

const isPreRelease = Boolean(semver.parse(manifest.version).prerelease.length)
const isDefaultTag = this.npm.config.isDefault('tag')

if (isPreRelease && isDefaultTag) {
throw new Error('You must specify a tag using --tag when publishing a prerelease version')
}

// If we are not in JSON mode then we show the user the contents of the tarball
// before it is published so they can see it while their otp is pending
if (!json) {
Expand Down
80 changes: 80 additions & 0 deletions test/lib/commands/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ t.test('workspaces', t => {
t.test('all workspaces - no color', async t => {
const { npm, joinedOutput, logs } = await loadMockNpm(t, {
config: {
tag: 'latest',
color: false,
...auth,
workspaces: true,
Expand Down Expand Up @@ -551,6 +552,7 @@ t.test('workspaces', t => {
const { npm, joinedOutput, logs } = await loadMockNpm(t, {
config: {
...auth,
tag: 'latest',
color: 'always',
workspaces: true,
},
Expand Down Expand Up @@ -580,6 +582,7 @@ t.test('workspaces', t => {
const { npm, joinedOutput } = await loadMockNpm(t, {
config: {
...auth,
tag: 'latest',
workspace: ['workspace-a'],
},
prefixDir: dir,
Expand All @@ -601,6 +604,7 @@ t.test('workspaces', t => {
const { npm } = await loadMockNpm(t, {
config: {
...auth,
tag: 'latest',
workspace: ['workspace-a'],
},
prefixDir: dir,
Expand Down Expand Up @@ -642,6 +646,7 @@ t.test('workspaces', t => {
const { npm, joinedOutput } = await loadMockNpm(t, {
config: {
...auth,
tag: 'latest',
workspaces: true,
},
prefixDir: testDir,
Expand All @@ -663,6 +668,7 @@ t.test('workspaces', t => {
const { npm } = await loadMockNpm(t, {
config: {
...auth,
tag: 'latest',
workspace: ['workspace-x'],
},
prefixDir: dir,
Expand All @@ -677,6 +683,7 @@ t.test('workspaces', t => {
const { npm, joinedOutput } = await loadMockNpm(t, {
config: {
...auth,
tag: 'latest',
workspaces: true,
json: true,
},
Expand Down Expand Up @@ -725,6 +732,7 @@ t.test('workspaces', t => {
const { npm, joinedOutput } = await loadMockNpm(t, {
config: {
...auth,
tag: 'latest',
},
prefixDir: testDir,
chdir: ({ prefix }) => path.resolve(prefix, './workspace-a'),
Expand Down Expand Up @@ -988,3 +996,75 @@ t.test('manifest', async t => {

t.matchSnapshot(manifest, 'manifest')
})

t.test('aborts when prerelease and no tag', async t => {
const { npm } = await loadMockNpm(t, {
config: {
loglevel: 'silent',
[`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token',
},
prefixDir: {
'package.json': JSON.stringify({
...pkgJson,
version: '1.0.0-0',
publishConfig: { registry: alternateRegistry },
}, null, 2),
},
})

await t.rejects(async () => {
await npm.exec('publish', [])
}, new Error('You must specify a tag using --tag when publishing a prerelease version'))
})

t.test('does not abort when prerelease and authored tag latest', async t => {
const prereleasePkg = {
...pkgJson,
version: '1.0.0-0',
}
const { npm } = await loadMockNpm(t, {
config: {
loglevel: 'silent',
tag: 'latest',
[`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token',
},
prefixDir: {
'package.json': JSON.stringify({
...prereleasePkg,
publishConfig: { registry: alternateRegistry },
}, null, 2),
},
})
const registry = new MockRegistry({
tap: t,
registry: alternateRegistry,
authorization: 'test-other-token',
})
registry.nock.put(`/${pkg}`, body => {
return t.match(body, {
_id: pkg,
name: pkg,
'dist-tags': { latest: prereleasePkg.version },
access: null,
versions: {
[prereleasePkg.version]: {
name: pkg,
version: prereleasePkg.version,
_id: `${pkg}@${prereleasePkg.version}`,
dist: {
shasum: /\.*/,
// eslint-disable-next-line max-len
tarball: `http:${alternateRegistry.slice(6)}/test-package/-/test-package-${prereleasePkg.version}.tgz`,
},
publishConfig: {
registry: alternateRegistry,
},
},
},
_attachments: {
[`${pkg}-${prereleasePkg.version}.tgz`]: {},
},
})
}).reply(200, {})
await npm.exec('publish', [])
})

0 comments on commit 16b7367

Please sign in to comment.