diff --git a/.changeset/publish-respect-publishconfig-registry.md b/.changeset/publish-respect-publishconfig-registry.md new file mode 100644 index 0000000000..591fbf06cc --- /dev/null +++ b/.changeset/publish-respect-publishconfig-registry.md @@ -0,0 +1,6 @@ +--- +"@pnpm/releasing.commands": patch +"pnpm": patch +--- + +Fixed `pnpm publish` to honor `publishConfig.registry` from `package.json` when publishing a single package. The native publish flow introduced in v11 was reading the registry from `.npmrc` only, ignoring the per-package override [#11419](https://github.com/pnpm/pnpm/issues/11419). diff --git a/releasing/commands/src/publish/publishPackedPkg.ts b/releasing/commands/src/publish/publishPackedPkg.ts index 5b4083a1eb..f3087f49fa 100644 --- a/releasing/commands/src/publish/publishPackedPkg.ts +++ b/releasing/commands/src/publish/publishPackedPkg.ts @@ -59,7 +59,10 @@ export async function publishPackedPkg ( } async function createPublishOptions (manifest: ExportedManifest, options: PublishPackedPkgOptions): Promise { - const { registry, config } = findRegistryInfo(manifest, options) + const publishConfigRegistry = typeof manifest.publishConfig?.registry === 'string' + ? manifest.publishConfig.registry + : undefined + const { registry, config } = findRegistryInfo(manifest, options, publishConfigRegistry) const { creds, tls } = config ?? {} const { @@ -130,16 +133,19 @@ interface RegistryInfo { /** * Find credentials and SSL info for a package's registry. * Follows {@link https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#auth-related-configuration}. + * + * The manifest's `publishConfig.registry`, when set, takes precedence over `registries`. */ function findRegistryInfo ( { name }: ExportedManifest, - { configByUri, registries }: Pick + { configByUri, registries }: Pick, + publishConfigRegistry?: string ): Partial { // eslint-disable-next-line regexp/no-unused-capturing-group const scopedMatches = /@(?[^/]+)\/(?[^/]+)/.exec(name) const registryName = scopedMatches?.groups ? `@${scopedMatches.groups.scope}` : 'default' - const nonNormalizedRegistry = registries[registryName] ?? registries.default + const nonNormalizedRegistry = publishConfigRegistry ?? registries[registryName] ?? registries.default const supportedRegistryInfo = parseSupportedRegistryUrl(nonNormalizedRegistry) if (!supportedRegistryInfo) { diff --git a/releasing/commands/test/publish/publish.ts b/releasing/commands/test/publish/publish.ts index c90506c71f..c8fadd4a82 100644 --- a/releasing/commands/test/publish/publish.ts +++ b/releasing/commands/test/publish/publish.ts @@ -304,6 +304,28 @@ test('publish: package with all possible fields in publishConfig', async () => { }) }) +test('publish: package with publishConfig.registry overrides the default registry', async () => { + const pkgName = `test-publish-config-registry-${Date.now()}` + prepare({ + name: pkgName, + version: '1.0.0', + + publishConfig: { + registry: `http://localhost:${REGISTRY_MOCK_PORT}`, + }, + }) + + await publish.handler({ + ...DEFAULT_OPTS, + argv: { original: ['publish'] }, + configByUri: CONFIG_BY_URI, + dir: process.cwd(), + registries: { default: 'https://__fake_npm_registry__.com' }, + }, []) + + await checkPkgExists(pkgName, '1.0.0') +}) + test('publish: package with publishConfig.directory', async () => { const packages = preparePackages([ {