feat(js): support publishing with registryConfigKey when pnpm >=9.15.7 <10.0.0 || >=10.5.0 (#31622)

This commit is contained in:
Jonathan Gelin 2025-06-18 11:16:59 +02:00 committed by GitHub
parent 5c2fdc9e31
commit 578405862d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 94 additions and 9 deletions

View File

@ -1,5 +1,6 @@
import { import {
detectPackageManager, detectPackageManager,
getPackageManagerCommand,
ExecutorContext, ExecutorContext,
readJsonFile, readJsonFile,
} from '@nx/devkit'; } from '@nx/devkit';
@ -263,14 +264,9 @@ Please update the local dependency on "${depName}" to be a valid semantic versio
* to running from the package root directly), then special attention should be paid to the fact that npm/pnpm publish will nest its * to running from the package root directly), then special attention should be paid to the fact that npm/pnpm publish will nest its
* JSON output under the name of the package in that case (and it would need to be handled below). * JSON output under the name of the package in that case (and it would need to be handled below).
*/ */
const pmCommand = getPackageManagerCommand(pm);
const publishCommandSegments = [ const publishCommandSegments = [
pm === 'bun' pmCommand.publish(packageRoot, registry, registryConfigKey, tag),
? // Unlike npm, bun publish does not support a custom registryConfigKey option
`bun publish --cwd="${packageRoot}" --json --registry="${registry}" --tag=${tag}`
: pm === 'pnpm'
? // Unlike npm, pnpm publish does not support a custom registryConfigKey option, and will error on uncommitted changes by default if --no-git-checks is not set
`pnpm publish "${packageRoot}" --json --registry="${registry}" --tag=${tag} --no-git-checks`
: `npm publish "${packageRoot}" --json --"${registryConfigKey}=${registry}" --tag=${tag}`,
]; ];
if (options.otp) { if (options.otp) {

View File

@ -10,6 +10,7 @@ import * as fileUtils from '../utils/fileutils';
import { import {
addPackagePathToWorkspaces, addPackagePathToWorkspaces,
detectPackageManager, detectPackageManager,
getPackageManagerCommand,
getPackageManagerVersion, getPackageManagerVersion,
getPackageWorkspaces, getPackageWorkspaces,
isWorkspacesEnabled, isWorkspacesEnabled,
@ -547,4 +548,66 @@ describe('package-manager', () => {
).toEqual('3.2.3'); ).toEqual('3.2.3');
}); });
}); });
describe('getPackageManagerCommand', () => {
const publishCmdParam: [string, string, string, string] = [
'dist/packages/my-pkg',
'https://registry.npmjs.org/',
'@org:registry',
'latest',
];
afterEach(() => {
jest.restoreAllMocks();
});
it('should return npm publish command', () => {
const commands = getPackageManagerCommand('npm');
expect(commands.publish(...publishCmdParam)).toEqual(
'npm publish "dist/packages/my-pkg" --json --"@org:registry=https://registry.npmjs.org/" --tag=latest'
);
});
it('should return yarn publish command using npm publish', () => {
const commands = getPackageManagerCommand('yarn');
expect(commands.publish(...publishCmdParam)).toEqual(
'npm publish "dist/packages/my-pkg" --json --"@org:registry=https://registry.npmjs.org/" --tag=latest'
);
});
it('should return pnpm publish command with scoped registry when provided for pnpm version >= 9.15.7 < 10.0.0 || >= 10.5.0', () => {
jest.spyOn(childProcess, 'execSync').mockImplementation((p) => {
switch (p) {
case 'pnpm --version':
return '9.15.7';
}
});
const commands = getPackageManagerCommand('pnpm');
expect(commands.publish(...publishCmdParam)).toEqual(
'pnpm publish "dist/packages/my-pkg" --json --"@org:registry=https://registry.npmjs.org/" --tag=latest --no-git-checks'
);
});
it('should return pnpm publish command without use scoped registry for pnpm version < 9.15.7', () => {
jest.spyOn(childProcess, 'execSync').mockImplementation((p) => {
switch (p) {
case 'pnpm --version':
return '9.10.1';
default:
throw new Error('Command failed');
}
});
jest.spyOn(fileUtils, 'readJsonFile').mockReturnValueOnce({});
const commands = getPackageManagerCommand('pnpm');
expect(commands.publish(...publishCmdParam)).toEqual(
'pnpm publish "dist/packages/my-pkg" --json --"registry=https://registry.npmjs.org/" --tag=latest --no-git-checks'
);
});
it('should return bun publish command with registry and tag', () => {
const commands = getPackageManagerCommand('bun');
expect(commands.publish(...publishCmdParam)).toEqual(
'bun publish --cwd="dist/packages/my-pkg" --json --registry="https://registry.npmjs.org/" --tag=latest'
);
});
});
}); });

