Path: blob/main/extensions/copilot/src/extension/configuration/vscode-node/configurationMigration.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45/**6* Heavily lifted from https://github.com/microsoft/vscode/tree/main/src/vs/workbench/common/configuration.ts7* It is a little simplified and does not handle overrides, but currently we are only migrating experimental configurations8*/91011import { ConfigurationTarget, l10n, Uri, window, workspace, WorkspaceFolder } from 'vscode';12import { ConfigurationKeyValuePairs, ConfigurationMigration, ConfigurationMigrationRegistry, ConfigurationValue } from '../../../platform/configuration/common/configurationService';13import { NextCursorLinePrediction } from '../../../platform/inlineEdits/common/dataTypes/nextCursorLinePrediction';14import { DisposableStore, IDisposable } from '../../../util/vs/base/common/lifecycle';15import { IExtensionContribution } from '../../common/contributions';161718interface IConfigurationNode {19id: string;20title: string;21type: string;22order?: number;2324}2526export const applicationConfigurationNodeBase = Object.freeze<IConfigurationNode>({27'id': 'application',28'order': 100,29'title': l10n.t("Application"),30'type': 'object'31});3233export const Extensions = {34ConfigurationMigration: 'base.contributions.configuration.migration'35};3637export class ConfigurationMigrationContribution implements IExtensionContribution {38private readonly _disposables = new DisposableStore();3940constructor() {41this._register(workspace.onDidChangeWorkspaceFolders(async (e) => {42for (const folder of e.added) {43await this.migrateConfigurationForFolder(folder, ConfigurationMigrationRegistry.migrations);44}45}));46this.migrateConfigurations(ConfigurationMigrationRegistry.migrations);47this._register(ConfigurationMigrationRegistry.onDidRegisterConfigurationMigration(migration => this.migrateConfigurations(migration)));48}4950private async migrateConfigurations(migrations: ConfigurationMigration[]): Promise<void> {51if (window.state.focused) {52await this.migrateConfigurationForFolder(undefined, migrations);53for (const folder of workspace.workspaceFolders ?? []) {54await this.migrateConfigurationForFolder(folder, migrations);55}56}57}5859private async migrateConfigurationForFolder(folder: WorkspaceFolder | undefined, migrations: ConfigurationMigration[]): Promise<void> {60await Promise.all([migrations.map(migration => this.migrateConfigurationsForFolder(migration, folder?.uri))]);61}6263private async migrateConfigurationsForFolder(migration: ConfigurationMigration, resource?: Uri): Promise<void> {6465const configuration = workspace.getConfiguration(undefined, resource);66const inspectData = configuration.inspect(migration.key);6768if (!inspectData) {69return;70}7172const targetPairs: [unknown, ConfigurationTarget][] = [73[inspectData.globalValue, ConfigurationTarget.Global],74[inspectData.workspaceValue, ConfigurationTarget.Workspace],75];7677for (const [inspectValue, target] of targetPairs) {78if (!inspectValue) {79continue;80}8182const migrationValues: [string, ConfigurationValue][] = [];8384if (inspectValue !== undefined) {85const keyValuePairs = await this.runMigration(migration, inspectValue);86for (const keyValuePair of keyValuePairs ?? []) {87migrationValues.push(keyValuePair);88}89}9091if (migrationValues.length) {92// apply migrations93await Promise.allSettled(migrationValues.map(async ([key, value]) => {94configuration.update(key, value.value, target);95}));96}97}98}99100private async runMigration(migration: ConfigurationMigration, value: any): Promise<ConfigurationKeyValuePairs | undefined> {101const result = await migration.migrateFn(value);102return Array.isArray(result) ? result : [[migration.key, result]];103}104105private _register(disposable: IDisposable): void {106this._disposables.add(disposable);107}108109dispose(): void {110this._disposables.dispose();111}112}113114ConfigurationMigrationRegistry.registerConfigurationMigrations([{115key: 'github.copilot.chat.experimental.setupTests.enabled',116migrateFn: async (value: any) => {117return [118['github.copilot.chat.setupTests.enabled', { value }],119['github.copilot.chat.experimental.setupTests.enabled', { value: undefined }]120];121}122}]);123124ConfigurationMigrationRegistry.registerConfigurationMigrations([{125key: 'github.copilot.chat.experimental.codeGeneration.instructions',126migrateFn: async (value: any) => {127return [128['github.copilot.chat.codeGeneration.instructions', { value }],129['github.copilot.chat.experimental.codeGeneration.instructions', { value: undefined }]130];131}132}]);133134ConfigurationMigrationRegistry.registerConfigurationMigrations([{135key: 'github.copilot.chat.experimental.codeGeneration.useInstructionFiles',136migrateFn: async (value: any) => {137return [138['github.copilot.chat.codeGeneration.useInstructionFiles', { value }],139['github.copilot.chat.experimental.codeGeneration.useInstructionFiles', { value: undefined }]140];141}142}]);143144ConfigurationMigrationRegistry.registerConfigurationMigrations([{145key: 'github.copilot.chat.experimental.testGeneration.instructions',146migrateFn: async (value: any) => {147return [148['github.copilot.chat.testGeneration.instructions', { value }],149['github.copilot.chat.experimental.testGeneration.instructions', { value: undefined }]150];151}152}]);153154ConfigurationMigrationRegistry.registerConfigurationMigrations([{155key: 'github.copilot.chat.planAgent.model',156migrateFn: async (value: any) => {157return [158['chat.planAgent.defaultModel', { value }],159['github.copilot.chat.planAgent.model', { value: undefined }]160];161}162}]);163164const oldCursorJumpKey = 'github.copilot.chat.advanced.inlineEdits.nextCursorPrediction.enabled';165const newCursorJumpKey = 'github.copilot.nextEditSuggestions.extendedRange';166ConfigurationMigrationRegistry.registerConfigurationMigrations([{167key: oldCursorJumpKey,168migrateFn: async (value: boolean | /* the rest is for backward compat: */ NextCursorLinePrediction | 'labelOnlyWithEdit' | boolean | undefined) => {169if (typeof value === 'string') { // for backward compatibility -- one of 'onlyWithEdit' | 'jump' | 'labelOnlyWithEdit'170value = true;171} else if (value === undefined) {172value = false;173}174return [175[newCursorJumpKey, { value }],176[oldCursorJumpKey, { value: undefined }]177];178}179}]);180181182