Implement feature toggles for beta commands
- Added feature toggles for beta commands in the package.json file. - Implemented dynamic registration of commands based on feature toggles. - Added error messages for users trying to access beta commands without the correct permissions. - Updated the version of the devchat-ask package based on the feature toggles. - Created a new featureToggle handler to manage feature toggles.
This commit is contained in:
parent
fa9bb41fd6
commit
9c16bced23
@ -2,7 +2,7 @@
|
||||
"name": "devchat",
|
||||
"displayName": "DevChat",
|
||||
"description": "Write prompts, not code",
|
||||
"version": "0.1.17",
|
||||
"version": "0.1.22",
|
||||
"icon": "assets/devchat.png",
|
||||
"publisher": "merico",
|
||||
"engines": {
|
||||
@ -165,6 +165,11 @@
|
||||
"type": "string",
|
||||
"default": ".+\\.js$, .+\\.ts$, .+\\.jsx$, .+\\.tsx$, .+\\.java$, .+\\.py$, .+\\.go$, .+\\.rb$, .+\\.php$, .+\\.cpp$, .+\\.c$, .+\\.cs$, .+\\.swift$, .+\\.rs$, .+\\.sh$, .+\\.bash$, .+\\.zsh$, .+\\.m$, .+\\.mm$, .+\\.h$, .+\\.hpp$, .+\\.hh$, .+\\.html$, .+\\.htm$, .+\\.xhtml$, .+\\.xml$, .+\\.css$, .+\\.scss$, .+\\.sass$, .+\\.less$, .+\\.json$, .+\\.yaml$, .+\\.yml$, .+\\.toml$, .+\\.ini$, .+\\.md$, .+\\.markdown$, .+\\.txt$, .+\\.csv$, .+\\.sql$, .+\\.sqlite$, .+\\.db$, .+\\.hql$, .+\\.psql$, .+\\.pgsql$, .+\\.plpgsql$",
|
||||
"description": "Comma-separated list of regular expressions for supported file types for analysis."
|
||||
},
|
||||
"DevChat.betaInvitationCode": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "The invitation code for beta testing."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { FT } from "../util/feature_flags/feature_toggles";
|
||||
import CustomCommands from "./customCommand";
|
||||
|
||||
export interface Command {
|
||||
@ -17,15 +18,17 @@ class CommandManager {
|
||||
public static getInstance(): CommandManager {
|
||||
if (!CommandManager.instance) {
|
||||
CommandManager.instance = new CommandManager();
|
||||
CommandManager.instance.registerCommand({
|
||||
name: 'ask-code',
|
||||
pattern: 'ask-code',
|
||||
description: 'ask code',
|
||||
args: 0,
|
||||
handler: async (commandName: string, userInput: string) => {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
if (FT("ask-code")) {
|
||||
CommandManager.instance.registerCommand({
|
||||
name: 'ask-code',
|
||||
pattern: 'ask-code',
|
||||
description: 'ask code',
|
||||
args: 0,
|
||||
handler: async (commandName: string, userInput: string) => {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return CommandManager.instance;
|
||||
|
@ -17,6 +17,8 @@ import { installAskCode as installAskCodeFun } from '../util/python_installer/in
|
||||
import { ProgressBar } from '../util/progressBar';
|
||||
import path from 'path';
|
||||
import { MessageHandler } from '../handler/messageHandler';
|
||||
import { FT } from '../util/feature_flags/feature_toggles';
|
||||
import { getPackageVersion } from '../util/python_installer/pip_package_version';
|
||||
|
||||
let indexProcess: CommandRun | null = null;
|
||||
let summaryIndexProcess: CommandRun | null = null;
|
||||
@ -238,17 +240,37 @@ export function TestDevChatCommand(context: vscode.ExtensionContext) {
|
||||
|
||||
export function registerAskCodeIndexStartCommand(context: vscode.ExtensionContext) {
|
||||
let disposable = vscode.commands.registerCommand('DevChat.AskCodeIndexStart', async () => {
|
||||
if (!FT("ask-code")) {
|
||||
UiUtilWrapper.showErrorMessage("This command is a beta version command and has not been released yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
const progressBar = new ProgressBar();
|
||||
progressBar.init();
|
||||
|
||||
progressBar.update("Index source code files for ask codebase ...", 0);
|
||||
|
||||
const config = getConfig();
|
||||
const pythonVirtualEnv = config.pythonVirtualEnv;
|
||||
let pythonVirtualEnv: any = config.pythonVirtualEnv;
|
||||
const supportedFileTypes = config.supportedFileTypes;
|
||||
|
||||
updateIndexingStatus("started");
|
||||
|
||||
if (pythonVirtualEnv) {
|
||||
// check whether pythonVirtualEnv is stisfy the requirement version
|
||||
const devchatAskVersion = getPackageVersion(pythonVirtualEnv, "devchat-ask");
|
||||
|
||||
let requireAskVersion = "0.0.8";
|
||||
if (FT("ask-code-summary")) {
|
||||
requireAskVersion = "0.0.10";
|
||||
}
|
||||
|
||||
if (!devchatAskVersion || devchatAskVersion < requireAskVersion) {
|
||||
logger.channel()?.info(`The version of devchat-ask is ${devchatAskVersion}`);
|
||||
pythonVirtualEnv = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pythonVirtualEnv) {
|
||||
progressBar.update("Install devchat-ask package ...", 0);
|
||||
await installAskCode(supportedFileTypes, progressBar, indexCode);
|
||||
@ -345,6 +367,11 @@ async function indexCode(pythonVirtualEnv, supportedFileTypes, progressBar: any)
|
||||
|
||||
export function registerAskCodeIndexStopCommand(context: vscode.ExtensionContext) {
|
||||
let disposable = vscode.commands.registerCommand('DevChat.AskCodeIndexStop', async () => {
|
||||
if (!FT("ask-code")) {
|
||||
UiUtilWrapper.showErrorMessage("This command is a beta version command and has not been released yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (indexProcess) {
|
||||
indexProcess.stop();
|
||||
indexProcess = null;
|
||||
@ -355,7 +382,12 @@ export function registerAskCodeIndexStopCommand(context: vscode.ExtensionContext
|
||||
|
||||
export function registerAskCodeSummaryIndexStartCommand(context: vscode.ExtensionContext) {
|
||||
let disposable = vscode.commands.registerCommand('DevChat.AskCodeSummaryIndexStart', async () => {
|
||||
const progressBar = new ProgressBar();
|
||||
if (!FT("ask-code-summary")) {
|
||||
UiUtilWrapper.showErrorMessage("This command is a beta version command and has not been released yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
const progressBar = new ProgressBar();
|
||||
progressBar.init();
|
||||
|
||||
progressBar.update("Index source code files for ask codebase summary...", 0);
|
||||
@ -438,9 +470,12 @@ async function indexCodeSummary(pythonVirtualEnv, supportedFileTypes, progressBa
|
||||
|
||||
export function registerAskCodeSummaryIndexStopCommand(context: vscode.ExtensionContext) {
|
||||
let disposable = vscode.commands.registerCommand('DevChat.AskCodeIndexSummaryStop', async () => {
|
||||
// 在这里实现停止索引的功能
|
||||
// 你可能需要检查summaryIndexProcess变量是否为null,如果不为null,那么停止索引进程
|
||||
if (summaryIndexProcess) {
|
||||
if (!FT("ask-code-summary")) {
|
||||
UiUtilWrapper.showErrorMessage("This command is a beta version command and has not been released yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (summaryIndexProcess) {
|
||||
summaryIndexProcess.stop();
|
||||
summaryIndexProcess = null;
|
||||
}
|
||||
@ -450,7 +485,12 @@ export function registerAskCodeSummaryIndexStopCommand(context: vscode.Extension
|
||||
|
||||
export function registerAddSummaryContextCommand(context: vscode.ExtensionContext) {
|
||||
const callback = async (uri: { fsPath: any; }) => {
|
||||
if (!await ensureChatPanel(context)) {
|
||||
if (!FT("ask-code-summary")) {
|
||||
UiUtilWrapper.showErrorMessage("This command is a beta version command and has not been released yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await ensureChatPanel(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ import { LoggerChannelVscode } from './util/logger_vscode';
|
||||
import { createStatusBarItem, createAskCodeStatusBarItem } from './panel/statusBarView';
|
||||
import { UiUtilWrapper } from './util/uiUtil';
|
||||
import { UiUtilVscode } from './util/uiUtil_vscode';
|
||||
import { FT } from './util/feature_flags/feature_toggles';
|
||||
|
||||
|
||||
function activate(context: vscode.ExtensionContext) {
|
||||
@ -52,7 +53,9 @@ function activate(context: vscode.ExtensionContext) {
|
||||
registerStatusBarItemClickCommand(context);
|
||||
|
||||
createStatusBarItem(context);
|
||||
createAskCodeStatusBarItem(context);
|
||||
if (FT("ask-code")) {
|
||||
createAskCodeStatusBarItem(context);
|
||||
}
|
||||
|
||||
regTopicDeleteCommand(context);
|
||||
regAddTopicCommand(context);
|
||||
@ -62,10 +65,12 @@ function activate(context: vscode.ExtensionContext) {
|
||||
regApplyDiffResultCommand(context);
|
||||
|
||||
regPythonPathCommand(context);
|
||||
registerAskCodeIndexStartCommand(context);
|
||||
registerAskCodeIndexStopCommand(context);
|
||||
registerAskCodeSummaryIndexStartCommand(context);
|
||||
registerAskCodeSummaryIndexStopCommand(context);
|
||||
|
||||
registerAskCodeIndexStartCommand(context);
|
||||
registerAskCodeIndexStopCommand(context);
|
||||
|
||||
registerAskCodeSummaryIndexStartCommand(context);
|
||||
registerAskCodeSummaryIndexStopCommand(context);
|
||||
registerAddSummaryContextCommand(context);
|
||||
}
|
||||
exports.activate = activate;
|
23
src/handler/featureToggle.ts
Normal file
23
src/handler/featureToggle.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
check whether some feature is enabled
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { regInMessage, regOutMessage } from '../util/reg_messages';
|
||||
import { logger } from '../util/logger';
|
||||
import { FT, FTs } from '../util/feature_flags/feature_toggles';
|
||||
import { MessageHandler } from './messageHandler';
|
||||
|
||||
regInMessage({command: 'featureToggle', feature: 'feature name'});
|
||||
regOutMessage({command: 'featureToggle', feature: 'feature name', enabled: true});
|
||||
export async function featureToggle(message: any, panel: vscode.WebviewPanel|vscode.WebviewView): Promise<void> {
|
||||
const enabled = FT(message.feature);
|
||||
MessageHandler.sendMessage(panel, {command: 'featureToggle', feature: message.feature, enabled: enabled});
|
||||
}
|
||||
|
||||
regInMessage({command: 'featureToggles'});
|
||||
regOutMessage({command: 'featureToggles', features: {'feature name': true}});
|
||||
export async function featureToggles(message: any, panel: vscode.WebviewPanel|vscode.WebviewView): Promise<void> {
|
||||
const featureTaggles = FTs();
|
||||
MessageHandler.sendMessage(panel, {command: 'featureToggles', features: featureTaggles});
|
||||
}
|
@ -17,6 +17,7 @@ import { regActionList } from './regActionList';
|
||||
import { applyAction } from './applyAction';
|
||||
import { doCommand } from './doCommand';
|
||||
import { getSetting, updateSetting } from './updateConfig';
|
||||
import { featureToggle, featureToggles } from './featureToggle';
|
||||
|
||||
|
||||
// According to the context menu selected by the user, add the corresponding context file
|
||||
@ -85,4 +86,6 @@ messageHandler.registerHandler('askCode', askCode);
|
||||
messageHandler.registerHandler('doCommand', doCommand);
|
||||
|
||||
messageHandler.registerHandler('updateSetting', updateSetting);
|
||||
messageHandler.registerHandler('getSetting', getSetting);
|
||||
messageHandler.registerHandler('getSetting', getSetting);
|
||||
messageHandler.registerHandler('featureToggle', featureToggle);
|
||||
messageHandler.registerHandler('featureToggles', featureToggles);
|
||||
|
@ -11,6 +11,7 @@ import { ApiKeyManager } from '../util/apiKey';
|
||||
import { regeneration, sendMessage as sendMessageX } from './sendMessage';
|
||||
import { codeFileApply } from './codeFileApply';
|
||||
import { applyAction } from './applyAction';
|
||||
import { FT } from '../util/feature_flags/feature_toggles';
|
||||
|
||||
let autox = false;
|
||||
|
||||
@ -53,9 +54,11 @@ export class MessageHandler {
|
||||
autox = true;
|
||||
}
|
||||
// if "/ask-code" in message.text, then call devchat-ask to get result
|
||||
if (message.text.indexOf('/ask-code') !== -1) {
|
||||
message.command = 'askCode';
|
||||
message.text = message.text.replace('/ask-code', '');
|
||||
if (FT("ask-code")) {
|
||||
if (message.text.indexOf('/ask-code') !== -1) {
|
||||
message.command = 'askCode';
|
||||
message.text = message.text.replace('/ask-code', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
27
src/util/feature_flags/feature_toggles.ts
Normal file
27
src/util/feature_flags/feature_toggles.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const featureTogglesJson = `
|
||||
{
|
||||
"ask-code-summary": false,
|
||||
"ask-code": true,
|
||||
"ask-code-dfs": false
|
||||
}`;
|
||||
const featureToggles = JSON.parse(featureTogglesJson);
|
||||
|
||||
export function FT(feature: string): boolean {
|
||||
const betaInvitationCode = vscode.workspace.getConfiguration('DevChat').get<string>('betaInvitationCode');
|
||||
const expectedInvitationCode = 'WELCOMEADDTODEVCHAT';
|
||||
|
||||
return betaInvitationCode === expectedInvitationCode || featureToggles[feature] === true;
|
||||
}
|
||||
|
||||
export function FTs(): any {
|
||||
// visited features
|
||||
let newFeatureToggles = {};
|
||||
for (const feature in featureToggles) {
|
||||
newFeatureToggles[feature] = FT(feature);
|
||||
}
|
||||
return newFeatureToggles;
|
||||
}
|
18
src/util/feature_flags/readme.txt
Normal file
18
src/util/feature_flags/readme.txt
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
总结如下:
|
||||
|
||||
在VSCode插件开发中,我们讨论了如何实现内测功能的激活控制。主要有以下几种方式:
|
||||
|
||||
1. **使用特定的配置项**:在插件的配置项中添加一个特定的字段,例如`enableBetaFeatures`,根据这个配置项的值来决定是否启用内测功能。
|
||||
|
||||
2. **使用特定的命令**:在插件中添加一个特定的命令,例如`activateBetaFeatures`,只有当用户执行了这个命令,才启用内测功能。
|
||||
|
||||
3. **使用许可证**:在插件中添加一个许可证验证功能,只有当用户输入了有效的许可证,才启用内测功能。
|
||||
|
||||
4. **使用特定的版本**:在插件的版本号中添加一个特定的标识,例如`1.0.0-beta`,只有当插件的版本号包含了这个标识,才启用内测功能。
|
||||
|
||||
为了避免在内测结束后需要修改代码,我们推荐使用特性开关(Feature Toggles)的方式来管理内测功能。可以创建一个特性开关的配置文件,例如`feature-toggles.json`,在这个文件中定义哪些特性是开启的,哪些特性是关闭的。在插件代码中,读取这个配置文件,根据特性开关的值来决定是否启用某个特性。
|
||||
|
||||
对于`package.json`文件中定义的命令,我们可以在插件的激活函数(`activate`函数)中动态地注册或注销命令来实现这个功能。首先,在`package.json`文件中定义所有可能需要的命令,包括内测命令。然后,在`activate`函数中,根据特性开关的值来决定是否注册内测命令。
|
||||
|
||||
以上就是我们对于VSCode插件开发中内测功能激活控制的讨论总结。
|
@ -2,7 +2,8 @@
|
||||
Install DevChat with python=3.11.4
|
||||
*/
|
||||
|
||||
import { logger } from "../logger";
|
||||
import { FT } from "../feature_flags/feature_toggles";
|
||||
import { logger } from "../logger";
|
||||
import { appInstall } from "./app_install"
|
||||
|
||||
|
||||
@ -12,7 +13,11 @@
|
||||
export async function installAskCode(): Promise<string> {
|
||||
try {
|
||||
logger.channel()?.info(`start installing AskCode with python=3.11.4 ...`);
|
||||
const pythonCommand = await appInstall('devchat-ask', '3.11.4');
|
||||
let devchatAskVersion = 'devchat-ask>=0.0.8';
|
||||
if (FT("ask-code-summary")) {
|
||||
devchatAskVersion = 'devchat-ask>=0.0.10';
|
||||
}
|
||||
const pythonCommand = await appInstall(devchatAskVersion, '3.11.4');
|
||||
if (!pythonCommand) {
|
||||
logger.channel()?.error(`failed to install devchat-ask with python=3.11.4`);
|
||||
logger.channel()?.show();
|
||||
|
Loading…
x
Reference in New Issue
Block a user