Skip to content

Commit 62fad3d

Browse files
authored
fix(update): use configured npm registry for update metadata (#93879)
Merged via squash. Prepared head SHA: ae8bbb0 Co-authored-by: vincentkoc <[email protected]> Co-authored-by: vincentkoc <[email protected]> Reviewed-by: @vincentkoc
1 parent f33cf5c commit 62fad3d

5 files changed

Lines changed: 452 additions & 66 deletions

File tree

src/cli/update-cli.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2215,6 +2215,15 @@ describe("update-cli", () => {
22152215
await updateCommand({ yes: true });
22162216

22172217
expectPackageInstallSpec("openclaw@latest");
2218+
const preflightParams = vi.mocked(fetchNpmPackageTargetStatus).mock.calls[0]?.[0];
2219+
expect(preflightParams).toEqual(
2220+
expect.objectContaining({
2221+
target: "latest",
2222+
spec: "openclaw@latest",
2223+
cwd: process.cwd(),
2224+
}),
2225+
);
2226+
expect(packageInstallCommandCall()?.[1].env).toBe(preflightParams?.env);
22182227
expect(defaultRuntime.exit).not.toHaveBeenCalledWith(1);
22192228
expect(
22202229
vi
@@ -3719,6 +3728,12 @@ describe("update-cli", () => {
37193728
"i",
37203729
),
37213730
);
3731+
expect(vi.mocked(resolveNpmChannelTag)).toHaveBeenCalledWith(
3732+
expect.objectContaining({ command: installCommand }),
3733+
);
3734+
expect(vi.mocked(fetchNpmPackageTargetStatus)).toHaveBeenCalledWith(
3735+
expect.objectContaining({ command: installCommand }),
3736+
);
37223737
const installOptions = requiredInstallCall[1] as { timeoutMs?: number };
37233738
expect(typeof installOptions.timeoutMs).toBe("number");
37243739
});
@@ -6388,7 +6403,9 @@ describe("update-cli", () => {
63886403
expect(
63896404
vi
63906405
.mocked(runCommandWithTimeout)
6391-
.mock.calls.some((call) => Array.isArray(call[0]) && call[0][0] === "npm"),
6406+
.mock.calls.some(
6407+
(call) => Array.isArray(call[0]) && call[0][0] === "npm" && call[0][1] === "i",
6408+
),
63926409
).toBe(shouldRunPackageUpdate);
63936410
});
63946411

src/cli/update-cli/shared.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export { readPackageName, readPackageVersion };
9898
export async function resolveTargetVersion(
9999
tag: string,
100100
timeoutMs?: number,
101+
options: { spec?: string; command?: string; cwd?: string; env?: NodeJS.ProcessEnv } = {},
101102
): Promise<string | null> {
102103
if (!canResolveRegistryVersionForPackageTarget(tag)) {
103104
return null;
@@ -106,7 +107,14 @@ export async function resolveTargetVersion(
106107
if (direct) {
107108
return direct;
108109
}
109-
const res = await fetchNpmTagVersion({ tag, timeoutMs });
110+
const res = await fetchNpmTagVersion({
111+
tag,
112+
timeoutMs,
113+
spec: options.spec,
114+
command: options.command,
115+
cwd: options.cwd,
116+
env: options.env,
117+
});
110118
return res.version ?? null;
111119
}
112120

src/cli/update-cli/update-command.ts

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import {
9191
resolveGlobalInstallTarget,
9292
resolveGlobalInstallSpec,
9393
resolvePnpmGlobalDirFromGlobalRoot,
94+
type ResolvedGlobalInstallTarget,
9495
} from "../../infra/update-global.js";
9596
import { cleanupStaleManagedServiceUpdateHandoffs } from "../../infra/update-managed-service-handoff-cleanup.js";
9697
import { runGatewayUpdate, type UpdateRunResult } from "../../infra/update-runner.js";
@@ -1045,17 +1046,28 @@ async function resolvePackageRuntimePreflightError(params: {
10451046
tag: string;
10461047
timeoutMs?: number;
10471048
nodeRunner?: string;
1049+
spec?: string;
1050+
command?: string;
1051+
cwd?: string;
1052+
env?: NodeJS.ProcessEnv;
10481053
}): Promise<string | null> {
10491054
if (!canResolveRegistryVersionForPackageTarget(params.tag)) {
10501055
return null;
10511056
}
1057+
if (params.spec && !canResolveRegistryVersionForPackageTarget(params.spec)) {
1058+
return null;
1059+
}
10521060
const target = params.tag.trim();
10531061
if (!target) {
10541062
return null;
10551063
}
10561064
const status = await fetchNpmPackageTargetStatus({
10571065
target,
1066+
spec: params.spec,
10581067
timeoutMs: params.timeoutMs,
1068+
command: params.command,
1069+
cwd: params.cwd,
1070+
env: params.env,
10591071
});
10601072
if (status.error) {
10611073
return null;
@@ -1503,21 +1515,26 @@ async function runPackageInstallUpdate(params: {
15031515
invocationCwd?: string;
15041516
honorPackageRoot?: boolean;
15051517
nodeRunner?: string;
1518+
installEnv?: NodeJS.ProcessEnv;
1519+
installTarget?: ResolvedGlobalInstallTarget;
15061520
}): Promise<UpdateRunResult> {
1507-
const manager = await resolveGlobalManager({
1508-
root: params.root,
1509-
installKind: params.installKind,
1510-
timeoutMs: params.timeoutMs,
1511-
});
1512-
const installEnv = await createGlobalInstallEnv();
1521+
const installEnv = params.installEnv ?? (await createGlobalInstallEnv());
15131522
const runCommand = createGlobalCommandRunner();
1514-
const installTarget = await resolveGlobalInstallTarget({
1515-
manager,
1516-
runCommand,
1517-
timeoutMs: params.timeoutMs,
1518-
pkgRoot: params.root,
1519-
honorPackageRoot: params.honorPackageRoot === true,
1520-
});
1523+
let installTarget = params.installTarget;
1524+
if (!installTarget) {
1525+
const manager = await resolveGlobalManager({
1526+
root: params.root,
1527+
installKind: params.installKind,
1528+
timeoutMs: params.timeoutMs,
1529+
});
1530+
installTarget = await resolveGlobalInstallTarget({
1531+
manager,
1532+
runCommand,
1533+
timeoutMs: params.timeoutMs,
1534+
pkgRoot: params.root,
1535+
honorPackageRoot: params.honorPackageRoot === true,
1536+
});
1537+
}
15211538
const pkgRoot = installTarget.packageRoot;
15221539
const packageName =
15231540
(pkgRoot ? await readPackageName(pkgRoot) : await readPackageName(params.root)) ??
@@ -1620,7 +1637,7 @@ async function runPackageInstallUpdate(params: {
16201637

16211638
return {
16221639
status: packageUpdate.failedStep ? "error" : "ok",
1623-
mode: manager,
1640+
mode: installTarget.manager,
16241641
root: packageUpdate.verifiedPackageRoot ?? params.root,
16251642
reason: packageUpdate.failedStep ? packageUpdate.failedStep.name : undefined,
16261643
before: { version: beforeVersion },
@@ -3286,6 +3303,9 @@ async function updateCommandInternal(opts: UpdateCommandOptions): Promise<void>
32863303
let downgradeRisk = false;
32873304
let fallbackToLatest = false;
32883305
let packageInstallSpec: string | null = null;
3306+
let packageInstallEnv: NodeJS.ProcessEnv | undefined;
3307+
let packageInstallCwd: string | undefined;
3308+
let packageInstallTarget: ResolvedGlobalInstallTarget | undefined;
32893309
let packageAlreadyCurrent = false;
32903310
let managedServiceRootRedirect: ManagedServiceRootRedirect | null = null;
32913311
// Resolved independently of the root redirect so it covers the common case
@@ -3340,11 +3360,46 @@ async function updateCommandInternal(opts: UpdateCommandOptions): Promise<void>
33403360
}
33413361

33423362
if (updateInstallKind !== "git") {
3363+
packageInstallEnv = await createGlobalInstallEnv();
3364+
packageInstallCwd = tryResolveInvocationCwd();
3365+
if (updateInstallKind === "package") {
3366+
const manager = await resolveGlobalManager({
3367+
root,
3368+
installKind,
3369+
timeoutMs: updateStepTimeoutMs,
3370+
});
3371+
packageInstallTarget = await resolveGlobalInstallTarget({
3372+
manager,
3373+
runCommand: createGlobalCommandRunner(),
3374+
timeoutMs: updateStepTimeoutMs,
3375+
pkgRoot: root,
3376+
honorPackageRoot:
3377+
managedServiceRootRedirect !== null || managedServiceNodeRunner !== undefined,
3378+
});
3379+
}
3380+
const npmMetadataCommand =
3381+
packageInstallTarget?.manager === "npm" ? packageInstallTarget.command : undefined;
33433382
currentVersion = switchToPackage ? null : await readPackageVersion(root);
33443383
if (explicitTag) {
3345-
targetVersion = await resolveTargetVersion(tag, timeoutMs);
3384+
const explicitSpec = resolveGlobalInstallSpec({
3385+
packageName: DEFAULT_PACKAGE_NAME,
3386+
tag,
3387+
env: packageInstallEnv,
3388+
});
3389+
targetVersion = await resolveTargetVersion(tag, timeoutMs, {
3390+
spec: explicitSpec,
3391+
command: npmMetadataCommand,
3392+
cwd: packageInstallCwd,
3393+
env: packageInstallEnv,
3394+
});
33463395
} else {
3347-
targetVersion = await resolveNpmChannelTag({ channel, timeoutMs }).then((resolved) => {
3396+
targetVersion = await resolveNpmChannelTag({
3397+
channel,
3398+
timeoutMs,
3399+
command: npmMetadataCommand,
3400+
cwd: packageInstallCwd,
3401+
env: packageInstallEnv,
3402+
}).then((resolved) => {
33483403
tag = resolved.tag;
33493404
fallbackToLatest = channel === "beta" && resolved.tag === "latest";
33503405
return resolved.version;
@@ -3367,7 +3422,7 @@ async function updateCommandInternal(opts: UpdateCommandOptions): Promise<void>
33673422
packageInstallSpec = resolveGlobalInstallSpec({
33683423
packageName: DEFAULT_PACKAGE_NAME,
33693424
tag,
3370-
env: process.env,
3425+
env: packageInstallEnv,
33713426
});
33723427
}
33733428

@@ -3485,8 +3540,12 @@ async function updateCommandInternal(opts: UpdateCommandOptions): Promise<void>
34853540
if (updateInstallKind === "package") {
34863541
const runtimePreflightError = await resolvePackageRuntimePreflightError({
34873542
tag,
3543+
spec: packageInstallSpec ?? undefined,
34883544
timeoutMs,
34893545
nodeRunner: managedServiceNodeRunner,
3546+
command: packageInstallTarget?.manager === "npm" ? packageInstallTarget.command : undefined,
3547+
cwd: packageInstallCwd,
3548+
env: packageInstallEnv,
34903549
});
34913550
if (runtimePreflightError) {
34923551
defaultRuntime.error(runtimePreflightError);
@@ -3591,6 +3650,8 @@ async function updateCommandInternal(opts: UpdateCommandOptions): Promise<void>
35913650
honorPackageRoot:
35923651
managedServiceRootRedirect !== null || managedServiceNodeRunner !== undefined,
35933652
nodeRunner: managedServiceNodeRunner,
3653+
installEnv: packageInstallEnv,
3654+
installTarget: packageInstallTarget,
35943655
})
35953656
: await runGitUpdate({
35963657
root,

0 commit comments

Comments
 (0)