diff --git a/CHANGELOG.md b/CHANGELOG.md index ce5442e..cc4b0dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ ## Fixes and improvements - +# 2.1.0 +## Added features +- Add context sensitive `delete` command +## Fixes and improvements +- Trying to fix delete in text fields on Mac + # 2.0.0 ## Breaking changes - Make `event` use a multiselect, because it is much easier, safer, and faster to use, and can give a more helpful error message. diff --git a/dist/windows.zip b/dist/windows.zip index 721f896..3110f4a 100644 Binary files a/dist/windows.zip and b/dist/windows.zip differ diff --git a/executors.js b/executors.js index 4862aff..309394c 100644 --- a/executors.js +++ b/executors.js @@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.do_event = exports.do_spending = exports.do_remove_auto_approve = exports.do_auto_approve = exports.do_attach_role = exports.do_join = exports.do_post = exports.do_help = exports.do_queue_time = exports.printTableHeader = exports.alignLeft = exports.alignRight = exports.do_cron = exports.do_envvar = exports.do_key = exports.do_inspect = exports.do_build = exports.do_redeploy = exports.do_deploy = exports.generateNewKey = exports.useExistingKey = exports.do_register = exports.addKnownHost = exports.do_duplicate = exports.fetch_template = exports.createService = exports.createServiceGroup = exports.createOrganization = exports.do_clone = exports.do_fetch = void 0; +exports.do_delete_org = exports.do_delete_group = exports.do_delete_service = exports.do_event = exports.do_spending = exports.do_remove_auto_approve = exports.do_auto_approve = exports.do_attach_role = exports.do_join = exports.do_post = exports.do_help = exports.do_queue_time = exports.printTableHeader = exports.alignLeft = exports.alignRight = exports.do_cron = exports.do_envvar = exports.do_key = exports.do_inspect = exports.do_build = exports.do_redeploy = exports.do_deploy = exports.generateNewKey = exports.useExistingKey = exports.do_register = exports.addKnownHost = exports.do_duplicate = exports.fetch_template = exports.createService = exports.createServiceGroup = exports.createOrganization = exports.do_clone = exports.do_fetch = void 0; const fs_1 = __importDefault(require("fs")); const os_1 = __importDefault(require("os")); const utils_1 = require("./utils"); @@ -747,3 +747,42 @@ function do_event(key, events) { }); } exports.do_event = do_event; +function do_delete_service(org, group, service) { + return __awaiter(this, void 0, void 0, function* () { + try { + (0, utils_1.output2)(yield (0, utils_1.sshReq)(`service`, `--delete`, `--org`, org, `--team`, group, service)); + if (fs_1.default.existsSync(service)) + fs_1.default.renameSync(service, `(deleted) ${service}`); + } + catch (e) { + throw e; + } + }); +} +exports.do_delete_service = do_delete_service; +function do_delete_group(org, group) { + return __awaiter(this, void 0, void 0, function* () { + try { + (0, utils_1.output2)(yield (0, utils_1.sshReq)(`team`, `--delete`, `--org`, org, group)); + if (fs_1.default.existsSync(group)) + fs_1.default.renameSync(group, `(deleted) ${group}`); + } + catch (e) { + throw e; + } + }); +} +exports.do_delete_group = do_delete_group; +function do_delete_org(org) { + return __awaiter(this, void 0, void 0, function* () { + try { + (0, utils_1.output2)(yield (0, utils_1.sshReq)(`org`, `--delete`, org)); + if (fs_1.default.existsSync(org)) + fs_1.default.renameSync(org, `(deleted) ${org}`); + } + catch (e) { + throw e; + } + }); +} +exports.do_delete_org = do_delete_org; diff --git a/executors.ts b/executors.ts index ae03c25..347cc2c 100644 --- a/executors.ts +++ b/executors.ts @@ -838,3 +838,44 @@ export async function do_event( throw e; } } + +export async function do_delete_service( + org: string, + group: string, + service: string +) { + try { + output2( + await sshReq( + `service`, + `--delete`, + `--org`, + org, + `--team`, + group, + service + ) + ); + if (fs.existsSync(service)) fs.renameSync(service, `(deleted) ${service}`); + } catch (e) { + throw e; + } +} + +export async function do_delete_group(org: string, group: string) { + try { + output2(await sshReq(`team`, `--delete`, `--org`, org, group)); + if (fs.existsSync(group)) fs.renameSync(group, `(deleted) ${group}`); + } catch (e) { + throw e; + } +} + +export async function do_delete_org(org: string) { + try { + output2(await sshReq(`org`, `--delete`, org)); + if (fs.existsSync(org)) fs.renameSync(org, `(deleted) ${org}`); + } catch (e) { + throw e; + } +} diff --git a/package.json b/package.json index a922a00..52fa801 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@merrymake/cli", - "version": "2.0.0", + "version": "2.1.0", "description": "", "main": "index.js", "scripts": { diff --git a/prompt.js b/prompt.js index 84d1380..7bca903 100644 --- a/prompt.js +++ b/prompt.js @@ -108,14 +108,15 @@ function cleanup() { output(exports.NORMAL_COLOR); output(exports.SHOW_CURSOR); } -function choice(options, invertedQuiet = { cmd: false, select: true }, def = 0) { +function choice(options, opts) { return new Promise((resolve) => { + var _a, _b; let quick = {}; let str = []; - if (options.length === 1) { + if (options.length === 1 && (opts === null || opts === void 0 ? void 0 : opts.disableAutoPick) !== true) { if ((0, args_1.getArgs)().length > 0) (0, args_1.getArgs)().splice(0, 1); - resolve(invertedQuiet.cmd + resolve(((_a = opts === null || opts === void 0 ? void 0 : opts.invertedQuiet) === null || _a === void 0 ? void 0 : _a.cmd) === true ? makeSelection(options[0]) : makeSelectionQuietly(options[0])); return; @@ -130,7 +131,9 @@ function choice(options, invertedQuiet = { cmd: false, select: true }, def = 0) const o = options[i]; if ((0, args_1.getArgs)()[0] === o.long || (0, args_1.getArgs)()[0] === `-${o.short}`) { (0, args_1.getArgs)().splice(0, 1); - resolve(invertedQuiet.cmd ? makeSelection(o) : makeSelectionQuietly(o)); + resolve(((_b = opts === null || opts === void 0 ? void 0 : opts.invertedQuiet) === null || _b === void 0 ? void 0 : _b.cmd) === true + ? makeSelection(o) + : makeSelectionQuietly(o)); return; } if (o.short) @@ -162,13 +165,14 @@ function choice(options, invertedQuiet = { cmd: false, select: true }, def = 0) console.log("This console does not support TTY, please use the 'mmk'-command instead."); process.exit(1); } - let pos = def; + let pos = (opts === null || opts === void 0 ? void 0 : opts.def) || 0; output(exports.YELLOW); moveCursor(0, -options.length + pos); output(`>`); moveCursor(-1, 0); // on any data into stdin node_process_1.stdin.on("data", (listener = (key) => { + var _a; let k = key.toString(); // moveCursor(0, options.length - pos); // //let l = JSON.stringify(key); @@ -176,7 +180,7 @@ function choice(options, invertedQuiet = { cmd: false, select: true }, def = 0) // stdout.write("" + yOffset); // moveCursor(-("" + yOffset).length, -options.length + pos); if (k === exports.ENTER) { - resolve(invertedQuiet.select + resolve(((_a = opts === null || opts === void 0 ? void 0 : opts.invertedQuiet) === null || _a === void 0 ? void 0 : _a.cmd) !== false ? makeSelection(options[pos]) : makeSelectionQuietly(options[pos])); return; @@ -453,15 +457,17 @@ function shortText(prompt, description, defaultValueArg) { output(beforeCursor + afterCursor); moveCursor(-afterCursor.length, 0); } - else if ((k === exports.DELETE || k.charCodeAt(0) === 127) && - afterCursor.length > 0) { + else if (k === exports.DELETE && afterCursor.length > 0) { moveCursor(-beforeCursor.length, 0); afterCursor = afterCursor.substring(1); node_process_1.stdout.clearLine(1); output(beforeCursor + afterCursor); moveCursor(-afterCursor.length, 0); } - else if ((k === exports.BACKSPACE || k.charCodeAt(0) === 8) && + else if ((k === exports.BACKSPACE || + k.charCodeAt(0) === 8 || + k.charCodeAt(0) === 46 || + k.charCodeAt(0) === 127) && beforeCursor.length > 0) { moveCursor(-beforeCursor.length, 0); beforeCursor = beforeCursor.substring(0, beforeCursor.length - 1); diff --git a/prompt.ts b/prompt.ts index eb8e8f3..75758a5 100644 --- a/prompt.ts +++ b/prompt.ts @@ -134,16 +134,19 @@ export type Option = { export function choice( options: Option[], - invertedQuiet = { cmd: false, select: true }, - def: number = 0 + opts?: { + def?: number; + disableAutoPick?: boolean; + invertedQuiet?: { cmd: boolean; select: boolean }; + } ) { return new Promise((resolve) => { let quick: { [key: string]: Option } = {}; let str: string[] = []; - if (options.length === 1) { + if (options.length === 1 && opts?.disableAutoPick !== true) { if (getArgs().length > 0) getArgs().splice(0, 1); resolve( - invertedQuiet.cmd + opts?.invertedQuiet?.cmd === true ? makeSelection(options[0]) : makeSelectionQuietly(options[0]) ); @@ -159,7 +162,11 @@ export function choice( const o = options[i]; if (getArgs()[0] === o.long || getArgs()[0] === `-${o.short}`) { getArgs().splice(0, 1); - resolve(invertedQuiet.cmd ? makeSelection(o) : makeSelectionQuietly(o)); + resolve( + opts?.invertedQuiet?.cmd === true + ? makeSelection(o) + : makeSelectionQuietly(o) + ); return; } if (o.short) quick[o.short] = o; @@ -193,7 +200,7 @@ export function choice( process.exit(1); } - let pos = def; + let pos = opts?.def || 0; output(YELLOW); moveCursor(0, -options.length + pos); output(`>`); @@ -211,7 +218,7 @@ export function choice( // moveCursor(-("" + yOffset).length, -options.length + pos); if (k === ENTER) { resolve( - invertedQuiet.select + opts?.invertedQuiet?.cmd !== false ? makeSelection(options[pos]) : makeSelectionQuietly(options[pos]) ); @@ -511,17 +518,17 @@ export function shortText( stdout.clearLine(1); output(beforeCursor + afterCursor); moveCursor(-afterCursor.length, 0); - } else if ( - (k === DELETE || k.charCodeAt(0) === 127) && - afterCursor.length > 0 - ) { + } else if (k === DELETE && afterCursor.length > 0) { moveCursor(-beforeCursor.length, 0); afterCursor = afterCursor.substring(1); stdout.clearLine(1); output(beforeCursor + afterCursor); moveCursor(-afterCursor.length, 0); } else if ( - (k === BACKSPACE || k.charCodeAt(0) === 8) && + (k === BACKSPACE || + k.charCodeAt(0) === 8 || + k.charCodeAt(0) === 46 || + k.charCodeAt(0) === 127) && beforeCursor.length > 0 ) { moveCursor(-beforeCursor.length, 0); diff --git a/questions.js b/questions.js index fc098fe..148e58f 100644 --- a/questions.js +++ b/questions.js @@ -73,6 +73,18 @@ function spending(org) { (0, utils_1.addToExecuteQueue)(() => (0, executors_1.do_spending)(org)); return (0, utils_1.finish)(); } +function delete_service_name(org, group, service) { + (0, utils_1.addToExecuteQueue)(() => (0, executors_1.do_delete_service)(org, group, service)); + return (0, utils_1.finish)(); +} +function delete_group_name(org, group) { + (0, utils_1.addToExecuteQueue)(() => (0, executors_1.do_delete_group)(org, group)); + return (0, utils_1.finish)(); +} +function delete_org_name(org) { + (0, utils_1.addToExecuteQueue)(() => (0, executors_1.do_delete_org)(org)); + return (0, utils_1.finish)(); +} function service_template(pathToService, template) { return __awaiter(this, void 0, void 0, function* () { try { @@ -254,7 +266,10 @@ function register() { action: () => register_key(executors_1.generateNewKey), }); } - return yield (0, prompt_1.choice)(keys, { cmd: false, select: true }, keys.length - 1).then((x) => x); + return yield (0, prompt_1.choice)(keys, { + invertedQuiet: { cmd: false, select: true }, + def: keys.length - 1, + }).then((x) => x); } catch (e) { throw e; @@ -303,7 +318,7 @@ function queue_id(org, id) { long: x.r, text: `${(0, executors_1.alignRight)(x.r, 12)} │ ${(0, executors_1.alignLeft)(x.e, 12)} │ ${(0, executors_1.alignLeft)(x.s, 7)} │ ${new Date(x.q).toLocaleString()}`, action: () => queue_event(org, x.id, x.r), - })), { cmd: true, select: true }).then((x) => x); + })), { invertedQuiet: { cmd: true, select: true } }).then((x) => x); } function queue_time_value(org, time) { (0, utils_1.addToExecuteQueue)(() => (0, executors_1.do_queue_time)(org, time)); @@ -364,7 +379,9 @@ function queue(org, offset) { text: `specify time`, action: () => queue_time(org), }); - return yield (0, prompt_1.choice)(options, { cmd: false, select: false }).then((x) => x); + return yield (0, prompt_1.choice)(options, { + invertedQuiet: { cmd: false, select: false }, + }).then((x) => x); } catch (e) { throw e; @@ -782,6 +799,54 @@ function envvar(org, group) { } }); } +function delete_service(org, group) { + return __awaiter(this, void 0, void 0, function* () { + try { + let resp = yield (0, utils_1.sshReq)(`list-services`, `--org`, org, `--team`, group); + let orgs = JSON.parse(resp); + return yield (0, prompt_1.choice)(orgs.map((x) => ({ + long: x, + text: `delete ${x}`, + action: () => delete_service_name(org, group, x), + })), { disableAutoPick: true }).then((x) => x); + } + catch (e) { + throw e; + } + }); +} +function delete_group(org) { + return __awaiter(this, void 0, void 0, function* () { + try { + let resp = yield (0, utils_1.sshReq)(`list-teams`, `--org`, org); + let orgs = JSON.parse(resp); + return yield (0, prompt_1.choice)(orgs.map((x) => ({ + long: x, + text: `delete ${x}`, + action: () => delete_group_name(org, x), + })), { disableAutoPick: true }).then((x) => x); + } + catch (e) { + throw e; + } + }); +} +function delete_org() { + return __awaiter(this, void 0, void 0, function* () { + try { + let resp = yield (0, utils_1.sshReq)(`list-organizations`); + let orgs = JSON.parse(resp); + return yield (0, prompt_1.choice)(orgs.map((x) => ({ + long: x, + text: `delete ${x}`, + action: () => delete_org_name(x), + })), { disableAutoPick: true }).then((x) => x); + } + catch (e) { + throw e; + } + }); +} function join() { return __awaiter(this, void 0, void 0, function* () { try { @@ -980,10 +1045,19 @@ function start() { options.push({ long: "repo", short: "r", - text: "create a new repo", + text: "create a repo", action: () => service(selectedGroup_hack.path, orgName, selectedGroup_hack.name), }); } + if (struct.serviceGroup !== null) { + let group = struct.serviceGroup; + options.push({ + long: "delete", + short: "d", + text: "delete a repo", + action: () => delete_service(orgName, group), + }); + } } if (fs_1.default.existsSync("mist.json") || fs_1.default.existsSync("merrymake.json")) { options.push({ @@ -1008,9 +1082,15 @@ function start() { options.push({ long: "group", short: "g", - text: "create a new service group", + text: "create a service group", action: () => group(new utils_2.Path(), orgName), }); + options.push({ + long: "delete", + short: "d", + text: "delete a service group", + action: () => delete_group(orgName), + }); } options.push({ long: "cron", @@ -1090,6 +1170,13 @@ function start() { action: () => checkout(), weight: cache.hasOrgs ? 10 : 3, }); + options.push({ + long: "delete", + short: "d", + text: "delete an organization", + action: () => delete_org(), + weight: cache.hasOrgs ? 10 : 3, + }); options.push({ long: "join", short: "j", diff --git a/questions.ts b/questions.ts index 7260629..b400e0e 100644 --- a/questions.ts +++ b/questions.ts @@ -54,6 +54,9 @@ import { do_auto_approve, do_remove_auto_approve, do_spending, + do_delete_service, + do_delete_group, + do_delete_org, } from "./executors"; import { VERSION_CMD, type ProjectType } from "@merrymake/detect-project-type"; import { execSync } from "child_process"; @@ -127,6 +130,21 @@ function spending(org: string) { return finish(); } +function delete_service_name(org: string, group: string, service: string) { + addToExecuteQueue(() => do_delete_service(org, group, service)); + return finish(); +} + +function delete_group_name(org: string, group: string) { + addToExecuteQueue(() => do_delete_group(org, group)); + return finish(); +} + +function delete_org_name(org: string) { + addToExecuteQueue(() => do_delete_org(org)); + return finish(); +} + async function service_template(pathToService: Path, template: string) { try { let langs = await Promise.all( @@ -342,11 +360,10 @@ async function register() { action: () => register_key(generateNewKey), }); } - return await choice( - keys, - { cmd: false, select: true }, - keys.length - 1 - ).then((x) => x); + return await choice(keys, { + invertedQuiet: { cmd: false, select: true }, + def: keys.length - 1, + }).then((x) => x); } catch (e) { throw e; } @@ -408,7 +425,7 @@ function queue_id(org: string, id: string) { )} │ ${new Date(x.q).toLocaleString()}`, action: () => queue_event(org, x.id, x.r), })), - { cmd: true, select: true } + { invertedQuiet: { cmd: true, select: true } } ).then((x) => x); } @@ -490,7 +507,9 @@ async function queue(org: string, offset: number) { text: `specify time`, action: () => queue_time(org), }); - return await choice(options, { cmd: false, select: false }).then((x) => x); + return await choice(options, { + invertedQuiet: { cmd: false, select: false }, + }).then((x) => x); } catch (e) { throw e; } @@ -993,6 +1012,57 @@ async function envvar(org: string, group: string) { } } +async function delete_service(org: string, group: string) { + try { + let resp = await sshReq(`list-services`, `--org`, org, `--team`, group); + let orgs: string[] = JSON.parse(resp); + return await choice( + orgs.map((x) => ({ + long: x, + text: `delete ${x}`, + action: () => delete_service_name(org, group, x), + })), + { disableAutoPick: true } + ).then((x) => x); + } catch (e) { + throw e; + } +} + +async function delete_group(org: string) { + try { + let resp = await sshReq(`list-teams`, `--org`, org); + let orgs: string[] = JSON.parse(resp); + return await choice( + orgs.map((x) => ({ + long: x, + text: `delete ${x}`, + action: () => delete_group_name(org, x), + })), + { disableAutoPick: true } + ).then((x) => x); + } catch (e) { + throw e; + } +} + +async function delete_org() { + try { + let resp = await sshReq(`list-organizations`); + let orgs: string[] = JSON.parse(resp); + return await choice( + orgs.map((x) => ({ + long: x, + text: `delete ${x}`, + action: () => delete_org_name(x), + })), + { disableAutoPick: true } + ).then((x) => x); + } catch (e) { + throw e; + } +} + async function join() { try { let name = await shortText( @@ -1231,7 +1301,7 @@ export async function start() { options.push({ long: "repo", short: "r", - text: "create a new repo", + text: "create a repo", action: () => service( selectedGroup_hack.path, @@ -1240,6 +1310,15 @@ export async function start() { ), }); } + if (struct.serviceGroup !== null) { + let group = struct.serviceGroup; + options.push({ + long: "delete", + short: "d", + text: "delete a repo", + action: () => delete_service(orgName, group), + }); + } } if (fs.existsSync("mist.json") || fs.existsSync("merrymake.json")) { options.push({ @@ -1266,9 +1345,15 @@ export async function start() { options.push({ long: "group", short: "g", - text: "create a new service group", + text: "create a service group", action: () => group(new Path(), orgName), }); + options.push({ + long: "delete", + short: "d", + text: "delete a service group", + action: () => delete_group(orgName), + }); } options.push({ @@ -1349,6 +1434,13 @@ export async function start() { action: () => checkout(), weight: cache.hasOrgs ? 10 : 3, }); + options.push({ + long: "delete", + short: "d", + text: "delete an organization", + action: () => delete_org(), + weight: cache.hasOrgs ? 10 : 3, + }); options.push({ long: "join", short: "j",