@neetru/cli 2.3.0 → 2.5.0
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/dist/commands/artifact-registry.d.ts +7 -0
- package/dist/commands/artifact-registry.js +60 -0
- package/dist/commands/artifact-registry.js.map +1 -0
- package/dist/commands/deploy.js +8 -8
- package/dist/commands/deployments.d.ts +5 -5
- package/dist/commands/deployments.js +32 -6
- package/dist/commands/deployments.js.map +1 -1
- package/dist/commands/env.d.ts +11 -0
- package/dist/commands/env.js +91 -0
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/hosting-write.d.ts +6 -0
- package/dist/commands/hosting-write.js +52 -0
- package/dist/commands/hosting-write.js.map +1 -0
- package/dist/commands/products-db.d.ts +9 -9
- package/dist/commands/products-db.js +84 -19
- package/dist/commands/products-db.js.map +1 -1
- package/dist/commands/products.d.ts +2 -2
- package/dist/commands/products.js +8 -6
- package/dist/commands/products.js.map +1 -1
- package/dist/commands/schema.d.ts +25 -0
- package/dist/commands/schema.js +321 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/servers.d.ts +5 -5
- package/dist/commands/servers.js +25 -17
- package/dist/commands/servers.js.map +1 -1
- package/dist/commands/status.js +3 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/tenants.d.ts +14 -14
- package/dist/commands/tenants.js +62 -30
- package/dist/commands/tenants.js.map +1 -1
- package/dist/commands/ui.d.ts +1 -0
- package/dist/commands/ui.js +454 -0
- package/dist/commands/ui.js.map +1 -0
- package/dist/commands/workspaces.d.ts +9 -9
- package/dist/commands/workspaces.js +66 -31
- package/dist/commands/workspaces.js.map +1 -1
- package/dist/index.js +164 -65
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/orchestrator.js +46 -23
- package/dist/lib/ai/orchestrator.js.map +1 -1
- package/dist/lib/config-schema.d.ts +18 -18
- package/dist/lib/pickers.d.ts +123 -0
- package/dist/lib/pickers.js +336 -0
- package/dist/lib/pickers.js.map +1 -0
- package/dist/lib/schema-cache.d.ts +87 -0
- package/dist/lib/schema-cache.js +134 -0
- package/dist/lib/schema-cache.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type StepUpOptions } from '../lib/cli-write.js';
|
|
2
|
+
export interface ArtifactRegistryCreateOptions extends StepUpOptions {
|
|
3
|
+
location?: string;
|
|
4
|
+
format?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function runArtifactRegistryCreate(name: string, opts: ArtifactRegistryCreateOptions): Promise<void>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neetru artifact-registry create <name>` — cria repositório no Artifact Registry.
|
|
3
|
+
*
|
|
4
|
+
* Use case típico: setup one-shot por produto SaaS antes do primeiro deploy.
|
|
5
|
+
* Após criado, `docker push <location>-docker.pkg.dev/neetru/<name>/<image>:<tag>`
|
|
6
|
+
* passa a funcionar.
|
|
7
|
+
*
|
|
8
|
+
* Endpoint: POST /api/cli/v1/artifact-registry
|
|
9
|
+
* body: { name, location, format?, description? }
|
|
10
|
+
*
|
|
11
|
+
* Não exige step-up MFA (criação não-destrutiva). Admin only.
|
|
12
|
+
*/
|
|
13
|
+
import ora from 'ora';
|
|
14
|
+
import { apiRequest } from '../lib/api-client.js';
|
|
15
|
+
import { requireToken, handleApiError, printWriteResult, } from '../lib/cli-write.js';
|
|
16
|
+
import { log } from '../utils/logger.js';
|
|
17
|
+
export async function runArtifactRegistryCreate(name, opts) {
|
|
18
|
+
if (!name) {
|
|
19
|
+
log.error('Uso: neetru artifact-registry create <name> [--location=us-central1] [--format=DOCKER]');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const location = opts.location ?? 'us-central1';
|
|
23
|
+
const format = (opts.format ?? 'DOCKER').toUpperCase();
|
|
24
|
+
const token = await requireToken(opts.json);
|
|
25
|
+
const spinner = opts.json
|
|
26
|
+
? null
|
|
27
|
+
: ora({
|
|
28
|
+
text: `Criando repositório ${name} em ${location} (${format})…`,
|
|
29
|
+
color: 'blue',
|
|
30
|
+
}).start();
|
|
31
|
+
const path = `/api/cli/v1/artifact-registry${opts.dryRun ? '?dryRun=true' : ''}`;
|
|
32
|
+
let res;
|
|
33
|
+
try {
|
|
34
|
+
res = await apiRequest(path, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
token,
|
|
37
|
+
body: { name, location, format, description: opts.description },
|
|
38
|
+
});
|
|
39
|
+
spinner?.stop();
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
spinner?.fail('Falha ao criar repositório.');
|
|
43
|
+
handleApiError(error, opts.json);
|
|
44
|
+
}
|
|
45
|
+
const humanMessage = res.done
|
|
46
|
+
? `Repositório ${res.name} criado em ${res.location}. Push: ${res.pushExample}`
|
|
47
|
+
: `Criação iniciada — operação ${res.operationName ?? '(?)'} ainda em andamento. Confirme via Console ou aguarde uns segundos antes do primeiro push.`;
|
|
48
|
+
printWriteResult(res.dryRun
|
|
49
|
+
? res
|
|
50
|
+
: {
|
|
51
|
+
name: res.name,
|
|
52
|
+
location: res.location,
|
|
53
|
+
format: res.format,
|
|
54
|
+
done: res.done,
|
|
55
|
+
operationName: res.operationName,
|
|
56
|
+
dockerHost: res.dockerHost,
|
|
57
|
+
pushExample: res.pushExample,
|
|
58
|
+
}, humanMessage, opts.json);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=artifact-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-registry.js","sourceRoot":"","sources":["../../src/commands/artifact-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAQzC,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,IAAY,EACZ,IAAmC;IAEnC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,GAAG,CAAC,KAAK,CAAC,wFAAwF,CAAC,CAAC;QACpG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,aAAa,CAAC;IAChD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAEvD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI;QACvB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,CAAC;YACF,IAAI,EAAE,uBAAuB,IAAI,OAAO,QAAQ,KAAK,MAAM,IAAI;YAC/D,KAAK,EAAE,MAAM;SACd,CAAC,CAAC,KAAK,EAAE,CAAC;IAEf,MAAM,IAAI,GAAG,gCAAgC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAEjF,IAAI,GAWH,CAAC;IACF,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,KAAK;YACL,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;SAChE,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC7C,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI;QAC3B,CAAC,CAAC,eAAe,GAAG,CAAC,IAAI,cAAc,GAAG,CAAC,QAAQ,WAAW,GAAG,CAAC,WAAW,EAAE;QAC/E,CAAC,CAAC,+BAA+B,GAAG,CAAC,aAAa,IAAI,KAAK,2FAA2F,CAAC;IAEzJ,gBAAgB,CACd,GAAG,CAAC,MAAM;QACR,CAAC,CAAC,GAAG;QACL,CAAC,CAAC;YACE,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,aAAa,EAAE,GAAG,CAAC,aAAa;YAChC,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,EACL,YAAY,EACZ,IAAI,CAAC,IAAI,CACV,CAAC;AACJ,CAAC"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
* `neetru deploy` — pipeline interativo de deploy do produto.
|
|
3
3
|
*
|
|
4
4
|
* Sprint 3 (P1-1): substitui o stub vazio. Fluxo:
|
|
5
|
-
* 1. Resolve produto (lista via /api/v1/
|
|
5
|
+
* 1. Resolve produto (lista via /api/cli/v1/catalog).
|
|
6
6
|
* 2. Detecta stack (product_config + fallback local).
|
|
7
7
|
* 3. Escolhe target (cloud-run | vm-existente | provisionar-nova).
|
|
8
|
-
* 4. Para target=vm: lista servers online (/api/v1/
|
|
8
|
+
* 4. Para target=vm: lista servers online (/api/cli/v1/servers) +
|
|
9
9
|
* escolha capacity-aware.
|
|
10
10
|
* 5. Domínio + porta (auto-detect ou input).
|
|
11
11
|
* 6. Build (chama runBuild se artifact ausente).
|
|
12
12
|
* 7. Upload artifact (Sprint 1: usa file:// local — owner roda em VM com
|
|
13
13
|
* acesso ao mesmo FS, OU define `NEETRU_ARTIFACT_BUCKET` e o CLI faz
|
|
14
14
|
* upload via signed URL — Sprint 2.5).
|
|
15
|
-
* 8. POST /api/v1/
|
|
16
|
-
* 9. Polling /api/v1/
|
|
15
|
+
* 8. POST /api/cli/v1/deploy → recebe deploymentId + statusUrl.
|
|
16
|
+
* 9. Polling /api/cli/v1/deploy/status até estado terminal.
|
|
17
17
|
*
|
|
18
18
|
* NÃO bloqueia em modo `--non-interactive` quando flags suficientes vieram.
|
|
19
19
|
*/
|
|
@@ -113,7 +113,7 @@ async function pickProduct(opts, nonInteractive, cwd) {
|
|
|
113
113
|
const spinner = ora({ text: 'Buscando catálogo…', color: 'blue' }).start();
|
|
114
114
|
let catalog;
|
|
115
115
|
try {
|
|
116
|
-
catalog = await apiRequest('/api/v1/
|
|
116
|
+
catalog = await apiRequest('/api/cli/v1/catalog');
|
|
117
117
|
spinner.stop();
|
|
118
118
|
}
|
|
119
119
|
catch (err) {
|
|
@@ -172,7 +172,7 @@ async function pickServer(opts, nonInteractive) {
|
|
|
172
172
|
}
|
|
173
173
|
if (resp.servers.length === 0) {
|
|
174
174
|
log.error('Nenhum servidor online encontrado.');
|
|
175
|
-
log.dim(' Provisione um com: POST /api/v1/
|
|
175
|
+
log.dim(' Provisione um com: POST /api/cli/v1/servers/provision');
|
|
176
176
|
process.exit(1);
|
|
177
177
|
}
|
|
178
178
|
if (opts.server) {
|
|
@@ -433,7 +433,7 @@ async function pollDeploymentStatus(deploymentId) {
|
|
|
433
433
|
while (Date.now() - start < timeoutMs) {
|
|
434
434
|
let resp;
|
|
435
435
|
try {
|
|
436
|
-
resp = await apiRequest(`/api/v1/
|
|
436
|
+
resp = await apiRequest(`/api/cli/v1/deploy/status?id=${encodeURIComponent(deploymentId)}`);
|
|
437
437
|
}
|
|
438
438
|
catch (err) {
|
|
439
439
|
// transient — segue tentando.
|
|
@@ -527,7 +527,7 @@ export async function runDeploy(opts) {
|
|
|
527
527
|
let deploy;
|
|
528
528
|
const dispatchSpinner = ora({ text: 'Enviando comando ao Core…', color: 'blue' }).start();
|
|
529
529
|
try {
|
|
530
|
-
deploy = await apiRequest('/api/v1/
|
|
530
|
+
deploy = await apiRequest('/api/cli/v1/deploy', {
|
|
531
531
|
method: 'POST',
|
|
532
532
|
body,
|
|
533
533
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type StepUpOptions } from '../lib/cli-write.js';
|
|
2
2
|
export interface DeploymentsCreateOptions {
|
|
3
|
-
product
|
|
4
|
-
tenant
|
|
5
|
-
version
|
|
6
|
-
env
|
|
7
|
-
server
|
|
3
|
+
product?: string;
|
|
4
|
+
tenant?: string;
|
|
5
|
+
version?: string;
|
|
6
|
+
env?: string;
|
|
7
|
+
server?: string;
|
|
8
8
|
json?: boolean;
|
|
9
9
|
}
|
|
10
10
|
export declare function runDeploymentsCreate(opts: DeploymentsCreateOptions): Promise<void>;
|
|
@@ -11,23 +11,49 @@
|
|
|
11
11
|
import ora from 'ora';
|
|
12
12
|
import { apiRequest } from '../lib/api-client.js';
|
|
13
13
|
import { requireToken, handleApiError, confirmDestructive, printWriteResult, resolveStepUp, } from '../lib/cli-write.js';
|
|
14
|
+
import { pickProductId, pickServer, pickTenant, promptChoice, promptText } from '../lib/pickers.js';
|
|
14
15
|
import { log } from '../utils/logger.js';
|
|
15
16
|
export async function runDeploymentsCreate(opts) {
|
|
16
17
|
const token = await requireToken(opts.json);
|
|
18
|
+
const product = await pickProductId(token, {
|
|
19
|
+
fromFlag: opts.product,
|
|
20
|
+
json: opts.json,
|
|
21
|
+
message: 'Produto do deployment:',
|
|
22
|
+
});
|
|
23
|
+
const tenant = await pickTenant(token, {
|
|
24
|
+
fromFlag: opts.tenant,
|
|
25
|
+
product,
|
|
26
|
+
json: opts.json,
|
|
27
|
+
message: 'Tenant alvo:',
|
|
28
|
+
});
|
|
29
|
+
const version = opts.version ?? (await promptText('Versao:', { json: opts.json }));
|
|
30
|
+
const env = opts.env ??
|
|
31
|
+
(await promptChoice('Ambiente:', [
|
|
32
|
+
{ name: 'dev', value: 'dev' },
|
|
33
|
+
{ name: 'staging', value: 'staging' },
|
|
34
|
+
{ name: 'prod', value: 'prod' },
|
|
35
|
+
], { default: 'dev', json: opts.json }));
|
|
36
|
+
const server = await pickServer(token, {
|
|
37
|
+
fromFlag: opts.server,
|
|
38
|
+
status: 'online',
|
|
39
|
+
capacity: true,
|
|
40
|
+
json: opts.json,
|
|
41
|
+
message: 'Server alvo:',
|
|
42
|
+
});
|
|
17
43
|
const spinner = opts.json
|
|
18
44
|
? null
|
|
19
|
-
: ora({ text: `Criando deployment ${
|
|
45
|
+
: ora({ text: `Criando deployment ${product}@${version}...`, color: 'blue' }).start();
|
|
20
46
|
let res;
|
|
21
47
|
try {
|
|
22
48
|
res = await apiRequest('/api/cli/v1/deployments', {
|
|
23
49
|
method: 'POST',
|
|
24
50
|
token,
|
|
25
51
|
body: {
|
|
26
|
-
productId:
|
|
27
|
-
tenantId:
|
|
28
|
-
version
|
|
29
|
-
environmentId:
|
|
30
|
-
serverId:
|
|
52
|
+
productId: product,
|
|
53
|
+
tenantId: tenant,
|
|
54
|
+
version,
|
|
55
|
+
environmentId: env,
|
|
56
|
+
serverId: server,
|
|
31
57
|
},
|
|
32
58
|
});
|
|
33
59
|
spinner?.stop();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployments.js","sourceRoot":"","sources":["../../src/commands/deployments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EACL,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GAEd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAWzC,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA8B;IAE9B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI;
|
|
1
|
+
{"version":3,"file":"deployments.js","sourceRoot":"","sources":["../../src/commands/deployments.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/env.d.ts
CHANGED
|
@@ -12,4 +12,15 @@ export interface EnvSwitchOptions {
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function applyEnvSwitch(content: string, value: EnvTarget): string;
|
|
14
14
|
export declare function runEnvSwitch(opts: EnvSwitchOptions): Promise<void>;
|
|
15
|
+
import { type StepUpOptions } from '../lib/cli-write.js';
|
|
16
|
+
export interface EnvSetOptions extends StepUpOptions {
|
|
17
|
+
service: string;
|
|
18
|
+
/** Repetível: --set KEY=VALUE */
|
|
19
|
+
set?: string[];
|
|
20
|
+
/** Repetível: --secret KEY=secretName[:version] */
|
|
21
|
+
secret?: string[];
|
|
22
|
+
/** Repetível: --unset KEY */
|
|
23
|
+
unset?: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare function runEnvSet(opts: EnvSetOptions): Promise<void>;
|
|
15
26
|
export {};
|
package/dist/commands/env.js
CHANGED
|
@@ -53,4 +53,95 @@ export async function runEnvSwitch(opts) {
|
|
|
53
53
|
await fs.writeFile(filePath, updated, 'utf-8');
|
|
54
54
|
log.success(`NEETRU_ENV=${target} (${file}).`);
|
|
55
55
|
}
|
|
56
|
+
// ─── neetru env set --service=X --key=Y --value=Z ──────────────────────────
|
|
57
|
+
//
|
|
58
|
+
// Mutação REMOTA: env vars de um serviço Cloud Run via control plane Core.
|
|
59
|
+
// Distinto do `env switch` (local .env.local). Operação merge — preserva vars
|
|
60
|
+
// existentes não-listadas em --unset. Suporta secretRefs apontando pra
|
|
61
|
+
// Secret Manager.
|
|
62
|
+
//
|
|
63
|
+
// Step-up MFA obrigatório (env vars contêm credenciais efetivas).
|
|
64
|
+
import ora from 'ora';
|
|
65
|
+
import { apiRequest } from '../lib/api-client.js';
|
|
66
|
+
import { requireToken, handleApiError, printWriteResult, resolveStepUp, } from '../lib/cli-write.js';
|
|
67
|
+
function parseKeyValue(pair) {
|
|
68
|
+
const idx = pair.indexOf('=');
|
|
69
|
+
if (idx < 1) {
|
|
70
|
+
throw new Error(`Formato inválido (esperado KEY=VALUE): ${pair}`);
|
|
71
|
+
}
|
|
72
|
+
const k = pair.slice(0, idx);
|
|
73
|
+
const v = pair.slice(idx + 1);
|
|
74
|
+
if (!k)
|
|
75
|
+
throw new Error(`KEY vazia em: ${pair}`);
|
|
76
|
+
return [k, v];
|
|
77
|
+
}
|
|
78
|
+
function parseSecretRef(pair) {
|
|
79
|
+
const [k, ref] = parseKeyValue(pair);
|
|
80
|
+
// ref pode ser "secretName" ou "secretName:version"
|
|
81
|
+
const colonIdx = ref.lastIndexOf(':');
|
|
82
|
+
if (colonIdx > 0) {
|
|
83
|
+
return [k, { secret: ref.slice(0, colonIdx), version: ref.slice(colonIdx + 1) }];
|
|
84
|
+
}
|
|
85
|
+
return [k, { secret: ref, version: 'latest' }];
|
|
86
|
+
}
|
|
87
|
+
export async function runEnvSet(opts) {
|
|
88
|
+
if (!opts.service) {
|
|
89
|
+
log.error('Uso: neetru env set --service=X [--set KEY=VAL] [--secret KEY=secretName[:version]] [--unset KEY]');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const envVars = {};
|
|
93
|
+
const secretRefs = {};
|
|
94
|
+
const unset = opts.unset ?? [];
|
|
95
|
+
try {
|
|
96
|
+
for (const pair of opts.set ?? []) {
|
|
97
|
+
const [k, v] = parseKeyValue(pair);
|
|
98
|
+
envVars[k] = v;
|
|
99
|
+
}
|
|
100
|
+
for (const pair of opts.secret ?? []) {
|
|
101
|
+
const [k, ref] = parseSecretRef(pair);
|
|
102
|
+
secretRefs[k] = ref;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
if (Object.keys(envVars).length === 0 &&
|
|
110
|
+
Object.keys(secretRefs).length === 0 &&
|
|
111
|
+
unset.length === 0) {
|
|
112
|
+
log.error('Nada para alterar — passe --set, --secret ou --unset.');
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
const token = await requireToken(opts.json);
|
|
116
|
+
const { headers } = await resolveStepUp(opts);
|
|
117
|
+
const spinner = opts.json
|
|
118
|
+
? null
|
|
119
|
+
: ora({
|
|
120
|
+
text: `Atualizando env vars em ${opts.service}…`,
|
|
121
|
+
color: 'blue',
|
|
122
|
+
}).start();
|
|
123
|
+
const path = `/api/cli/v1/cloud-run/${encodeURIComponent(opts.service)}/env${opts.dryRun ? '?dryRun=true' : ''}`;
|
|
124
|
+
let res;
|
|
125
|
+
try {
|
|
126
|
+
res = await apiRequest(path, {
|
|
127
|
+
method: 'POST',
|
|
128
|
+
token,
|
|
129
|
+
headers,
|
|
130
|
+
body: { envVars, secretRefs, unset },
|
|
131
|
+
});
|
|
132
|
+
spinner?.stop();
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
spinner?.fail('Falha ao atualizar env vars.');
|
|
136
|
+
handleApiError(error, opts.json);
|
|
137
|
+
}
|
|
138
|
+
const setSummary = [
|
|
139
|
+
Object.keys(envVars).length ? `${Object.keys(envVars).length} var(s)` : null,
|
|
140
|
+
Object.keys(secretRefs).length ? `${Object.keys(secretRefs).length} secret(s)` : null,
|
|
141
|
+
unset.length ? `${unset.length} removida(s)` : null,
|
|
142
|
+
]
|
|
143
|
+
.filter(Boolean)
|
|
144
|
+
.join(' · ');
|
|
145
|
+
printWriteResult(res.dryRun ? res : { service: res.service, totalEnvVars: res.totalEnvVars }, `Env vars atualizadas em ${res.service} (${setSummary}; total agora: ${res.totalEnvVars}).`, opts.json);
|
|
146
|
+
}
|
|
56
147
|
//# sourceMappingURL=env.js.map
|
package/dist/commands/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEzC,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,CAAU,CAAC;AAU9D,SAAS,WAAW,CAAC,CAAS;IAC5B,OAAQ,SAA+B,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,KAAgB;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,EAAE,CAAC;YACN,KAAK,GAAG,IAAI,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/D,GAAG,CAAC,IAAI,CAAC,cAAc,KAAK,EAAE,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAsB;IACvD,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,GAAG,YAAY,EAAE,GAAG,IAAI,CAAC;IAClE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,GAAG,CAAC,KAAK,CAAC,WAAW,MAAM,oBAAoB,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtC,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,GAAG,CAAC,OAAO,CAAC,cAAc,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC;AACjD,CAAC"}
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type StepUpOptions } from '../lib/cli-write.js';
|
|
2
|
+
export interface HostingCreateMappingOptions extends StepUpOptions {
|
|
3
|
+
service: string;
|
|
4
|
+
domain: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function runHostingCreateMapping(opts: HostingCreateMappingOptions): Promise<void>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neetru hosting create-mapping` — cria domain mapping pra Cloud Run.
|
|
3
|
+
*
|
|
4
|
+
* Endpoint: POST /api/cli/v1/hosting/mappings
|
|
5
|
+
* body: { service: string, domain: string }
|
|
6
|
+
*
|
|
7
|
+
* Step-up MFA: SIM (pode redirecionar tráfego público).
|
|
8
|
+
* Owner ainda precisa criar o CNAME no DNS provider externo.
|
|
9
|
+
*/
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { apiRequest } from '../lib/api-client.js';
|
|
12
|
+
import { requireToken, handleApiError, printWriteResult, resolveStepUp, } from '../lib/cli-write.js';
|
|
13
|
+
import { log } from '../utils/logger.js';
|
|
14
|
+
export async function runHostingCreateMapping(opts) {
|
|
15
|
+
if (!opts.service || !opts.domain) {
|
|
16
|
+
log.error('Uso: neetru hosting create-mapping --service=<service> --domain=<domain>');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const token = await requireToken(opts.json);
|
|
20
|
+
const { headers } = await resolveStepUp(opts);
|
|
21
|
+
const spinner = opts.json
|
|
22
|
+
? null
|
|
23
|
+
: ora({
|
|
24
|
+
text: `Criando mapping ${opts.domain} → ${opts.service}…`,
|
|
25
|
+
color: 'blue',
|
|
26
|
+
}).start();
|
|
27
|
+
const path = `/api/cli/v1/hosting/mappings${opts.dryRun ? '?dryRun=true' : ''}`;
|
|
28
|
+
let res;
|
|
29
|
+
try {
|
|
30
|
+
res = await apiRequest(path, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
token,
|
|
33
|
+
headers,
|
|
34
|
+
body: { service: opts.service, domain: opts.domain },
|
|
35
|
+
});
|
|
36
|
+
spinner?.stop();
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
spinner?.fail('Falha ao criar domain mapping.');
|
|
40
|
+
handleApiError(error, opts.json);
|
|
41
|
+
}
|
|
42
|
+
const verb = res.alreadyExisted ? 'já existia' : 'criado';
|
|
43
|
+
printWriteResult(res.dryRun
|
|
44
|
+
? res
|
|
45
|
+
: {
|
|
46
|
+
service: res.service,
|
|
47
|
+
domain: res.domain,
|
|
48
|
+
alreadyExisted: res.alreadyExisted,
|
|
49
|
+
hint: res.hint,
|
|
50
|
+
}, `Domain mapping ${verb}: ${res.domain} → ${res.service}. ${res.hint ?? ''}`.trim(), opts.json);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=hosting-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosting-write.js","sourceRoot":"","sources":["../../src/commands/hosting-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,GAEd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAOzC,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAAiC;IAEjC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAClC,GAAG,CAAC,KAAK,CAAC,0EAA0E,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IAE9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI;QACvB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,CAAC;YACF,IAAI,EAAE,mBAAmB,IAAI,CAAC,MAAM,MAAM,IAAI,CAAC,OAAO,GAAG;YACzD,KAAK,EAAE,MAAM;SACd,CAAC,CAAC,KAAK,EAAE,CAAC;IAEf,MAAM,IAAI,GAAG,+BAA+B,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAEhF,IAAI,GAQH,CAAC;IACF,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,KAAK;YACL,OAAO;YACP,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;SACrD,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAChD,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1D,gBAAgB,CACd,GAAG,CAAC,MAAM;QACR,CAAC,CAAC,GAAG;QACL,CAAC,CAAC;YACE,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,EACL,kBAAkB,IAAI,KAAK,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAClF,IAAI,CAAC,IAAI,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -6,30 +6,30 @@ export interface DbListOptions {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function runDbList(opts: DbListOptions): Promise<void>;
|
|
8
8
|
export interface DbCreateOptions {
|
|
9
|
-
productId
|
|
10
|
-
label
|
|
11
|
-
engine
|
|
12
|
-
|
|
9
|
+
productId?: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
engine?: string;
|
|
12
|
+
env?: string;
|
|
13
13
|
region: string;
|
|
14
14
|
serverId?: string;
|
|
15
15
|
replicaCount?: string;
|
|
16
16
|
json?: boolean;
|
|
17
17
|
}
|
|
18
18
|
export declare function runDbCreate(opts: DbCreateOptions): Promise<void>;
|
|
19
|
-
export declare function runDbGet(id: string, opts: {
|
|
19
|
+
export declare function runDbGet(id: string | undefined, opts: {
|
|
20
20
|
json?: boolean;
|
|
21
21
|
}): Promise<void>;
|
|
22
|
-
export declare function runDbStatus(id: string, status: string, opts: {
|
|
22
|
+
export declare function runDbStatus(id: string | undefined, status: string | undefined, opts: {
|
|
23
23
|
reason?: string;
|
|
24
24
|
json?: boolean;
|
|
25
25
|
}): Promise<void>;
|
|
26
|
-
export declare function runDbRetry(id: string, opts: {
|
|
26
|
+
export declare function runDbRetry(id: string | undefined, opts: {
|
|
27
27
|
json?: boolean;
|
|
28
28
|
}): Promise<void>;
|
|
29
|
-
export declare function runDbRotate(id: string, opts: {
|
|
29
|
+
export declare function runDbRotate(id: string | undefined, opts: {
|
|
30
30
|
json?: boolean;
|
|
31
31
|
}): Promise<void>;
|
|
32
|
-
export declare function runDbDelete(id: string, opts: {
|
|
32
|
+
export declare function runDbDelete(id: string | undefined, opts: {
|
|
33
33
|
json?: boolean;
|
|
34
34
|
}): Promise<void>;
|
|
35
35
|
export declare function runDbEngines(opts: {
|
|
@@ -9,6 +9,7 @@ import ora from 'ora';
|
|
|
9
9
|
import { apiRequest } from '../lib/api-client.js';
|
|
10
10
|
import { requireToken, handleApiError } from '../lib/cli-read.js';
|
|
11
11
|
import { renderTable } from '../lib/render.js';
|
|
12
|
+
import { pickDatabase, pickProductId, pickServer, promptChoice, promptText, } from '../lib/pickers.js';
|
|
12
13
|
import { log } from '../utils/logger.js';
|
|
13
14
|
function colorStatus(s) {
|
|
14
15
|
if (s === 'active')
|
|
@@ -59,45 +60,76 @@ export async function runDbList(opts) {
|
|
|
59
60
|
}
|
|
60
61
|
export async function runDbCreate(opts) {
|
|
61
62
|
const token = await requireToken(opts.json);
|
|
63
|
+
const productId = await pickProductId(token, {
|
|
64
|
+
fromFlag: opts.productId,
|
|
65
|
+
json: opts.json,
|
|
66
|
+
message: 'Produto do banco:',
|
|
67
|
+
});
|
|
68
|
+
const label = opts.label ?? (await promptText('Label do banco:', { json: opts.json }));
|
|
69
|
+
const engine = opts.engine ??
|
|
70
|
+
(await promptChoice('Engine:', [
|
|
71
|
+
{ name: 'firestore-instance', value: 'firestore-instance' },
|
|
72
|
+
{ name: 'cloud-sql-postgres', value: 'cloud-sql-postgres' },
|
|
73
|
+
{ name: 'cloud-sql-mysql', value: 'cloud-sql-mysql' },
|
|
74
|
+
{ name: 'vm-postgres-single', value: 'vm-postgres-single' },
|
|
75
|
+
{ name: 'vm-postgres-cluster', value: 'vm-postgres-cluster' },
|
|
76
|
+
{ name: 'vm-mysql-single', value: 'vm-mysql-single' },
|
|
77
|
+
{ name: 'vm-mysql-cluster', value: 'vm-mysql-cluster' },
|
|
78
|
+
], { default: 'firestore-instance', json: opts.json }));
|
|
79
|
+
const environment = opts.env ??
|
|
80
|
+
(await promptChoice('Ambiente:', [
|
|
81
|
+
{ name: 'dev', value: 'dev' },
|
|
82
|
+
{ name: 'staging', value: 'staging' },
|
|
83
|
+
{ name: 'production', value: 'production' },
|
|
84
|
+
], { default: 'dev', json: opts.json }));
|
|
85
|
+
const serverId = opts.serverId ??
|
|
86
|
+
(engine.startsWith('vm-')
|
|
87
|
+
? await pickServer(token, {
|
|
88
|
+
json: opts.json,
|
|
89
|
+
status: 'online',
|
|
90
|
+
capacity: true,
|
|
91
|
+
message: 'Server para o banco VM:',
|
|
92
|
+
})
|
|
93
|
+
: undefined);
|
|
62
94
|
let provisioning;
|
|
63
|
-
if (
|
|
95
|
+
if (engine === 'firestore-instance') {
|
|
64
96
|
provisioning = {
|
|
65
|
-
engine
|
|
97
|
+
engine,
|
|
66
98
|
config: { locationId: opts.region, type: 'regional' },
|
|
67
99
|
};
|
|
68
100
|
}
|
|
69
|
-
else if (
|
|
101
|
+
else if (engine.startsWith('cloud-sql-')) {
|
|
70
102
|
provisioning = {
|
|
71
|
-
engine
|
|
103
|
+
engine,
|
|
72
104
|
config: {
|
|
73
105
|
region: opts.region,
|
|
74
106
|
tier: 'db-custom-2-7680',
|
|
75
107
|
storageGb: 50,
|
|
76
|
-
highAvailability:
|
|
108
|
+
highAvailability: environment === 'production',
|
|
77
109
|
},
|
|
78
110
|
};
|
|
79
111
|
}
|
|
80
112
|
else {
|
|
81
113
|
provisioning = {
|
|
82
|
-
engine
|
|
114
|
+
engine,
|
|
83
115
|
config: {
|
|
84
116
|
region: opts.region,
|
|
85
117
|
zone: `${opts.region}-a`,
|
|
86
118
|
machineType: 'e2-standard-4',
|
|
87
119
|
diskGb: 100,
|
|
88
|
-
...(
|
|
120
|
+
...(engine.endsWith('-cluster')
|
|
89
121
|
? { replicaCount: Number(opts.replicaCount ?? '2') || 2 }
|
|
90
122
|
: {}),
|
|
91
123
|
},
|
|
92
124
|
};
|
|
93
125
|
}
|
|
94
126
|
const body = {
|
|
95
|
-
productId
|
|
96
|
-
label
|
|
97
|
-
engine
|
|
98
|
-
environment
|
|
127
|
+
productId,
|
|
128
|
+
label,
|
|
129
|
+
engine,
|
|
130
|
+
environment,
|
|
99
131
|
provisioning,
|
|
100
|
-
...(
|
|
132
|
+
...(serverId ? { serverId } : {}),
|
|
101
133
|
};
|
|
102
134
|
const spinner = opts.json ? null : ora({ text: 'Criando banco…', color: 'blue' }).start();
|
|
103
135
|
try {
|
|
@@ -121,8 +153,13 @@ export async function runDbCreate(opts) {
|
|
|
121
153
|
// ─── get ─────────────────────────────────────────────────────────────────────
|
|
122
154
|
export async function runDbGet(id, opts) {
|
|
123
155
|
const token = await requireToken(opts.json);
|
|
156
|
+
const databaseId = await pickDatabase(token, {
|
|
157
|
+
fromFlag: id,
|
|
158
|
+
json: opts.json,
|
|
159
|
+
message: 'Banco:',
|
|
160
|
+
});
|
|
124
161
|
try {
|
|
125
|
-
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(
|
|
162
|
+
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(databaseId)}/get`, { token });
|
|
126
163
|
if (opts.json) {
|
|
127
164
|
console.log(JSON.stringify(res));
|
|
128
165
|
return;
|
|
@@ -145,17 +182,30 @@ export async function runDbGet(id, opts) {
|
|
|
145
182
|
// ─── status / retry / rotate / delete ────────────────────────────────────────
|
|
146
183
|
export async function runDbStatus(id, status, opts) {
|
|
147
184
|
const token = await requireToken(opts.json);
|
|
185
|
+
const databaseId = await pickDatabase(token, {
|
|
186
|
+
fromFlag: id,
|
|
187
|
+
json: opts.json,
|
|
188
|
+
message: 'Banco:',
|
|
189
|
+
});
|
|
190
|
+
const resolvedStatus = status ??
|
|
191
|
+
(await promptChoice('Novo status:', [
|
|
192
|
+
{ name: 'active', value: 'active' },
|
|
193
|
+
{ name: 'provisioning', value: 'provisioning' },
|
|
194
|
+
{ name: 'degraded', value: 'degraded' },
|
|
195
|
+
{ name: 'failed', value: 'failed' },
|
|
196
|
+
{ name: 'archived', value: 'archived' },
|
|
197
|
+
], { default: 'active', json: opts.json }));
|
|
148
198
|
try {
|
|
149
|
-
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(
|
|
199
|
+
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(databaseId)}/status`, {
|
|
150
200
|
token,
|
|
151
201
|
method: 'POST',
|
|
152
|
-
body: { status, reason: opts.reason },
|
|
202
|
+
body: { status: resolvedStatus, reason: opts.reason },
|
|
153
203
|
});
|
|
154
204
|
if (opts.json) {
|
|
155
205
|
console.log(JSON.stringify(res));
|
|
156
206
|
return;
|
|
157
207
|
}
|
|
158
|
-
log.success(`Status atualizado: ${chalk.cyan(
|
|
208
|
+
log.success(`Status atualizado: ${chalk.cyan(resolvedStatus)}`);
|
|
159
209
|
}
|
|
160
210
|
catch (error) {
|
|
161
211
|
handleApiError(error, opts.json);
|
|
@@ -163,8 +213,13 @@ export async function runDbStatus(id, status, opts) {
|
|
|
163
213
|
}
|
|
164
214
|
export async function runDbRetry(id, opts) {
|
|
165
215
|
const token = await requireToken(opts.json);
|
|
216
|
+
const databaseId = await pickDatabase(token, {
|
|
217
|
+
fromFlag: id,
|
|
218
|
+
json: opts.json,
|
|
219
|
+
message: 'Banco para retry:',
|
|
220
|
+
});
|
|
166
221
|
try {
|
|
167
|
-
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(
|
|
222
|
+
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(databaseId)}/retry`, {
|
|
168
223
|
token,
|
|
169
224
|
method: 'POST',
|
|
170
225
|
body: {},
|
|
@@ -181,8 +236,13 @@ export async function runDbRetry(id, opts) {
|
|
|
181
236
|
}
|
|
182
237
|
export async function runDbRotate(id, opts) {
|
|
183
238
|
const token = await requireToken(opts.json);
|
|
239
|
+
const databaseId = await pickDatabase(token, {
|
|
240
|
+
fromFlag: id,
|
|
241
|
+
json: opts.json,
|
|
242
|
+
message: 'Banco para rotacionar:',
|
|
243
|
+
});
|
|
184
244
|
try {
|
|
185
|
-
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(
|
|
245
|
+
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(databaseId)}/rotate-credentials`, { token, method: 'POST', body: {} });
|
|
186
246
|
if (opts.json) {
|
|
187
247
|
console.log(JSON.stringify(res));
|
|
188
248
|
return;
|
|
@@ -195,8 +255,13 @@ export async function runDbRotate(id, opts) {
|
|
|
195
255
|
}
|
|
196
256
|
export async function runDbDelete(id, opts) {
|
|
197
257
|
const token = await requireToken(opts.json);
|
|
258
|
+
const databaseId = await pickDatabase(token, {
|
|
259
|
+
fromFlag: id,
|
|
260
|
+
json: opts.json,
|
|
261
|
+
message: 'Banco para arquivar:',
|
|
262
|
+
});
|
|
198
263
|
try {
|
|
199
|
-
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(
|
|
264
|
+
const res = await apiRequest(`/api/cli/v1/db/${encodeURIComponent(databaseId)}/delete`, {
|
|
200
265
|
token,
|
|
201
266
|
method: 'POST',
|
|
202
267
|
body: {},
|