fix(update): migrate config before plugin convergence (#113280)

This commit is contained in:
Vincent Koc
2026-07-24 16:55:38 +08:00
committed by GitHub
parent 7584d9585b
commit 741ed2d6a8
3 changed files with 60 additions and 1 deletions
+31
View File
@@ -21,6 +21,37 @@ function getDiscordCompatibilityNormalizer(): NonNullable<
}
describe("discord doctor", () => {
it("promotes shipped nested DM access at root and account scope", () => {
const normalize = getDiscordCompatibilityNormalizer();
const result = normalize({
cfg: {
channels: {
discord: {
dm: { enabled: false, policy: "allowlist", allowFrom: ["123"] },
accounts: {
work: {
dm: { groupEnabled: true, policy: "open", allowFrom: ["*"] },
},
},
},
},
} as never,
});
expect(result.config.channels?.discord).toEqual({
dm: { enabled: false },
dmPolicy: "allowlist",
allowFrom: ["123"],
accounts: {
work: {
dm: { groupEnabled: true },
dmPolicy: "open",
allowFrom: ["*"],
},
},
});
});
it("strips retired gateway, queue, and retry tuning at root and account scope", () => {
const normalize = getDiscordCompatibilityNormalizer();
const result = normalize({
+8
View File
@@ -1984,6 +1984,14 @@ describe("update-cli", () => {
),
).toBe(true);
expect(defaultRuntime.exit).toHaveBeenCalledWith(0);
expect(doctorCommand).toHaveBeenCalledWith(defaultRuntime, {
nonInteractive: true,
repair: true,
yes: false,
});
expect(vi.mocked(doctorCommand).mock.invocationCallOrder[0] ?? 0).toBeLessThan(
syncPluginsForUpdateChannel.mock.invocationCallOrder[0] ?? 0,
);
expect(syncPluginsForUpdateChannel).toHaveBeenCalledTimes(1);
expect(updateNpmInstalledPlugins).toHaveBeenCalledTimes(1);
expect(spawn).not.toHaveBeenCalled();
+21 -1
View File
@@ -1,3 +1,4 @@
import { doctorCommand } from "../../commands/doctor.js";
import { readConfigFileSnapshot } from "../../config/config.js";
import { normalizeUpdateChannel } from "../../infra/update-channels.js";
import { POST_CORE_UPDATE_SOURCE_CONFIG_PATH_ENV } from "../../infra/update-post-core-context.js";
@@ -9,11 +10,15 @@ import { defaultRuntime } from "../../runtime.js";
import { VERSION } from "../../version.js";
import { readPackageVersion, type UpdateCommandOptions } from "./shared.js";
import {
createUpdateConfigSnapshot,
persistRequestedUpdateChannel,
readPostCorePreUpdateSourceConfig,
restoreDroppedPreUpdateChannels,
} from "./update-command-config.js";
import { completePostCorePluginUpdate } from "./update-command-fresh-doctor.js";
import {
completePostCorePluginUpdate,
withUpdateFinalizationEnv,
} from "./update-command-fresh-doctor.js";
import { updatePluginsAfterCoreUpdate } from "./update-command-plugins.js";
import {
POST_CORE_UPDATE_INSTALL_RECORDS_PATH_ENV,
@@ -71,6 +76,21 @@ async function resumePostCoreUpdateUnlocked(params: ResumePostCoreUpdateParams):
currentSnapshot: configSnapshot,
updateStartedAtMs,
});
await withUpdateFinalizationEnv(async () => {
await createUpdateConfigSnapshot();
await doctorCommand(defaultRuntime, {
nonInteractive: true,
repair: true,
yes: params.opts.yes === true,
});
});
// The fresh process owns the updated migration contracts. Repair before
// plugin convergence writes config, or newly retired plugin keys can block
// the update before doctor gets a chance to migrate them.
configSnapshot = await readConfigFileSnapshot({
skipPluginValidation: true,
suppressFutureVersionWarning: true,
});
configSnapshot = await persistRequestedUpdateChannel({
configSnapshot,
requestedChannel,