diff --git a/.changeset/honest-walls-search.md b/.changeset/honest-walls-search.md new file mode 100644 index 0000000000..96b8b25618 --- /dev/null +++ b/.changeset/honest-walls-search.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Preserve existing provider profiles when importing diff --git a/src/core/config/__tests__/importExport.test.ts b/src/core/config/__tests__/importExport.test.ts index 8df619f3bf..d472856975 100644 --- a/src/core/config/__tests__/importExport.test.ts +++ b/src/core/config/__tests__/importExport.test.ts @@ -2,7 +2,6 @@ import fs from "fs/promises" import * as path from "path" -import os from "os" import * as vscode from "vscode" @@ -37,6 +36,7 @@ jest.mock("os", () => ({ describe("importExport", () => { let mockProviderSettingsManager: jest.Mocked let mockContextProxy: jest.Mocked + let mockExtensionContext: jest.Mocked beforeEach(() => { // Reset all mocks @@ -55,6 +55,15 @@ describe("importExport", () => { setValue: jest.fn(), export: jest.fn().mockImplementation(() => Promise.resolve({})), } as unknown as jest.Mocked + + const map = new Map() + + mockExtensionContext = { + secrets: { + get: jest.fn().mockImplementation((key: string) => map.get(key)), + store: jest.fn().mockImplementation((key: string, value: string) => map.set(key, value)), + }, + } as unknown as jest.Mocked }) describe("importSettings", () => { @@ -161,9 +170,7 @@ describe("importExport", () => { // Invalid content (missing required fields) const mockInvalidContent = JSON.stringify({ - providerProfiles: { - apiConfigs: {}, - }, + providerProfiles: { apiConfigs: {} }, globalSettings: {}, }) @@ -219,6 +226,38 @@ describe("importExport", () => { expect(mockProviderSettingsManager.import).not.toHaveBeenCalled() expect(mockContextProxy.setValues).not.toHaveBeenCalled() }) + + it("should not clobber existing api configs", async () => { + const providerSettingsManager = new ProviderSettingsManager(mockExtensionContext) + await providerSettingsManager.saveConfig("openai", { apiProvider: "openai", id: "openai" }) + + const configs = await providerSettingsManager.listConfig() + expect(configs[0].name).toBe("default") + expect(configs[1].name).toBe("openai") + ;(vscode.window.showOpenDialog as jest.Mock).mockResolvedValue([{ fsPath: "/mock/path/settings.json" }]) + + const mockFileContent = JSON.stringify({ + globalSettings: { mode: "code" }, + providerProfiles: { + currentApiConfigName: "anthropic", + apiConfigs: { default: { apiProvider: "anthropic" as const, id: "anthropic" } }, + }, + }) + + ;(fs.readFile as jest.Mock).mockResolvedValue(mockFileContent) + + mockContextProxy.export.mockResolvedValue({ mode: "code" }) + + const result = await importSettings({ + providerSettingsManager, + contextProxy: mockContextProxy, + }) + + expect(result.success).toBe(true) + expect(result.providerProfiles?.apiConfigs["openai"]).toBeDefined() + expect(result.providerProfiles?.apiConfigs["default"]).toBeDefined() + expect(result.providerProfiles?.apiConfigs["default"].apiProvider).toBe("anthropic") + }) }) describe("exportSettings", () => { diff --git a/src/core/config/importExport.ts b/src/core/config/importExport.ts index 3bd2c2ede8..f8059160a2 100644 --- a/src/core/config/importExport.ts +++ b/src/core/config/importExport.ts @@ -30,15 +30,27 @@ export const importSettings = async ({ providerSettingsManager, contextProxy }: }) try { - const { providerProfiles, globalSettings } = schema.parse( + const previousProviderProfiles = await providerSettingsManager.export() + + const { providerProfiles: newProviderProfiles, globalSettings } = schema.parse( JSON.parse(await fs.readFile(uris[0].fsPath, "utf-8")), ) - const previousProviderProfiles = await providerSettingsManager.export() + const providerProfiles = { + currentApiConfigName: newProviderProfiles.currentApiConfigName, + apiConfigs: { + ...previousProviderProfiles.apiConfigs, + ...newProviderProfiles.apiConfigs, + }, + modeApiConfigs: { + ...previousProviderProfiles.modeApiConfigs, + ...newProviderProfiles.modeApiConfigs, + }, + } + + await providerSettingsManager.import(newProviderProfiles) await contextProxy.setValues(globalSettings) - await providerSettingsManager.import({ ...previousProviderProfiles, ...providerProfiles }) - contextProxy.setValue("currentApiConfigName", providerProfiles.currentApiConfigName) contextProxy.setValue("listApiConfigMeta", await providerSettingsManager.listConfig())