@cat-indev/catops-cli 0.0.1-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1254 -0
- package/dist/bin/devops-cli.d.ts +2 -0
- package/dist/bin/devops-cli.js +132 -0
- package/dist/bin/devops-cli.js.map +1 -0
- package/dist/core/Context.d.ts +56 -0
- package/dist/core/Context.js +197 -0
- package/dist/core/Context.js.map +1 -0
- package/dist/core/Menu.d.ts +23 -0
- package/dist/core/Menu.js +160 -0
- package/dist/core/Menu.js.map +1 -0
- package/dist/core/Notifier.d.ts +42 -0
- package/dist/core/Notifier.js +128 -0
- package/dist/core/Notifier.js.map +1 -0
- package/dist/core/classifiers.d.ts +45 -0
- package/dist/core/classifiers.js +90 -0
- package/dist/core/classifiers.js.map +1 -0
- package/dist/core/logger.d.ts +8 -0
- package/dist/core/logger.js +37 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/messages.d.ts +102 -0
- package/dist/core/messages.js +163 -0
- package/dist/core/messages.js.map +1 -0
- package/dist/core/prompt.d.ts +10 -0
- package/dist/core/prompt.js +87 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/senders.d.ts +27 -0
- package/dist/core/senders.js +109 -0
- package/dist/core/senders.js.map +1 -0
- package/dist/core/types.d.ts +135 -0
- package/dist/core/types.js +33 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/services/ansible.d.ts +12 -0
- package/dist/services/ansible.js +35 -0
- package/dist/services/ansible.js.map +1 -0
- package/dist/services/archive.d.ts +4 -0
- package/dist/services/archive.js +16 -0
- package/dist/services/archive.js.map +1 -0
- package/dist/services/argocd.d.ts +23 -0
- package/dist/services/argocd.js +48 -0
- package/dist/services/argocd.js.map +1 -0
- package/dist/services/az.d.ts +38 -0
- package/dist/services/az.js +51 -0
- package/dist/services/az.js.map +1 -0
- package/dist/services/azdo-api.d.ts +213 -0
- package/dist/services/azdo-api.js +247 -0
- package/dist/services/azdo-api.js.map +1 -0
- package/dist/services/azdo.d.ts +13 -0
- package/dist/services/azdo.js +57 -0
- package/dist/services/azdo.js.map +1 -0
- package/dist/services/docker.d.ts +21 -0
- package/dist/services/docker.js +36 -0
- package/dist/services/docker.js.map +1 -0
- package/dist/services/git.d.ts +9 -0
- package/dist/services/git.js +36 -0
- package/dist/services/git.js.map +1 -0
- package/dist/services/helm.d.ts +4 -0
- package/dist/services/helm.js +24 -0
- package/dist/services/helm.js.map +1 -0
- package/dist/services/http-types.d.ts +57 -0
- package/dist/services/http-types.js +3 -0
- package/dist/services/http-types.js.map +1 -0
- package/dist/services/http.d.ts +64 -0
- package/dist/services/http.js +288 -0
- package/dist/services/http.js.map +1 -0
- package/dist/services/index.d.ts +37 -0
- package/dist/services/index.js +88 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/kubectl.d.ts +137 -0
- package/dist/services/kubectl.js +271 -0
- package/dist/services/kubectl.js.map +1 -0
- package/dist/services/npm.d.ts +5 -0
- package/dist/services/npm.js +20 -0
- package/dist/services/npm.js.map +1 -0
- package/dist/services/oc.d.ts +156 -0
- package/dist/services/oc.js +309 -0
- package/dist/services/oc.js.map +1 -0
- package/dist/services/pipeline.d.ts +116 -0
- package/dist/services/pipeline.js +474 -0
- package/dist/services/pipeline.js.map +1 -0
- package/dist/services/shell.d.ts +28 -0
- package/dist/services/shell.js +206 -0
- package/dist/services/shell.js.map +1 -0
- package/dist/services/tekton.d.ts +16 -0
- package/dist/services/tekton.js +46 -0
- package/dist/services/tekton.js.map +1 -0
- package/dist/services/terraform.d.ts +31 -0
- package/dist/services/terraform.js +63 -0
- package/dist/services/terraform.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const Context_1 = require("../core/Context");
|
|
40
|
+
const Menu_1 = require("../core/Menu");
|
|
41
|
+
const logger_1 = require("../core/logger");
|
|
42
|
+
const CONFIG_CANDIDATES = [
|
|
43
|
+
"devops.pipeline.js",
|
|
44
|
+
"devops.config.js",
|
|
45
|
+
".catops-cli.js"
|
|
46
|
+
];
|
|
47
|
+
function findConfig() {
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
for (const file of CONFIG_CANDIDATES) {
|
|
50
|
+
const fullPath = path.join(cwd, file);
|
|
51
|
+
if (fs.existsSync(fullPath)) {
|
|
52
|
+
return fullPath;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function printHelp() {
|
|
58
|
+
console.log(`
|
|
59
|
+
catops-cli — framework CLI para pipelines DevOps
|
|
60
|
+
|
|
61
|
+
Uso:
|
|
62
|
+
catops-cli [--flag] [--param=valor]
|
|
63
|
+
|
|
64
|
+
Este comando busca, en el directorio actual, uno de estos archivos:
|
|
65
|
+
${CONFIG_CANDIDATES.join("\n ")}
|
|
66
|
+
|
|
67
|
+
Ese archivo debe exportar una definición de menú, por ejemplo:
|
|
68
|
+
|
|
69
|
+
// devops.pipeline.js
|
|
70
|
+
module.exports = (ctx) => ({
|
|
71
|
+
title: "Pipeline",
|
|
72
|
+
"flag-selector": "--menu-selector",
|
|
73
|
+
options: {
|
|
74
|
+
Build: {
|
|
75
|
+
selector: "build",
|
|
76
|
+
action: async () => {
|
|
77
|
+
await ctx.services.docker.build({
|
|
78
|
+
image: "registry/app:v1",
|
|
79
|
+
dockerfile: "Dockerfile"
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
Deploy: {
|
|
84
|
+
selector: "deploy",
|
|
85
|
+
action: async () => {
|
|
86
|
+
await ctx.services.kubectl.apply("deployment.yaml");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
Con esa definición, ambas formas funcionan:
|
|
93
|
+
|
|
94
|
+
catops-cli # menú interactivo
|
|
95
|
+
catops-cli --menu-selector=build # ejecuta "Build" directamente, sin prompts
|
|
96
|
+
|
|
97
|
+
Si "Deploy" fuera un submenú anidado con su propio "flag-selector", se puede
|
|
98
|
+
encadenar en un solo comando, por ejemplo:
|
|
99
|
+
|
|
100
|
+
catops-cli --menu-selector=deploy --deploy-target=staging
|
|
101
|
+
|
|
102
|
+
También puedes usar la librería directamente en tu código:
|
|
103
|
+
|
|
104
|
+
const { Context, Menu } = require("catops-cli");
|
|
105
|
+
import { Context, Menu } from "catops-cli"; // con tipados, en TS
|
|
106
|
+
`);
|
|
107
|
+
}
|
|
108
|
+
async function main() {
|
|
109
|
+
const configPath = findConfig();
|
|
110
|
+
if (!configPath) {
|
|
111
|
+
printHelp();
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
const ctx = Context_1.Context.parseArgv();
|
|
115
|
+
if (ctx.hasFlag("help") || ctx.hasFlag("h")) {
|
|
116
|
+
printHelp();
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
|
|
120
|
+
const definitionFactory = require(configPath);
|
|
121
|
+
const definition = typeof definitionFactory === "function"
|
|
122
|
+
? await definitionFactory(ctx)
|
|
123
|
+
: definitionFactory;
|
|
124
|
+
logger_1.logger.info(`Usando configuración: ${path.relative(process.cwd(), configPath)}`);
|
|
125
|
+
await Menu_1.Menu.render(definition, ctx);
|
|
126
|
+
}
|
|
127
|
+
main().catch(error => {
|
|
128
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
129
|
+
logger_1.logger.error(message);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=devops-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devops-cli.js","sourceRoot":"","sources":["../../src/bin/devops-cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,2CAA6B;AAC7B,uCAAyB;AACzB,6CAA0C;AAC1C,uCAAoC;AACpC,2CAAwC;AAGxC,MAAM,iBAAiB,GAAG;IACtB,oBAAoB;IACpB,kBAAkB;IAClB,gBAAgB;CACnB,CAAC;AAEF,SAAS,UAAU;IAEf,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAEtC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,OAAO,QAAQ,CAAC;QACpB,CAAC;IAEL,CAAC;IAED,OAAO,IAAI,CAAC;AAEhB,CAAC;AAED,SAAS,SAAS;IAEd,OAAO,CAAC,GAAG,CAAC;;;;;;;IAOZ,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCjC,CAAC,CAAC;AAEH,CAAC;AAMD,KAAK,UAAU,IAAI;IAEf,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;IAEhC,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,GAAG,GAAG,iBAAO,CAAC,SAAS,EAAE,CAAC;IAEhC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,8EAA8E;IAC9E,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAoC,CAAC;IAEjF,MAAM,UAAU,GAAG,OAAO,iBAAiB,KAAK,UAAU;QACtD,CAAC,CAAC,MAAM,iBAAiB,CAAC,GAAG,CAAC;QAC9B,CAAC,CAAC,iBAAiB,CAAC;IAExB,eAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;IAEjF,MAAM,WAAI,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AAEvC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;IACjB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,eAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type Logger } from "./logger";
|
|
2
|
+
import { type ServicesRegistry } from "../services";
|
|
3
|
+
import { Notifier } from "./Notifier";
|
|
4
|
+
import type { AskOptions, ConfirmOptions, SelectChoices } from "./prompt";
|
|
5
|
+
import type { TaskHooks } from "./types";
|
|
6
|
+
export type FlagValue = boolean | string;
|
|
7
|
+
export declare class Context {
|
|
8
|
+
private static instance;
|
|
9
|
+
flags: Record<string, FlagValue>;
|
|
10
|
+
params: Record<string, string>;
|
|
11
|
+
env: NodeJS.ProcessEnv;
|
|
12
|
+
vars: Record<string, unknown>;
|
|
13
|
+
results: Record<string, unknown>;
|
|
14
|
+
logger: Logger;
|
|
15
|
+
services: ServicesRegistry;
|
|
16
|
+
notifier: Notifier;
|
|
17
|
+
config: Record<string, unknown>;
|
|
18
|
+
state: Record<string, unknown>;
|
|
19
|
+
static current(): Context;
|
|
20
|
+
/** Reinicia el singleton. Útil sobre todo en tests. */
|
|
21
|
+
static reset(): Context;
|
|
22
|
+
setFlag(name: string, value?: FlagValue): this;
|
|
23
|
+
getFlag(name: string): FlagValue | undefined;
|
|
24
|
+
hasFlag(name: string): boolean;
|
|
25
|
+
set<T = unknown>(name: string, value: T): this;
|
|
26
|
+
get<T = unknown>(name: string): T | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Ejecuta una task, guarda su resultado en `ctx.results[taskId]`, y
|
|
29
|
+
* dispara los callbacks de éxito/error correspondientes:
|
|
30
|
+
* 1. `hooks.onSuccess` / `hooks.onError` (si los pasaste), y
|
|
31
|
+
* 2. el `notifier` global (clasifica el error por área de TI y
|
|
32
|
+
* lo reporta a los canales registrados con `ctx.notifier.channel(...)`).
|
|
33
|
+
*
|
|
34
|
+
* Si la task lanza, el error se re-lanza después de notificar, para no
|
|
35
|
+
* esconder fallas silenciosamente.
|
|
36
|
+
*/
|
|
37
|
+
run<T>(taskId: string, callback: (ctx: Context) => Promise<T> | T, hooks?: TaskHooks<T>): Promise<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Envuelve un objeto de servicio (o cualquier objeto con métodos) en un
|
|
40
|
+
* Proxy que intercepta cada llamada a método. Si el método lanza un error,
|
|
41
|
+
* lo envuelve en un `ServiceError` con metadata del servicio (nombre,
|
|
42
|
+
* método, argumentos) y lo despacha al notifier antes de re-lanzarlo.
|
|
43
|
+
*
|
|
44
|
+
* Ejemplo:
|
|
45
|
+
* const docker = ctx.wrap(ctx.services.docker, "docker");
|
|
46
|
+
* await docker.push("myimage:latest");
|
|
47
|
+
* // Si falla, el notifier recibe:
|
|
48
|
+
* // taskId: 'docker.push("myimage:latest")'
|
|
49
|
+
* // error: ServiceError { service: "docker", method: "push", args: [...], cause: ExecResult }
|
|
50
|
+
*/
|
|
51
|
+
wrap<T extends Record<string, (...args: any[]) => any>>(service: T, serviceName: string): T;
|
|
52
|
+
ask(question: string, options?: AskOptions): Promise<string | undefined>;
|
|
53
|
+
confirm(question: string, options?: ConfirmOptions): Promise<boolean>;
|
|
54
|
+
select(title: string, choices: SelectChoices): Promise<string>;
|
|
55
|
+
static parseArgv(argv?: string[]): Context;
|
|
56
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Context = void 0;
|
|
37
|
+
const logger_1 = require("./logger");
|
|
38
|
+
const prompt = __importStar(require("./prompt"));
|
|
39
|
+
const services_1 = require("../services");
|
|
40
|
+
const Notifier_1 = require("./Notifier");
|
|
41
|
+
const types_1 = require("./types");
|
|
42
|
+
class Context {
|
|
43
|
+
constructor() {
|
|
44
|
+
this.flags = {};
|
|
45
|
+
this.params = {};
|
|
46
|
+
this.env = { ...process.env };
|
|
47
|
+
this.vars = {};
|
|
48
|
+
this.results = {};
|
|
49
|
+
this.logger = logger_1.logger;
|
|
50
|
+
this.services = services_1.services;
|
|
51
|
+
this.notifier = new Notifier_1.Notifier();
|
|
52
|
+
this.config = {};
|
|
53
|
+
this.state = {};
|
|
54
|
+
}
|
|
55
|
+
static current() {
|
|
56
|
+
if (!Context.instance) {
|
|
57
|
+
Context.instance = new Context();
|
|
58
|
+
}
|
|
59
|
+
return Context.instance;
|
|
60
|
+
}
|
|
61
|
+
/** Reinicia el singleton. Útil sobre todo en tests. */
|
|
62
|
+
static reset() {
|
|
63
|
+
Context.instance = new Context();
|
|
64
|
+
return Context.instance;
|
|
65
|
+
}
|
|
66
|
+
// ---- flags ----
|
|
67
|
+
setFlag(name, value = true) {
|
|
68
|
+
this.flags[name] = value;
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
getFlag(name) {
|
|
72
|
+
return this.flags[name];
|
|
73
|
+
}
|
|
74
|
+
hasFlag(name) {
|
|
75
|
+
return Boolean(this.flags[name]);
|
|
76
|
+
}
|
|
77
|
+
// ---- vars ----
|
|
78
|
+
set(name, value) {
|
|
79
|
+
this.vars[name] = value;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
get(name) {
|
|
83
|
+
return this.vars[name];
|
|
84
|
+
}
|
|
85
|
+
// ---- results del pipe ----
|
|
86
|
+
/**
|
|
87
|
+
* Ejecuta una task, guarda su resultado en `ctx.results[taskId]`, y
|
|
88
|
+
* dispara los callbacks de éxito/error correspondientes:
|
|
89
|
+
* 1. `hooks.onSuccess` / `hooks.onError` (si los pasaste), y
|
|
90
|
+
* 2. el `notifier` global (clasifica el error por área de TI y
|
|
91
|
+
* lo reporta a los canales registrados con `ctx.notifier.channel(...)`).
|
|
92
|
+
*
|
|
93
|
+
* Si la task lanza, el error se re-lanza después de notificar, para no
|
|
94
|
+
* esconder fallas silenciosamente.
|
|
95
|
+
*/
|
|
96
|
+
async run(taskId, callback, hooks = {}) {
|
|
97
|
+
try {
|
|
98
|
+
const value = await callback(this);
|
|
99
|
+
this.results[taskId] = value;
|
|
100
|
+
await hooks.onSuccess?.(value, this);
|
|
101
|
+
await this.notifier.reportSuccess(taskId, value, this);
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
await hooks.onError?.(error, this);
|
|
106
|
+
await this.notifier.reportError(taskId, error, this);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Envuelve un objeto de servicio (o cualquier objeto con métodos) en un
|
|
112
|
+
* Proxy que intercepta cada llamada a método. Si el método lanza un error,
|
|
113
|
+
* lo envuelve en un `ServiceError` con metadata del servicio (nombre,
|
|
114
|
+
* método, argumentos) y lo despacha al notifier antes de re-lanzarlo.
|
|
115
|
+
*
|
|
116
|
+
* Ejemplo:
|
|
117
|
+
* const docker = ctx.wrap(ctx.services.docker, "docker");
|
|
118
|
+
* await docker.push("myimage:latest");
|
|
119
|
+
* // Si falla, el notifier recibe:
|
|
120
|
+
* // taskId: 'docker.push("myimage:latest")'
|
|
121
|
+
* // error: ServiceError { service: "docker", method: "push", args: [...], cause: ExecResult }
|
|
122
|
+
*/
|
|
123
|
+
wrap(service, serviceName) {
|
|
124
|
+
const ctx = this;
|
|
125
|
+
return new Proxy(service, {
|
|
126
|
+
get(target, prop, receiver) {
|
|
127
|
+
const original = Reflect.get(target, prop, receiver);
|
|
128
|
+
if (typeof original !== "function")
|
|
129
|
+
return original;
|
|
130
|
+
return async function (...args) {
|
|
131
|
+
try {
|
|
132
|
+
return await original.apply(target, args);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
const methodName = String(prop);
|
|
136
|
+
const serializedArgs = args.map(a => {
|
|
137
|
+
try {
|
|
138
|
+
return JSON.stringify(a);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return String(a);
|
|
142
|
+
}
|
|
143
|
+
}).join(", ");
|
|
144
|
+
const taskId = `${serviceName}.${methodName}(${serializedArgs})`;
|
|
145
|
+
const wrapped = new types_1.ServiceError(serviceName, methodName, args, error);
|
|
146
|
+
await ctx.notifier.reportError(taskId, wrapped, ctx);
|
|
147
|
+
throw wrapped;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// ---- prompts ----
|
|
154
|
+
async ask(question, options) {
|
|
155
|
+
return prompt.ask(question, options);
|
|
156
|
+
}
|
|
157
|
+
async confirm(question, options) {
|
|
158
|
+
return prompt.confirm(question, options);
|
|
159
|
+
}
|
|
160
|
+
async select(title, choices) {
|
|
161
|
+
return prompt.select(title, choices);
|
|
162
|
+
}
|
|
163
|
+
// ---- inicialización desde argv ----
|
|
164
|
+
static parseArgv(argv = process.argv.slice(2)) {
|
|
165
|
+
const ctx = Context.current();
|
|
166
|
+
argv.forEach(arg => {
|
|
167
|
+
if (arg.startsWith("--")) {
|
|
168
|
+
const [key, value] = arg.slice(2).split("=");
|
|
169
|
+
if (value === undefined) {
|
|
170
|
+
ctx.setFlag(key, true);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
ctx.params[key] = value;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
// Flags globales que reconfiguran shell.exec para todo el proceso,
|
|
178
|
+
// sin que ninguna task tenga que pasarlos manualmente.
|
|
179
|
+
const shellOptions = {};
|
|
180
|
+
if (ctx.hasFlag("dry-run") || ctx.hasFlag("dryRun")) {
|
|
181
|
+
shellOptions.dryRun = true;
|
|
182
|
+
}
|
|
183
|
+
if (ctx.params.retry !== undefined) {
|
|
184
|
+
shellOptions.retry = parseInt(ctx.params.retry, 10);
|
|
185
|
+
}
|
|
186
|
+
if (ctx.params.timeout !== undefined) {
|
|
187
|
+
shellOptions.timeout = parseInt(ctx.params.timeout, 10);
|
|
188
|
+
}
|
|
189
|
+
if (Object.keys(shellOptions).length) {
|
|
190
|
+
ctx.services.shell.configure(shellOptions);
|
|
191
|
+
}
|
|
192
|
+
return ctx;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.Context = Context;
|
|
196
|
+
Context.instance = null;
|
|
197
|
+
//# sourceMappingURL=Context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Context.js","sourceRoot":"","sources":["../../src/core/Context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Context } from "./Context";
|
|
2
|
+
import type { MenuDefinition } from "./types";
|
|
3
|
+
export declare const EXIT: unique symbol;
|
|
4
|
+
export declare class Menu {
|
|
5
|
+
static readonly EXIT: symbol;
|
|
6
|
+
/**
|
|
7
|
+
* Ejecuta un item ya resuelto: si es una task, la corre, guarda su
|
|
8
|
+
* resultado en `ctx.results[label]`, dispara `onSuccess`/`onError`
|
|
9
|
+
* propios del item (si se pasaron) y reporta el resultado al
|
|
10
|
+
* `ctx.notifier` (clasificación por área de TI + canales). Si es un
|
|
11
|
+
* submenú, simplemente lo renderiza (y así hereda su propio manejo de
|
|
12
|
+
* flag-selector/hooks).
|
|
13
|
+
*/
|
|
14
|
+
private static executeEntry;
|
|
15
|
+
/**
|
|
16
|
+
* Renderiza un menú. Si `definition["flag-selector"]` está presente y el
|
|
17
|
+
* Context trae un param que matchea el `selector` de alguno de los
|
|
18
|
+
* items, esa opción se ejecuta automáticamente sin pedir input al
|
|
19
|
+
* usuario (y, si es un submenú, este a su vez revisa su propio
|
|
20
|
+
* "flag-selector", permitiendo encadenar varios niveles).
|
|
21
|
+
*/
|
|
22
|
+
static render(definition: MenuDefinition, ctx?: Context): Promise<typeof EXIT | void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Menu = exports.EXIT = void 0;
|
|
37
|
+
const prompt = __importStar(require("./prompt"));
|
|
38
|
+
const logger_1 = require("./logger");
|
|
39
|
+
const Context_1 = require("./Context");
|
|
40
|
+
exports.EXIT = Symbol("exit");
|
|
41
|
+
function isMenuDefinition(value) {
|
|
42
|
+
return Boolean(value)
|
|
43
|
+
&& typeof value === "object"
|
|
44
|
+
&& "title" in value
|
|
45
|
+
&& "options" in value;
|
|
46
|
+
}
|
|
47
|
+
function resolveEntry(value) {
|
|
48
|
+
if (typeof value === "function") {
|
|
49
|
+
return { kind: "task", run: value };
|
|
50
|
+
}
|
|
51
|
+
if (isMenuDefinition(value)) {
|
|
52
|
+
return { kind: "menu", menu: value };
|
|
53
|
+
}
|
|
54
|
+
if (value && typeof value === "object") {
|
|
55
|
+
const wrapped = value;
|
|
56
|
+
if (wrapped.menu) {
|
|
57
|
+
return { kind: "menu", menu: wrapped.menu, selector: wrapped.selector };
|
|
58
|
+
}
|
|
59
|
+
if (typeof wrapped.action === "function") {
|
|
60
|
+
return {
|
|
61
|
+
kind: "task",
|
|
62
|
+
run: wrapped.action,
|
|
63
|
+
selector: wrapped.selector,
|
|
64
|
+
onSuccess: wrapped.onSuccess,
|
|
65
|
+
onError: wrapped.onError
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`Item de menú inválido: ${JSON.stringify(value)}`);
|
|
70
|
+
}
|
|
71
|
+
function normalizeFlagName(flagSelector) {
|
|
72
|
+
return flagSelector.replace(/^--?/, "");
|
|
73
|
+
}
|
|
74
|
+
function errorMessage(error) {
|
|
75
|
+
if (error instanceof Error)
|
|
76
|
+
return error.message;
|
|
77
|
+
const execError = error;
|
|
78
|
+
return execError?.stderr ?? execError?.stdout ?? String(error);
|
|
79
|
+
}
|
|
80
|
+
class Menu {
|
|
81
|
+
/**
|
|
82
|
+
* Ejecuta un item ya resuelto: si es una task, la corre, guarda su
|
|
83
|
+
* resultado en `ctx.results[label]`, dispara `onSuccess`/`onError`
|
|
84
|
+
* propios del item (si se pasaron) y reporta el resultado al
|
|
85
|
+
* `ctx.notifier` (clasificación por área de TI + canales). Si es un
|
|
86
|
+
* submenú, simplemente lo renderiza (y así hereda su propio manejo de
|
|
87
|
+
* flag-selector/hooks).
|
|
88
|
+
*/
|
|
89
|
+
static async executeEntry(entry, label, ctx) {
|
|
90
|
+
if (entry.kind === "menu" && entry.menu) {
|
|
91
|
+
return Menu.render(entry.menu, ctx);
|
|
92
|
+
}
|
|
93
|
+
if (entry.kind === "task" && entry.run) {
|
|
94
|
+
try {
|
|
95
|
+
const result = await entry.run(ctx);
|
|
96
|
+
ctx.results[label] = result;
|
|
97
|
+
await entry.onSuccess?.(result, ctx);
|
|
98
|
+
await ctx.notifier.reportSuccess(label, result, ctx);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
await entry.onError?.(error, ctx);
|
|
102
|
+
await ctx.notifier.reportError(label, error, ctx);
|
|
103
|
+
logger_1.logger.error(errorMessage(error));
|
|
104
|
+
if (ctx.params.catch === "throw" || ctx.flags.catch === "throw")
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
logger_1.logger.warn(`Opción "${label}" no tiene acción definida.`);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Renderiza un menú. Si `definition["flag-selector"]` está presente y el
|
|
113
|
+
* Context trae un param que matchea el `selector` de alguno de los
|
|
114
|
+
* items, esa opción se ejecuta automáticamente sin pedir input al
|
|
115
|
+
* usuario (y, si es un submenú, este a su vez revisa su propio
|
|
116
|
+
* "flag-selector", permitiendo encadenar varios niveles).
|
|
117
|
+
*/
|
|
118
|
+
static async render(definition, ctx) {
|
|
119
|
+
const activeCtx = ctx ?? Context_1.Context.current();
|
|
120
|
+
const { title, options } = definition;
|
|
121
|
+
const flagSelector = definition["flag-selector"];
|
|
122
|
+
if (flagSelector) {
|
|
123
|
+
const flagKey = normalizeFlagName(flagSelector);
|
|
124
|
+
const wantedValue = activeCtx.params[flagKey];
|
|
125
|
+
if (wantedValue !== undefined) {
|
|
126
|
+
const match = Object.entries(options).find(([, value]) => {
|
|
127
|
+
try {
|
|
128
|
+
return resolveEntry(value).selector === wantedValue;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
if (match) {
|
|
135
|
+
const [label, value] = match;
|
|
136
|
+
const entry = resolveEntry(value);
|
|
137
|
+
logger_1.logger.info(`Selector automático: "${label}" (${flagSelector}=${wantedValue})`);
|
|
138
|
+
return Menu.executeEntry(entry, label, activeCtx);
|
|
139
|
+
}
|
|
140
|
+
logger_1.logger.warn(`Ningún item de "${title}" coincide con ${flagSelector}=${wantedValue}; se muestra el menú interactivo.`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const labels = Object.keys(options);
|
|
144
|
+
labels.push("Salir");
|
|
145
|
+
while (true) {
|
|
146
|
+
const choiceKey = await prompt.select(title, labels);
|
|
147
|
+
const label = labels[Number(choiceKey)];
|
|
148
|
+
if (label === "Salir") {
|
|
149
|
+
return exports.EXIT;
|
|
150
|
+
}
|
|
151
|
+
const entry = resolveEntry(options[label]);
|
|
152
|
+
const result = await Menu.executeEntry(entry, label, activeCtx);
|
|
153
|
+
if (result === exports.EXIT)
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.Menu = Menu;
|
|
159
|
+
Menu.EXIT = exports.EXIT;
|
|
160
|
+
//# sourceMappingURL=Menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Menu.js","sourceRoot":"","sources":["../../src/core/Menu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Context } from "./Context";
|
|
2
|
+
import type { ErrorClassifier, ErrorMessageFormatter, Sender } from "./types";
|
|
3
|
+
export declare class Notifier {
|
|
4
|
+
private classifiers;
|
|
5
|
+
private messageFormatters;
|
|
6
|
+
private channels;
|
|
7
|
+
private successSenders;
|
|
8
|
+
private defaultArea;
|
|
9
|
+
/**
|
|
10
|
+
* Registra una función que decide a qué área de TI corresponde un
|
|
11
|
+
* error. Se prueban en el orden en que se registraron; gana la primera
|
|
12
|
+
* que devuelva un string. Si ninguna matchea, se usa el área "unclassified"
|
|
13
|
+
* (configurable con `setDefaultArea`).
|
|
14
|
+
*/
|
|
15
|
+
classify(classifier: ErrorClassifier): this;
|
|
16
|
+
/**
|
|
17
|
+
* Registra una función que, dado el error, devuelve el mensaje
|
|
18
|
+
* personalizado a reportar (reemplaza el stderr/mensaje crudo). Se
|
|
19
|
+
* prueban en orden; gana la primera que devuelva un string. Si ninguna
|
|
20
|
+
* matchea, se usa el mensaje crudo del error (stderr/Error.message).
|
|
21
|
+
*
|
|
22
|
+
* Ejemplo:
|
|
23
|
+
* notifier.describeError(messages.byPattern([
|
|
24
|
+
* [/500 Internal Server Error/, "Se reportó a infraestructura: falta de espacio en el registry"],
|
|
25
|
+
* [/unauthorized|403/, "Credenciales inválidas contra el registry, revisa el secret"]
|
|
26
|
+
* ]));
|
|
27
|
+
*/
|
|
28
|
+
describeError(formatter: ErrorMessageFormatter): this;
|
|
29
|
+
setDefaultArea(area: string): this;
|
|
30
|
+
/**
|
|
31
|
+
* Asocia uno o más senders a un área. Puedes registrar el mismo sender
|
|
32
|
+
* en varias áreas, o usar el área especial "*" para que reciba TODOS
|
|
33
|
+
* los errores sin importar la clasificación.
|
|
34
|
+
*/
|
|
35
|
+
channel(area: string, ...senders: Sender[]): this;
|
|
36
|
+
/** Senders que se disparan en cada tarea exitosa, sin clasificación. */
|
|
37
|
+
onSuccess(...senders: Sender[]): this;
|
|
38
|
+
private resolveArea;
|
|
39
|
+
private resolveMessage;
|
|
40
|
+
reportSuccess(taskId: string, result: unknown, ctx: Context): Promise<void>;
|
|
41
|
+
reportError(taskId: string, error: unknown, ctx: Context): Promise<string>;
|
|
42
|
+
}
|