Fix setting migration nosiness and merging (#7571)

This commit is contained in:
Gal Zahavi
2025-09-01 18:23:35 -07:00
committed by GitHub
parent 0c0309abdc
commit 52cc0f6feb
2 changed files with 85 additions and 17 deletions

View File

@@ -142,6 +142,11 @@ describe('Settings Loading and Merging', () => {
workspacesWithMigrationNudge: [], workspacesWithMigrationNudge: [],
}, },
security: {}, security: {},
general: {},
privacy: {},
telemetry: {},
tools: {},
ide: {},
}); });
expect(settings.errors.length).toBe(0); expect(settings.errors.length).toBe(0);
}); });
@@ -197,6 +202,13 @@ describe('Settings Loading and Merging', () => {
workspacesWithMigrationNudge: [], workspacesWithMigrationNudge: [],
}, },
security: {}, security: {},
general: {},
privacy: {},
telemetry: {},
tools: {
sandbox: false,
},
ide: {},
}); });
}); });
@@ -253,6 +265,11 @@ describe('Settings Loading and Merging', () => {
workspacesWithMigrationNudge: [], workspacesWithMigrationNudge: [],
}, },
security: {}, security: {},
general: {},
privacy: {},
telemetry: {},
tools: {},
ide: {},
}); });
}); });
@@ -308,6 +325,10 @@ describe('Settings Loading and Merging', () => {
workspacesWithMigrationNudge: [], workspacesWithMigrationNudge: [],
}, },
security: {}, security: {},
general: {},
privacy: {},
telemetry: {},
ide: {},
}); });
}); });
@@ -374,6 +395,10 @@ describe('Settings Loading and Merging', () => {
chatCompression: {}, chatCompression: {},
}, },
security: {}, security: {},
general: {},
privacy: {},
telemetry: {},
ide: {},
}); });
}); });
@@ -439,6 +464,7 @@ describe('Settings Loading and Merging', () => {
}, },
tools: { tools: {
sandbox: false, sandbox: false,
core: ['tool1'],
}, },
telemetry: { enabled: false }, telemetry: { enabled: false },
context: { context: {
@@ -460,6 +486,9 @@ describe('Settings Loading and Merging', () => {
chatCompression: {}, chatCompression: {},
}, },
security: {}, security: {},
general: {},
privacy: {},
ide: {},
}); });
}); });
@@ -538,6 +567,10 @@ describe('Settings Loading and Merging', () => {
workspacesWithMigrationNudge: [], workspacesWithMigrationNudge: [],
}, },
security: {}, security: {},
privacy: {},
telemetry: {},
tools: {},
ide: {},
}); });
}); });
@@ -668,7 +701,7 @@ describe('Settings Loading and Merging', () => {
chatCompression: {}, chatCompression: {},
}, },
security: {}, security: {},
telemetry: false, telemetry: {},
tools: { tools: {
sandbox: false, sandbox: false,
}, },
@@ -676,6 +709,9 @@ describe('Settings Loading and Merging', () => {
customThemes: {}, customThemes: {},
theme: 'system-theme', theme: 'system-theme',
}, },
general: {},
privacy: {},
ide: {},
}); });
}); });
@@ -901,7 +937,7 @@ describe('Settings Loading and Merging', () => {
(mockFsExistsSync as Mock).mockImplementation( (mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH, (p: fs.PathLike) => p === USER_SETTINGS_PATH,
); );
const userSettingsContent = { telemetry: true }; const userSettingsContent = { telemetry: { enabled: true } };
(fs.readFileSync as Mock).mockImplementation( (fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => { (p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH) if (p === USER_SETTINGS_PATH)
@@ -910,14 +946,14 @@ describe('Settings Loading and Merging', () => {
}, },
); );
const settings = loadSettings(MOCK_WORKSPACE_DIR); const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBe(true); expect(settings.merged.telemetry?.enabled).toBe(true);
}); });
it('should load telemetry setting from workspace settings', () => { it('should load telemetry setting from workspace settings', () => {
(mockFsExistsSync as Mock).mockImplementation( (mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH, (p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH,
); );
const workspaceSettingsContent = { telemetry: false }; const workspaceSettingsContent = { telemetry: { enabled: false } };
(fs.readFileSync as Mock).mockImplementation( (fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => { (p: fs.PathOrFileDescriptor) => {
if (p === MOCK_WORKSPACE_SETTINGS_PATH) if (p === MOCK_WORKSPACE_SETTINGS_PATH)
@@ -926,13 +962,13 @@ describe('Settings Loading and Merging', () => {
}, },
); );
const settings = loadSettings(MOCK_WORKSPACE_DIR); const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBe(false); expect(settings.merged.telemetry?.enabled).toBe(false);
}); });
it('should prioritize workspace telemetry setting over user setting', () => { it('should prioritize workspace telemetry setting over user setting', () => {
(mockFsExistsSync as Mock).mockReturnValue(true); (mockFsExistsSync as Mock).mockReturnValue(true);
const userSettingsContent = { telemetry: true }; const userSettingsContent = { telemetry: { enabled: true } };
const workspaceSettingsContent = { telemetry: false }; const workspaceSettingsContent = { telemetry: { enabled: false } };
(fs.readFileSync as Mock).mockImplementation( (fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => { (p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH) if (p === USER_SETTINGS_PATH)
@@ -943,14 +979,14 @@ describe('Settings Loading and Merging', () => {
}, },
); );
const settings = loadSettings(MOCK_WORKSPACE_DIR); const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBe(false); expect(settings.merged.telemetry?.enabled).toBe(false);
}); });
it('should have telemetry as undefined if not in any settings file', () => { it('should have telemetry as undefined if not in any settings file', () => {
(mockFsExistsSync as Mock).mockReturnValue(false); // No settings files exist (mockFsExistsSync as Mock).mockReturnValue(false); // No settings files exist
(fs.readFileSync as Mock).mockReturnValue('{}'); (fs.readFileSync as Mock).mockReturnValue('{}');
const settings = loadSettings(MOCK_WORKSPACE_DIR); const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBeUndefined(); expect(settings.merged.telemetry).toEqual({});
expect(settings.merged.ui?.customThemes).toEqual({}); expect(settings.merged.ui?.customThemes).toEqual({});
expect(settings.merged.mcpServers).toEqual({}); expect(settings.merged.mcpServers).toEqual({});
}); });
@@ -1400,6 +1436,11 @@ describe('Settings Loading and Merging', () => {
workspacesWithMigrationNudge: [], workspacesWithMigrationNudge: [],
}, },
security: {}, security: {},
general: {},
privacy: {},
tools: {},
telemetry: {},
ide: {},
}); });
// Check that error objects are populated in settings.errors // Check that error objects are populated in settings.errors
@@ -1828,6 +1869,10 @@ describe('Settings Loading and Merging', () => {
workspacesWithMigrationNudge: [], workspacesWithMigrationNudge: [],
}, },
security: {}, security: {},
general: {},
privacy: {},
telemetry: {},
ide: {},
}); });
}); });
}); });