View File

@ -11,7 +11,7 @@ import {
} from 'yaml'; } from 'yaml';
import { rm } from 'node:fs/promises'; import { rm } from 'node:fs/promises';
import { dirname, join, relative } from 'path'; import { dirname, join, relative } from 'path';
import { gte, lt, parse } from 'semver'; import { gte, lt, parse, satisfies } from 'semver';
import { dirSync } from 'tmp'; import { dirSync } from 'tmp';
import { promisify } from 'util'; import { promisify } from 'util';
@ -44,6 +44,12 @@ export interface PackageManagerCommands {
run: (script: string, args?: string) => string; run: (script: string, args?: string) => string;
// Make this required once bun adds programatically support for reading config https://github.com/oven-sh/bun/issues/7140 // Make this required once bun adds programatically support for reading config https://github.com/oven-sh/bun/issues/7140
getRegistryUrl?: string; getRegistryUrl?: string;
publish: (
packageRoot: string,
registry: string,
registryConfigKey: string,
tag: string
) => string;
} }
/** /**
@ -130,17 +136,28 @@ export function getPackageManagerCommand(
getRegistryUrl: useBerry getRegistryUrl: useBerry
? 'yarn config get npmRegistryServer' ? 'yarn config get npmRegistryServer'
: 'yarn config get registry', : 'yarn config get registry',
publish: (packageRoot, registry, registryConfigKey, tag) =>
`npm publish "${packageRoot}" --json --"${registryConfigKey}=${registry}" --tag=${tag}`,
}; };
}, },
pnpm: () => { pnpm: () => {
let modernPnpm: boolean, includeDoubleDashBeforeArgs: boolean; let modernPnpm: boolean,
includeDoubleDashBeforeArgs: boolean,
allowRegistryConfigKey: boolean;
try { try {
const pnpmVersion = getPackageManagerVersion('pnpm', root); const pnpmVersion = getPackageManagerVersion('pnpm', root);
modernPnpm = gte(pnpmVersion, '6.13.0'); modernPnpm = gte(pnpmVersion, '6.13.0');
includeDoubleDashBeforeArgs = lt(pnpmVersion, '7.0.0'); includeDoubleDashBeforeArgs = lt(pnpmVersion, '7.0.0');
// Support for --@scope:registry was added in pnpm v10.5.0 and backported to v9.15.7.
// Versions >=10.0.0 and <10.5.0 do NOT support this CLI option.
allowRegistryConfigKey = satisfies(
pnpmVersion,
'>=9.15.7 <10.0.0 || >=10.5.0'
);
} catch { } catch {
modernPnpm = true; modernPnpm = true;
includeDoubleDashBeforeArgs = true; includeDoubleDashBeforeArgs = true;
allowRegistryConfigKey = false;
} }
const isPnpmWorkspace = existsSync(join(root, 'pnpm-workspace.yaml')); const isPnpmWorkspace = existsSync(join(root, 'pnpm-workspace.yaml'));
@ -163,6 +180,10 @@ export function getPackageManagerCommand(
}`, }`,
list: 'pnpm ls --depth 100', list: 'pnpm ls --depth 100',
getRegistryUrl: 'pnpm config get registry', getRegistryUrl: 'pnpm config get registry',
publish: (packageRoot, registry, registryConfigKey, tag) =>
`pnpm publish "${packageRoot}" --json --"${
allowRegistryConfigKey ? registryConfigKey : 'registry'
}=${registry}" --tag=${tag} --no-git-checks`,
}; };
}, },
npm: () => { npm: () => {
@ -182,6 +203,8 @@ export function getPackageManagerCommand(
`npm run ${script}${args ? ' -- ' + args : ''}`, `npm run ${script}${args ? ' -- ' + args : ''}`,
list: 'npm ls', list: 'npm ls',
getRegistryUrl: 'npm config get registry', getRegistryUrl: 'npm config get registry',
publish: (packageRoot, registry, registryConfigKey, tag) =>
`npm publish "${packageRoot}" --json --"${registryConfigKey}=${registry}" --tag=${tag}`,
}; };
}, },
bun: () => { bun: () => {
@ -197,6 +220,9 @@ export function getPackageManagerCommand(
dlx: 'bunx', dlx: 'bunx',
run: (script: string, args: string) => `bun run ${script} -- ${args}`, run: (script: string, args: string) => `bun run ${script} -- ${args}`,
list: 'bun pm ls', list: 'bun pm ls',
// Unlike npm, bun publish does not support a custom registryConfigKey option
publish: (packageRoot, registry, registryConfigKey, tag) =>
`bun publish --cwd="${packageRoot}" --json --registry="${registry}" --tag=${tag}`,
}; };
}, },
}; };