Skip to content

Commit 29f34a3

Browse files
JounQinAndarist
andauthoredApr 12, 2025··
Support scoped registries configured using package.json#publishConfig (#1470)
* feat: support read scoped registry from package json close #1469 * refactor: use computed property instead * chore: add `isCustomRegistry(process.env.npm_config_registry)` back * Create eleven-panthers-talk.md * tweak getCorrectRegistry implementation * chore: `tsc` complains possible optional False positive, so make it happy * Update .changeset/eleven-panthers-talk.md --------- Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

File tree

4 files changed

+51
-16
lines changed

4 files changed

+51
-16
lines changed
 

‎.changeset/eleven-panthers-talk.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@changesets/cli": minor
3+
---
4+
5+
Support scoped registries configured using `package.json#publishConfig`

‎packages/cli/src/commands/publish/npm-utils.ts

+43-14
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,37 @@ function jsonParse(input: string) {
3232
}
3333
}
3434

35-
function getCorrectRegistry(packageJson?: PackageJSON): string {
35+
interface RegistryInfo {
36+
scope?: string;
37+
registry: string;
38+
}
39+
40+
export function getCorrectRegistry(packageJson?: PackageJSON): RegistryInfo {
41+
const packageName = packageJson?.name;
42+
43+
if (packageName?.startsWith("@")) {
44+
const scope = packageName.split("/")[0];
45+
const scopedRegistry =
46+
packageJson!.publishConfig?.[`${scope}:registry`] ||
47+
process.env[`npm_config_${scope}:registry`];
48+
if (scopedRegistry) {
49+
return {
50+
scope,
51+
registry: scopedRegistry,
52+
};
53+
}
54+
}
55+
3656
const registry =
37-
packageJson?.publishConfig?.registry ?? process.env.npm_config_registry;
57+
packageJson?.publishConfig?.registry || process.env.npm_config_registry;
3858

39-
return !registry || registry === "https://registry.yarnpkg.com"
40-
? "https://registry.npmjs.org"
41-
: registry;
59+
return {
60+
scope: undefined,
61+
registry:
62+
!registry || registry === "https://registry.yarnpkg.com"
63+
? "https://registry.npmjs.org"
64+
: registry,
65+
};
4266
}
4367

4468
async function getPublishTool(
@@ -64,10 +88,11 @@ async function getPublishTool(
6488
}
6589

6690
export async function getTokenIsRequired() {
91+
const { scope, registry } = getCorrectRegistry();
6792
// Due to a super annoying issue in yarn, we have to manually override this env variable
6893
// See: https://github.com/yarnpkg/yarn/issues/2935#issuecomment-355292633
6994
const envOverride = {
70-
npm_config_registry: getCorrectRegistry(),
95+
[scope ? `npm_config_${scope}:registry` : "npm_config_registry"]: registry,
7196
};
7297
let result = await spawn("npm", ["profile", "get", "--json"], {
7398
env: Object.assign({}, process.env, envOverride),
@@ -90,6 +115,8 @@ export function getPackageInfo(packageJson: PackageJSON) {
90115
return npmRequestLimit(async () => {
91116
info(`npm info ${packageJson.name}`);
92117

118+
const { scope, registry } = getCorrectRegistry(packageJson);
119+
93120
// Due to a couple of issues with yarnpkg, we also want to override the npm registry when doing
94121
// npm info.
95122
// Issues: We sometimes get back cached responses, i.e old data about packages which causes
@@ -99,8 +126,7 @@ export function getPackageInfo(packageJson: PackageJSON) {
99126
let result = await spawn("npm", [
100127
"info",
101128
packageJson.name,
102-
"--registry",
103-
getCorrectRegistry(packageJson),
129+
`--${scope ? `${scope}:` : ""}registry=${registry}`,
104130
"--json",
105131
]);
106132

@@ -161,7 +187,7 @@ export let getOtpCode = async (twoFactorState: TwoFactorState) => {
161187
// we have this so that we can do try a publish again after a publish without
162188
// the call being wrapped in the npm request limit and causing the publishes to potentially never run
163189
async function internalPublish(
164-
pkgName: string,
190+
packageJson: PackageJSON,
165191
opts: PublishOptions,
166192
twoFactorState: TwoFactorState
167193
): Promise<{ published: boolean }> {
@@ -177,11 +203,14 @@ async function internalPublish(
177203
publishFlags.push("--no-git-checks");
178204
}
179205

206+
const { scope, registry } = getCorrectRegistry(packageJson);
207+
180208
// Due to a super annoying issue in yarn, we have to manually override this env variable
181209
// See: https://github.com/yarnpkg/yarn/issues/2935#issuecomment-355292633
182210
const envOverride = {
183-
npm_config_registry: getCorrectRegistry(),
211+
[scope ? `npm_config_${scope}:registry` : "npm_config_registry"]: registry,
184212
};
213+
185214
let { code, stdout, stderr } =
186215
publishTool.name === "pnpm"
187216
? await spawn("pnpm", ["publish", "--json", ...publishFlags], {
@@ -219,10 +248,10 @@ async function internalPublish(
219248
}
220249
// just in case this isn't already true
221250
twoFactorState.isRequired = Promise.resolve(true);
222-
return internalPublish(pkgName, opts, twoFactorState);
251+
return internalPublish(packageJson, opts, twoFactorState);
223252
}
224253
error(
225-
`an error occurred while publishing ${pkgName}: ${json.error.code}`,
254+
`an error occurred while publishing ${packageJson.name}: ${json.error.code}`,
226255
json.error.summary,
227256
json.error.detail ? "\n" + json.error.detail : ""
228257
);
@@ -235,13 +264,13 @@ async function internalPublish(
235264
}
236265

237266
export function publish(
238-
pkgName: string,
267+
packageJson: PackageJSON,
239268
opts: PublishOptions,
240269
twoFactorState: TwoFactorState
241270
): Promise<{ published: boolean }> {
242271
// If there are many packages to be published, it's better to limit the
243272
// concurrency to avoid unwanted errors, for example from npm.
244273
return npmRequestLimit(() =>
245-
npmPublishLimit(() => internalPublish(pkgName, opts, twoFactorState))
274+
npmPublishLimit(() => internalPublish(packageJson, opts, twoFactorState))
246275
);
247276
}

‎packages/cli/src/commands/publish/publishPackages.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const getTwoFactorState = ({
5656
if (
5757
isCI ||
5858
publicPackages.some((pkg) =>
59-
isCustomRegistry(pkg.packageJson.publishConfig?.registry)
59+
isCustomRegistry(npmUtils.getCorrectRegistry(pkg.packageJson).registry)
6060
) ||
6161
isCustomRegistry(process.env.npm_config_registry)
6262
) {
@@ -125,7 +125,7 @@ async function publishAPackage(
125125
info(`Publishing ${pc.cyan(`"${name}"`)} at ${pc.green(`"${version}"`)}`);
126126

127127
const publishConfirmation = await npmUtils.publish(
128-
name,
128+
pkg.packageJson,
129129
{
130130
cwd: pkg.dir,
131131
publishDir: publishConfig?.directory

‎packages/types/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export type PackageJSON = {
5353
access?: AccessType;
5454
directory?: string;
5555
registry?: string;
56+
[registry: `${string}:registry`]: string;
5657
};
5758
};
5859

0 commit comments

Comments
 (0)
Please sign in to comment.