Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

publish semver checking bugfixes #8038

Merged
merged 4 commits into from
Jan 17, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(publish): accept publishConfig.tag to override highes semver check
Setting `tag` in `publishConfig` constitutes a "non default" scenario.
  • Loading branch information
wraithgar committed Jan 16, 2025
commit 695471f2afa85399a1b960aa1a21124060c02441
6 changes: 3 additions & 3 deletions lib/commands/publish.js
Original file line number Diff line number Diff line change
@@ -117,7 +117,7 @@ class Publish extends BaseCommand {
manifest = await this.#getManifest(spec, opts, true)

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

if (isPreRelease && isDefaultTag) {
throw new Error('You must specify a tag using --tag when publishing a prerelease version.')
@@ -157,7 +157,7 @@ class Publish extends BaseCommand {
}
}

const latestVersion = await this.#latestPublishedVersion(resolved, registry)
const latestVersion = await this.#highestPublishedVersion(resolved, registry)
const latestSemverIsGreater = !!latestVersion && semver.gte(latestVersion, manifest.version)

if (latestSemverIsGreater && isDefaultTag) {
@@ -204,7 +204,7 @@ class Publish extends BaseCommand {
}
}

async #latestPublishedVersion (spec, registry) {
async #highestPublishedVersion (spec, registry) {
try {
const packument = await pacote.packument(spec, {
...this.npm.flatOptions,
28 changes: 14 additions & 14 deletions tap-snapshots/test/lib/commands/publish.js.test.cjs
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
*/
'use strict'
exports[`test/lib/commands/publish.js TAP _auth config default registry > new package version 1`] = `
+ [email protected]
+ @npmcli/[email protected]
`

exports[`test/lib/commands/publish.js TAP bare _auth and registry config > new package version 1`] = `
@@ -15,15 +15,15 @@ exports[`test/lib/commands/publish.js TAP bare _auth and registry config > new p

exports[`test/lib/commands/publish.js TAP dry-run > must match snapshot 1`] = `
Array [
"package: [email protected]",
"package: @npmcli/[email protected]",
"Tarball Contents",
"87B package.json",
"95B package.json",
"Tarball Details",
"name: test-package",
"name: @npmcli/test-package",
"version: 1.0.0",
"filename: test-package-1.0.0.tgz",
"filename: npmcli-test-package-1.0.0.tgz",
"package size: {size}",
"unpacked size: 87 B",
"unpacked size: 95 B",
"shasum: {sha}",
"integrity: {integrity}
"total files: 1",
@@ -76,7 +76,7 @@ exports[`test/lib/commands/publish.js TAP has token auth for scope configured re
`

exports[`test/lib/commands/publish.js TAP ignore-scripts > new package version 1`] = `
+ [email protected]
+ @npmcli/[email protected]
`

exports[`test/lib/commands/publish.js TAP json > must match snapshot 1`] = `
@@ -87,14 +87,14 @@ Array [

exports[`test/lib/commands/publish.js TAP json > new package json 1`] = `
{
"id": "[email protected]",
"name": "test-package",
"id": "@npmcli/[email protected]",
"name": "@npmcli/test-package",
"version": "1.0.0",
"size": "{size}",
"unpackedSize": 87,
"unpackedSize": 95,
"shasum": "{sha}",
"integrity": "{integrity}",
"filename": "test-package-1.0.0.tgz",
"filename": "npmcli-test-package-1.0.0.tgz",
"files": [
{
"path": "package.json",
@@ -249,7 +249,7 @@ Object {
`

exports[`test/lib/commands/publish.js TAP no auth dry-run > must match snapshot 1`] = `
+ [email protected]
+ @npmcli/[email protected]
`

exports[`test/lib/commands/publish.js TAP no auth dry-run > warns about auth being needed 1`] = `
@@ -259,7 +259,7 @@ Array [
`

exports[`test/lib/commands/publish.js TAP prioritize CLI flags over publishConfig > new package version 1`] = `
+ [email protected]
+ @npmcli/[email protected]
`

exports[`test/lib/commands/publish.js TAP public access > must match snapshot 1`] = `
@@ -285,7 +285,7 @@ exports[`test/lib/commands/publish.js TAP public access > new package version 1`
`

exports[`test/lib/commands/publish.js TAP re-loads publishConfig.registry if added during script process > new package version 1`] = `
+ [email protected]
+ @npmcli/[email protected]
`

exports[`test/lib/commands/publish.js TAP respects publishConfig.registry, runs appropriate scripts > new package version 1`] = `
45 changes: 28 additions & 17 deletions test/lib/commands/publish.js
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ const Arborist = require('@npmcli/arborist')
const path = require('node:path')
const fs = require('node:fs')

const pkg = 'test-package'
const pkg = '@npmcli/test-package'
const token = 'test-auth-token'
const auth = { '//registry.npmjs.org/:_authToken': token }
const alternateRegistry = 'https://other.registry.npmjs.org'
@@ -238,8 +238,7 @@ t.test('throws when invalid tag when not url encodable', async t => {
await t.rejects(
npm.exec('publish', []),
{
/* eslint-disable-next-line max-len */
message: 'Invalid tag name "@test" of package "test-package@@test": Tags may not have any characters that encodeURIComponent encodes.',
message: `Invalid tag name "@test" of package "${pkg}@@test": Tags may not have any characters that encodeURIComponent encodes.`,
}
)
})
@@ -857,15 +856,16 @@ t.test('prerelease dist tag', (t) => {
t.end()
})

t.test('latest dist tag', (t) => {
const init = (version) => ({
t.test('semver highest dist tag', async t => {
const init = ({ version, pkgExtra = {} }) => ({
config: {
loglevel: 'silent',
...auth,
},
prefixDir: {
'package.json': JSON.stringify({
...pkgJson,
...pkgExtra,
version,
}, null, 2),
},
@@ -879,46 +879,57 @@ t.test('latest dist tag', (t) => {
{ version: '105.0.0-pre' },
]

t.test('PREVENTS publish when latest version is HIGHER than publishing version', async t => {
await t.test('PREVENTS publish when highest version is HIGHER than publishing version', async t => {
const version = '99.0.0'
const { npm, registry } = await loadNpmWithRegistry(t, init(version))
const { npm, registry } = await loadNpmWithRegistry(t, init({ version }))
registry.publish(pkg, { noPut: true, packuments })
await t.rejects(async () => {
await npm.exec('publish', [])
/* eslint-disable-next-line max-len */
}, new Error('Cannot implicitly apply the "latest" tag because published version 100.0.0 is higher than the new version 99.0.0. You must specify a tag using --tag.'))
})

t.test('ALLOWS publish when latest is HIGHER than publishing version and flag', async t => {
await t.test('ALLOWS publish when highest is HIGHER than publishing version and flag', async t => {
const version = '99.0.0'
const { npm, registry } = await loadNpmWithRegistry(t, {
...init(version),
...init({ version }),
argv: ['--tag', 'latest'],
})
registry.publish(pkg, { packuments })
await npm.exec('publish', [])
})

t.test('ALLOWS publish when latest versions are LOWER than publishing version', async t => {
await t.test('ALLOWS publish when highest versions are LOWER than publishing version', async t => {
const version = '101.0.0'
const { npm, registry } = await loadNpmWithRegistry(t, init(version))
const { npm, registry } = await loadNpmWithRegistry(t, init({ version }))
registry.publish(pkg, { packuments })
await npm.exec('publish', [])
})

t.test('ALLOWS publish when packument has empty versions (for coverage)', async t => {
await t.test('ALLOWS publish when packument has empty versions (for coverage)', async t => {
const version = '1.0.0'
const { npm, registry } = await loadNpmWithRegistry(t, init(version))
const { npm, registry } = await loadNpmWithRegistry(t, init({ version }))
registry.publish(pkg, { manifest: { versions: { } } })
await npm.exec('publish', [])
})

t.test('ALLOWS publish when packument has empty manifest (for coverage)', async t => {
await t.test('ALLOWS publish when packument has empty manifest (for coverage)', async t => {
const version = '1.0.0'
const { npm, registry } = await loadNpmWithRegistry(t, init(version))
const { npm, registry } = await loadNpmWithRegistry(t, init({ version }))
registry.publish(pkg, { manifest: {} })
await npm.exec('publish', [])
})

t.end()
await t.test('ALLOWS publish when highest version is HIGHER than publishing version with publishConfig', async t => {
const version = '99.0.0'
const { npm, registry } = await loadNpmWithRegistry(t, init({
version,
pkgExtra: {
publishConfig: {
tag: 'next',
},
},
}))
registry.publish(pkg, { packuments })
await npm.exec('publish', [])
})
})