View File

@@ -30,7 +30,6 @@ export const DEFAULT_EXCLUDED_ENV_VARS = ['DEBUG', 'DEBUG_MODE'];
const MIGRATE_V2_OVERWRITE = false; const MIGRATE_V2_OVERWRITE = false;
// As defined in spec.md
const MIGRATION_MAP: Record<string, string> = { const MIGRATION_MAP: Record<string, string> = {
preferredEditor: 'general.preferredEditor', preferredEditor: 'general.preferredEditor',
vimMode: 'general.vimMode', vimMode: 'general.vimMode',
@@ -63,6 +62,7 @@ const MIGRATION_MAP: Record<string, string> = {
fileFiltering: 'context.fileFiltering', fileFiltering: 'context.fileFiltering',
sandbox: 'tools.sandbox', sandbox: 'tools.sandbox',
shouldUseNodePtyShell: 'tools.usePty', shouldUseNodePtyShell: 'tools.usePty',
allowedTools: 'tools.allowed',
coreTools: 'tools.core', coreTools: 'tools.core',
excludeTools: 'tools.exclude', excludeTools: 'tools.exclude',
toolDiscoveryCommand: 'tools.discoveryCommand', toolDiscoveryCommand: 'tools.discoveryCommand',
@@ -299,6 +299,12 @@ function mergeSettings(
...user, ...user,
...safeWorkspaceWithoutFolderTrust, ...safeWorkspaceWithoutFolderTrust,
...system, ...system,
general: {
...(systemDefaults.general || {}),
...(user.general || {}),
...(safeWorkspaceWithoutFolderTrust.general || {}),
...(system.general || {}),
},
ui: { ui: {
...(systemDefaults.ui || {}), ...(systemDefaults.ui || {}),
...(user.ui || {}), ...(user.ui || {}),
@@ -311,6 +317,24 @@ function mergeSettings(
...(system.ui?.customThemes || {}), ...(system.ui?.customThemes || {}),
}, },
}, },
ide: {
...(systemDefaults.ide || {}),
...(user.ide || {}),
...(safeWorkspaceWithoutFolderTrust.ide || {}),
...(system.ide || {}),
},
privacy: {
...(systemDefaults.privacy || {}),
...(user.privacy || {}),
...(safeWorkspaceWithoutFolderTrust.privacy || {}),
...(system.privacy || {}),
},
telemetry: {
...(systemDefaults.telemetry || {}),
...(user.telemetry || {}),
...(safeWorkspaceWithoutFolderTrust.telemetry || {}),
...(system.telemetry || {}),
},
security: { security: {
...(systemDefaults.security || {}), ...(systemDefaults.security || {}),
...(user.security || {}), ...(user.security || {}),
@@ -329,6 +353,12 @@ function mergeSettings(
...(safeWorkspaceWithoutFolderTrust.mcpServers || {}), ...(safeWorkspaceWithoutFolderTrust.mcpServers || {}),
...(system.mcpServers || {}), ...(system.mcpServers || {}),
}, },
tools: {
...(systemDefaults.tools || {}),
...(user.tools || {}),
...(safeWorkspaceWithoutFolderTrust.tools || {}),
...(system.tools || {}),
},
context: { context: {
...(systemDefaults.context || {}), ...(systemDefaults.context || {}),
...(user.context || {}), ...(user.context || {}),
@@ -667,7 +697,6 @@ export function loadSettings(workspaceDir: string): LoadedSettings {
let settingsObject = rawSettings as Record<string, unknown>; let settingsObject = rawSettings as Record<string, unknown>;
if (needsMigration(settingsObject)) { if (needsMigration(settingsObject)) {
console.error(`Legacy settings file detected at: ${filePath}`);
const migratedSettings = migrateSettingsToV2(settingsObject); const migratedSettings = migrateSettingsToV2(settingsObject);
if (migratedSettings) { if (migratedSettings) {
if (MIGRATE_V2_OVERWRITE) { if (MIGRATE_V2_OVERWRITE) {
@@ -678,9 +707,6 @@ export function loadSettings(workspaceDir: string): LoadedSettings {
JSON.stringify(migratedSettings, null, 2), JSON.stringify(migratedSettings, null, 2),
'utf-8', 'utf-8',
); );
console.log(
`Successfully migrated and saved settings file: ${filePath}`,
);
} catch (e) { } catch (e) {
console.error( console.error(
`Error migrating settings file on disk: ${getErrorMessage( `Error migrating settings file on disk: ${getErrorMessage(
@@ -689,9 +715,6 @@ export function loadSettings(workspaceDir: string): LoadedSettings {
); );
} }
} else { } else {
console.log(
`Successfully migrated settings for ${filePath} in-memory for the current session.`,
);
migratedInMemorScopes.add(scope); migratedInMemorScopes.add(scope);
} }
settingsObject = migratedSettings; settingsObject = migratedSettings;