[vscode-spring-cli] User defined command remove, execution and simple new
This commit is contained in:
@@ -9,10 +9,12 @@
|
||||
"version": "1.52.0",
|
||||
"license": "EPL-1.0",
|
||||
"dependencies": {
|
||||
"lodash.debounce": "4.0.8"
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash.debounce": "^4.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash.debounce": "4.0.9",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/lodash.debounce": "^4.0.9",
|
||||
"@types/node": "^18.8.0",
|
||||
"@types/vscode": "1.75.0",
|
||||
"@vscode/vsce": "^2.22.0",
|
||||
@@ -23,6 +25,12 @@
|
||||
"vscode": "^1.75.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/js-yaml": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
||||
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.202",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
|
||||
@@ -133,8 +141,7 @@
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/azure-devops-node-api": {
|
||||
"version": "11.2.0",
|
||||
@@ -729,6 +736,17 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonc-parser": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
|
||||
@@ -1411,6 +1429,12 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/js-yaml": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
||||
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.202",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
|
||||
@@ -1503,8 +1527,7 @@
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"azure-devops-node-api": {
|
||||
"version": "11.2.0",
|
||||
@@ -1936,6 +1959,14 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"jsonc-parser": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
|
||||
|
||||
@@ -74,7 +74,22 @@
|
||||
},
|
||||
{
|
||||
"command": "vscode-spring-cli.command.add",
|
||||
"title": "Add Command",
|
||||
"title": "Add User Defined Command",
|
||||
"category": "Spring CLI"
|
||||
},
|
||||
{
|
||||
"command": "vscode-spring-cli.command.remove",
|
||||
"title": "Remove User Defined Command",
|
||||
"category": "Spring CLI"
|
||||
},
|
||||
{
|
||||
"command": "vscode-spring-cli.command.new",
|
||||
"title": "New User Defined Command",
|
||||
"category": "Spring CLI"
|
||||
},
|
||||
{
|
||||
"command": "vscode-spring-cli.command.execute",
|
||||
"title": "Execute User Defined Command",
|
||||
"category": "Spring CLI"
|
||||
}
|
||||
],
|
||||
@@ -123,9 +138,11 @@
|
||||
"vsce-pre-release-package": "vsce package --pre-release"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash.debounce": "^4.0.8"
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"js-yaml": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/lodash.debounce": "^4.0.9",
|
||||
"@types/node": "^18.8.0",
|
||||
"@types/vscode": "1.75.0",
|
||||
|
||||
@@ -20,13 +20,41 @@ export interface BootAddMetadata {
|
||||
catalog?: string;
|
||||
}
|
||||
|
||||
export interface commandAddMetadata {
|
||||
export interface CommandAddMetadata {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface CommandRemoveMetadata {
|
||||
command: string;
|
||||
subcommand: string;
|
||||
cwd: string;
|
||||
}
|
||||
|
||||
export interface ProjectCatalog {
|
||||
name: string;
|
||||
url: string;
|
||||
description?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export interface CommandInfo {
|
||||
description?: string
|
||||
options: CommandOptions[];
|
||||
}
|
||||
|
||||
export interface CommandOptions {
|
||||
name: string;
|
||||
description?: string;
|
||||
paramLabel?: string;
|
||||
dataType: string;
|
||||
defaultValue: string;
|
||||
inputType: string;
|
||||
required: boolean;
|
||||
choices: {[name: string]: string}
|
||||
}
|
||||
|
||||
export interface CommandExecuteMetadata {
|
||||
command: string;
|
||||
subcommand: string;
|
||||
params: {[name: string]: string};
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
import { BootAddMetadata, BootNewMetadata, Project, ProjectCatalog, commandAddMetadata } from "./cli-types";
|
||||
import { BootAddMetadata, BootNewMetadata, Project, ProjectCatalog, CommandAddMetadata, CommandRemoveMetadata, CommandInfo, CommandExecuteMetadata } from "./cli-types";
|
||||
import { CancellationToken, ProcessExecution, ProgressLocation, ProviderResult, Task, TaskProvider, TaskScope, Uri, tasks, window, workspace } from "vscode";
|
||||
import cp from "child_process";
|
||||
import { homedir } from "os";
|
||||
import { getWorkspaceRoot } from "./utils";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import yaml from "js-yaml";
|
||||
|
||||
export const SPRING_CLI_TASK_TYPE = 'spring-cli';
|
||||
|
||||
@@ -12,10 +15,6 @@ export class Cli {
|
||||
return workspace.getConfiguration("spring-cli").get("executable") || "spring";
|
||||
}
|
||||
|
||||
isBorderLine(s: string) {
|
||||
return !/(\s|\S)+/.test(s);
|
||||
}
|
||||
|
||||
projectList() : Promise<Project[]> {
|
||||
return this.fetchJson("Fetching projects...", undefined, ["project", "list"]);
|
||||
}
|
||||
@@ -28,14 +27,87 @@ export class Cli {
|
||||
return this.fetchJson("Fetching Available Catalogs...", undefined, ["project-catalog", "list-available"]);
|
||||
}
|
||||
|
||||
commandAdd(metadata: commandAddMetadata) {
|
||||
commandAdd(metadata: CommandAddMetadata, cwd?: string) {
|
||||
const args = [
|
||||
"command",
|
||||
"add",
|
||||
"--from",
|
||||
metadata.url
|
||||
];
|
||||
this.exec("Add Command", metadata.url, args);
|
||||
this.exec("Add Command", metadata.url, args, cwd || homedir());
|
||||
}
|
||||
|
||||
commandRemove(metadata: CommandRemoveMetadata) {
|
||||
const args = [
|
||||
"command",
|
||||
"remove",
|
||||
"--commandName",
|
||||
metadata.command,
|
||||
"--subCommandName",
|
||||
metadata.subcommand
|
||||
];
|
||||
this.exec("Remove Command", `'${metadata.command} ${metadata.subcommand}'`, args, metadata.cwd);
|
||||
}
|
||||
|
||||
commandList(cwd: string, command?: string): Promise<string[]> {
|
||||
return new Promise(async(resolve, reject) => {
|
||||
let p = path.join(cwd, ".spring", "commands");
|
||||
if (command) {
|
||||
p = path.join(p, command);
|
||||
}
|
||||
fs.readdir(p, { withFileTypes: true }, (error, files) => {
|
||||
if (error) {
|
||||
reject(error.message);
|
||||
} else {
|
||||
resolve(files.filter(d => d.isDirectory()).map(d => d.name));
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
commandInfo(cwd: string, command: string, subcommand: string): Promise<CommandInfo> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parentFolder = path.join(cwd, ".spring", "commands", command, subcommand);
|
||||
let file;
|
||||
if (fs.existsSync(path.join(parentFolder, "command.yaml"))) {
|
||||
file = path.join(parentFolder, "command.yaml");
|
||||
} else if (fs.existsSync(path.join(parentFolder, "command.yml"))) {
|
||||
file = path.join(parentFolder, "command.yml");
|
||||
}
|
||||
if (file) {
|
||||
const content = fs.readFileSync(file, "utf-8");
|
||||
const obj = yaml.load(content, {json: true}) as any;
|
||||
if (typeof obj === 'object' && obj?.command) {
|
||||
resolve(obj.command as CommandInfo);
|
||||
} else {
|
||||
reject(`Unable to read command '${command} ${subcommand}' info`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
commandNew(cwd: string) {
|
||||
const args = [
|
||||
"command",
|
||||
"new",
|
||||
];
|
||||
return this.exec("Remove Command", undefined, args, cwd);
|
||||
}
|
||||
|
||||
commandExecute(metadata: CommandExecuteMetadata, cwd: string) {
|
||||
const args = [
|
||||
metadata.command,
|
||||
metadata.subcommand,
|
||||
];
|
||||
Object.keys(metadata.params).forEach(p => {
|
||||
args.push(`--${p}`);
|
||||
args.push(metadata.params[p]);
|
||||
});
|
||||
return this.exec("Executing Command", `'${metadata.command} ${metadata.subcommand}'`, args, cwd);
|
||||
}
|
||||
|
||||
projectCatalogAdd(catalog: ProjectCatalog): Promise<void> {
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
import { Uri, window } from "vscode";
|
||||
import { QuickPickItem, Uri, WorkspaceFolder, window, workspace } from "vscode";
|
||||
import { enterText } from "./utils";
|
||||
import { CLI } from "./extension";
|
||||
import { homedir } from "os";
|
||||
import { CommandInfo } from "./cli-types";
|
||||
|
||||
export async function handleCommandAdd() {
|
||||
interface SubCommandQuickPickItem extends QuickPickItem {
|
||||
info?: CommandInfo;
|
||||
}
|
||||
|
||||
interface ChoiceQuickPickItem extends QuickPickItem {
|
||||
value: string;
|
||||
}
|
||||
|
||||
const GLOBAL: QuickPickItem = {
|
||||
label: "GLOBAL",
|
||||
description: "Globally available for all user projects",
|
||||
detail: homedir()
|
||||
};
|
||||
|
||||
const LOCAL_SCOPE_DESCRIPTION = "Available only within selected workspace folder"
|
||||
|
||||
export async function handleCommandAdd(uri?: Uri) {
|
||||
|
||||
// Enter CWD for CLI (global vs workspace folder local command)
|
||||
const cwd = await enterCwd(uri);
|
||||
|
||||
// Enter URL of the repo for the command to add
|
||||
let url;
|
||||
try {
|
||||
url = await enterText({
|
||||
@@ -22,14 +45,109 @@ export async function handleCommandAdd() {
|
||||
}
|
||||
|
||||
if (url) {
|
||||
CLI.commandAdd({url});
|
||||
CLI.commandAdd({url}, cwd);
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleCommandRemove() {
|
||||
window.showErrorMessage("Not Implemented!");
|
||||
export async function handleCommandRemove(uri?: Uri) {
|
||||
// Enter CWD for CLI (global vs workspace folder local command)
|
||||
const cwd = await enterCwd(uri);
|
||||
// Select the command
|
||||
const command = await pickCommand(cwd);
|
||||
// Select the subcommand
|
||||
const subcommand = (await pickSubCommand(cwd, command))?.label;
|
||||
return CLI.commandRemove({
|
||||
command,
|
||||
subcommand,
|
||||
cwd
|
||||
});
|
||||
}
|
||||
|
||||
export async function handleCommandNew() {
|
||||
window.showErrorMessage("Not Implemented!");
|
||||
export async function handleCommandNew(uri?: Uri) {
|
||||
const cwd = await enterCwd(uri);
|
||||
return CLI.commandNew(cwd);
|
||||
}
|
||||
|
||||
export async function handleCommandExecute(uri?: Uri) {
|
||||
// Enter CWD for CLI (global vs workspace folder local command)
|
||||
const cwd = await enterCwd(uri);
|
||||
// Select the command
|
||||
const command = await pickCommand(cwd);
|
||||
// Select the subcommand
|
||||
const subcommand = (await pickSubCommand(cwd, command));
|
||||
|
||||
const params = {};
|
||||
|
||||
if (Array.isArray(subcommand?.info?.options)) {
|
||||
for (const o of subcommand.info.options) {
|
||||
let value;
|
||||
if (o.choices) {
|
||||
const quickPickItems = Object.keys(o.choices).map(s => ({
|
||||
label: s,
|
||||
value: o.choices[s]
|
||||
}) as ChoiceQuickPickItem);
|
||||
value = (await window.showQuickPick(quickPickItems, { canPickMany: false, ignoreFocusOut: true })).value;
|
||||
} else {
|
||||
value = await enterText({
|
||||
title: o.paramLabel || o.name,
|
||||
defaultValue: o.defaultValue,
|
||||
placeholder: o.defaultValue,
|
||||
prompt: `Enter ${o.paramLabel || o.name}${o.description ? " - " : ""}${o.description}`
|
||||
});
|
||||
}
|
||||
if (value) {
|
||||
params[o.name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CLI.commandExecute({
|
||||
command,
|
||||
subcommand: subcommand.label,
|
||||
params
|
||||
}, cwd);
|
||||
}
|
||||
|
||||
function mapFolderToQuickPickItem(folder: WorkspaceFolder): QuickPickItem {
|
||||
return {
|
||||
label: folder.name,
|
||||
description: LOCAL_SCOPE_DESCRIPTION,
|
||||
detail: folder.uri.fsPath
|
||||
};
|
||||
}
|
||||
|
||||
async function enterCwd(uri?: Uri): Promise<string> {
|
||||
const commandScopes = [ GLOBAL ];
|
||||
if (uri) {
|
||||
const folder = workspace.getWorkspaceFolder(uri);
|
||||
if (folder) {
|
||||
commandScopes.push(mapFolderToQuickPickItem(folder));
|
||||
}
|
||||
} else {
|
||||
commandScopes.push(...workspace.workspaceFolders.map(mapFolderToQuickPickItem));
|
||||
}
|
||||
|
||||
return commandScopes.length > 1 ? (await window.showQuickPick(commandScopes, { canPickMany: false, ignoreFocusOut: true }))?.detail : GLOBAL.detail;
|
||||
}
|
||||
|
||||
async function pickCommand(cwd: string): Promise<string> {
|
||||
return await window.showQuickPick(CLI.commandList(cwd), { canPickMany: false, ignoreFocusOut: true});
|
||||
}
|
||||
|
||||
async function pickSubCommand(cwd: string, command: string): Promise<SubCommandQuickPickItem> {
|
||||
const deferredItems = CLI.commandList(cwd, command).then(async subcommands => {
|
||||
return await Promise.all(subcommands.map(async sc => {
|
||||
const qp: SubCommandQuickPickItem = {
|
||||
label: sc,
|
||||
};
|
||||
try {
|
||||
qp.info = await CLI.commandInfo(cwd, command, sc);
|
||||
qp.description = qp.info.description;
|
||||
} catch (error) {
|
||||
window.showWarningMessage(`Could not fetch info for CLI command: '${command} ${sc}'`);
|
||||
}
|
||||
return qp;
|
||||
}));
|
||||
});
|
||||
return await window.showQuickPick(deferredItems, {canPickMany: false, ignoreFocusOut: true});
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { Cli, CliTaskProvider, SPRING_CLI_TASK_TYPE } from "./cli";
|
||||
import { handleBootAdd, handleBootNew } from "./boot";
|
||||
import { handleCatalogAdd, handleCatalogRemove } from "./project-catalog";
|
||||
import { handleProjectAdd, handleProjectRemove } from "./project";
|
||||
import { handleCommandAdd, handleCommandNew, handleCommandRemove } from "./command";
|
||||
import { handleCommandAdd, handleCommandExecute, handleCommandNew, handleCommandRemove } from "./command";
|
||||
import { ExtensionContext, commands, tasks } from "vscode";
|
||||
|
||||
export const CLI = new Cli();
|
||||
@@ -25,6 +25,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
|
||||
context.subscriptions.push(commands.registerCommand('vscode-spring-cli.command.add', handleCommandAdd));
|
||||
context.subscriptions.push(commands.registerCommand('vscode-spring-cli.command.remove', handleCommandRemove));
|
||||
context.subscriptions.push(commands.registerCommand('vscode-spring-cli.command.new', handleCommandNew));
|
||||
context.subscriptions.push(commands.registerCommand('vscode-spring-cli.command.execute', handleCommandExecute));
|
||||
|
||||
context.subscriptions.push(tasks.registerTaskProvider(SPRING_CLI_TASK_TYPE, new CliTaskProvider(CLI)));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user