Files
pnpm/pnpm11/__utils__/scripts/test/bump.ts
T
Zoltan KochanandClaude Fable 5 cbf8fbae0d fix(scripts): accept the leading -- forwarded by pnpm run bump (#13507)
pnpm run forwards everything after the script name to the script verbatim,
including the -- separator itself, so the create-release-pr workflow's
`pnpm run bump -- --release <product>` invocations delivered a literal --
as the first argument and the fail-closed parser rejected it.

parseSelectedProducts now skips a single leading --; a -- in any other
position, and any other unrecognized token, still fails closed.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 20:14:42 +02:00

82 lines
3.1 KiB
TypeScript

import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { afterEach, beforeEach, describe, expect, test } from '@jest/globals'
import { findRepoRoot, parseSelectedProducts, releaseFilterArgs } from '../src/bump.js'
describe('findRepoRoot', () => {
let dir: string
beforeEach(() => {
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bump-root-'))
})
afterEach(() => fs.rmSync(dir, { recursive: true, force: true }))
test('walks up to the directory containing .changeset', () => {
fs.mkdirSync(path.join(dir, '.changeset'))
const nested = path.join(dir, 'pnpm11', '__utils__', 'scripts', 'src')
fs.mkdirSync(nested, { recursive: true })
expect(findRepoRoot(nested)).toBe(dir)
})
test('throws when no .changeset directory exists above', () => {
expect(() => findRepoRoot(dir)).toThrow(/No \.changeset directory/)
})
})
describe('parseSelectedProducts', () => {
test('collects the products named by --release', () => {
expect(parseSelectedProducts(['--release', 'pnpm11', '--release', 'pnpr']))
.toEqual(new Set(['pnpm11', 'pnpr']))
})
test('is empty when no argument is passed (a bare `pnpm bump` releases everything)', () => {
expect(parseSelectedProducts([])).toEqual(new Set())
})
test('skips the leading `--` separator forwarded by `pnpm run bump -- …`', () => {
expect(parseSelectedProducts(['--', '--release', 'pnpm', '--release', 'pnpr']))
.toEqual(new Set(['pnpm', 'pnpr']))
expect(parseSelectedProducts(['--'])).toEqual(new Set())
})
test('rejects a `--` that is not in the leading position', () => {
expect(() => parseSelectedProducts(['--release', 'pnpm', '--'])).toThrow(/Unexpected bump argument/)
})
test('throws on an unknown product', () => {
expect(() => parseSelectedProducts(['--release', 'bogus'])).toThrow(/Unknown --release product/)
})
test('fails closed on a misspelled flag instead of releasing everything', () => {
expect(() => parseSelectedProducts(['--releases', 'pnpr'])).toThrow(/Unexpected bump argument/)
})
})
describe('releaseFilterArgs', () => {
test('releases everything (no filter) when nothing is selected', () => {
expect(releaseFilterArgs(new Set())).toEqual([])
})
test('releases everything (no filter) when all three products are selected', () => {
expect(releaseFilterArgs(new Set(['pnpm11', 'pnpm', 'pnpr']))).toEqual([])
})
test('excludes the unselected alpha products when pnpm11 is selected', () => {
expect(releaseFilterArgs(new Set(['pnpm11'])))
.toEqual(['--filter=!pacquet', '--filter=!@pnpm/napi', '--filter=!@pnpm/pnpr'])
expect(releaseFilterArgs(new Set(['pnpm11', 'pnpr'])))
.toEqual(['--filter=!pacquet', '--filter=!@pnpm/napi'])
})
test('includes only the selected alpha products when pnpm11 is not selected', () => {
expect(releaseFilterArgs(new Set(['pnpm'])))
.toEqual(['--filter=pacquet', '--filter=@pnpm/napi'])
expect(releaseFilterArgs(new Set(['pnpm', 'pnpr'])))
.toEqual(['--filter=pacquet', '--filter=@pnpm/napi', '--filter=@pnpm/pnpr'])
expect(releaseFilterArgs(new Set(['pnpr'])))
.toEqual(['--filter=@pnpm/pnpr'])
})
})