@eve-horizon/cli 0.2.11 → 0.2.13
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/index.js +65918 -121
- package/package.json +5 -3
- package/dist/commands/admin.js +0 -81
- package/dist/commands/agents.js +0 -196
- package/dist/commands/api.js +0 -350
- package/dist/commands/auth.js +0 -823
- package/dist/commands/build.js +0 -397
- package/dist/commands/chat.js +0 -55
- package/dist/commands/db.js +0 -204
- package/dist/commands/env.js +0 -673
- package/dist/commands/event.js +0 -273
- package/dist/commands/harness.js +0 -158
- package/dist/commands/init.js +0 -290
- package/dist/commands/integrations.js +0 -73
- package/dist/commands/job.js +0 -2537
- package/dist/commands/manifest.js +0 -86
- package/dist/commands/org.js +0 -106
- package/dist/commands/pipeline.js +0 -629
- package/dist/commands/profile.js +0 -155
- package/dist/commands/project.js +0 -212
- package/dist/commands/release.js +0 -69
- package/dist/commands/secrets.js +0 -218
- package/dist/commands/skills.js +0 -390
- package/dist/commands/system.js +0 -649
- package/dist/commands/workflow.js +0 -337
- package/dist/lib/args.js +0 -57
- package/dist/lib/client.js +0 -116
- package/dist/lib/config.js +0 -49
- package/dist/lib/context.js +0 -187
- package/dist/lib/git.js +0 -158
- package/dist/lib/harness-capabilities.js +0 -74
- package/dist/lib/help.js +0 -1572
- package/dist/lib/logs.js +0 -51
- package/dist/lib/output.js +0 -14
package/dist/commands/env.js
DELETED
|
@@ -1,673 +0,0 @@
|
|
|
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.handleEnv = handleEnv;
|
|
37
|
-
const args_1 = require("../lib/args");
|
|
38
|
-
const client_1 = require("../lib/client");
|
|
39
|
-
const output_1 = require("../lib/output");
|
|
40
|
-
const git_js_1 = require("../lib/git.js");
|
|
41
|
-
const readline = __importStar(require("node:readline/promises"));
|
|
42
|
-
// ============================================================================
|
|
43
|
-
// Main Handler
|
|
44
|
-
// ============================================================================
|
|
45
|
-
async function handleEnv(subcommand, positionals, flags, context) {
|
|
46
|
-
const json = Boolean(flags.json);
|
|
47
|
-
switch (subcommand) {
|
|
48
|
-
case 'list':
|
|
49
|
-
return handleList(positionals, flags, context, json);
|
|
50
|
-
case 'show':
|
|
51
|
-
return handleShow(positionals, flags, context, json);
|
|
52
|
-
case 'create':
|
|
53
|
-
return handleCreate(positionals, flags, context, json);
|
|
54
|
-
case 'deploy':
|
|
55
|
-
return handleDeploy(positionals, flags, context, json);
|
|
56
|
-
case 'logs':
|
|
57
|
-
return handleLogs(positionals, flags, context, json);
|
|
58
|
-
case 'diagnose':
|
|
59
|
-
return handleDiagnose(positionals, flags, context, json);
|
|
60
|
-
case 'delete':
|
|
61
|
-
return handleDelete(positionals, flags, context, json);
|
|
62
|
-
default:
|
|
63
|
-
throw new Error('Usage: eve env <list|show|create|deploy|logs|delete>\n' +
|
|
64
|
-
' list [project] - list environments for a project\n' +
|
|
65
|
-
' show <project> <name> - show details of an environment\n' +
|
|
66
|
-
' create <name> --type=<type> [options] - create an environment\n' +
|
|
67
|
-
' deploy <env> --ref <sha> [--direct] [--inputs <json>] [--repo-dir <path>] - deploy to an environment\n' +
|
|
68
|
-
' logs <project> <env> <service> [--since <seconds>] [--tail <n>] [--grep <text>] - get service logs\n' +
|
|
69
|
-
' diagnose <project> <env> - diagnose deployment health and events\n' +
|
|
70
|
-
' delete <name> [--project=<id>] [--force] - delete an environment');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// ============================================================================
|
|
74
|
-
// Subcommand Handlers
|
|
75
|
-
// ============================================================================
|
|
76
|
-
/**
|
|
77
|
-
* eve env list [project]
|
|
78
|
-
* List environments for a project
|
|
79
|
-
*/
|
|
80
|
-
async function handleList(positionals, flags, context, json) {
|
|
81
|
-
const projectId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
82
|
-
if (!projectId) {
|
|
83
|
-
throw new Error('Usage: eve env list [project] [--project=<id>]');
|
|
84
|
-
}
|
|
85
|
-
const query = buildQuery({
|
|
86
|
-
limit: (0, args_1.getStringFlag)(flags, ['limit']),
|
|
87
|
-
offset: (0, args_1.getStringFlag)(flags, ['offset']),
|
|
88
|
-
});
|
|
89
|
-
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs${query}`);
|
|
90
|
-
if (json) {
|
|
91
|
-
(0, output_1.outputJson)(response, json);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
if (response.data.length === 0) {
|
|
95
|
-
console.log('No environments found.');
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
formatEnvironmentsTable(response.data);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* eve env show <project> <name>
|
|
103
|
-
* Show details of an environment
|
|
104
|
-
*/
|
|
105
|
-
async function handleShow(positionals, flags, context, json) {
|
|
106
|
-
const projectId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
107
|
-
const envName = positionals[1] ?? (0, args_1.getStringFlag)(flags, ['name']);
|
|
108
|
-
if (!projectId || !envName) {
|
|
109
|
-
throw new Error('Usage: eve env show <project> <name> [--project=<id>] [--name=<name>]');
|
|
110
|
-
}
|
|
111
|
-
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}`);
|
|
112
|
-
const health = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/health`);
|
|
113
|
-
if (json) {
|
|
114
|
-
(0, output_1.outputJson)({ ...response, health }, json);
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
formatEnvironmentDetails(response, health);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* eve env create <name> --type=<type> [--namespace=<ns>] [--db-ref=<ref>]
|
|
122
|
-
* Create an environment
|
|
123
|
-
*/
|
|
124
|
-
async function handleCreate(positionals, flags, context, json) {
|
|
125
|
-
const projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
126
|
-
const name = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['name']);
|
|
127
|
-
const type = (0, args_1.getStringFlag)(flags, ['type']);
|
|
128
|
-
if (!projectId) {
|
|
129
|
-
throw new Error('Usage: eve env create <name> --type=<type> [--project=<id>]');
|
|
130
|
-
}
|
|
131
|
-
if (!name) {
|
|
132
|
-
throw new Error('Usage: eve env create <name> --type=<type>');
|
|
133
|
-
}
|
|
134
|
-
if (!type || !['persistent', 'temporary'].includes(type)) {
|
|
135
|
-
throw new Error('--type must be either "persistent" or "temporary"');
|
|
136
|
-
}
|
|
137
|
-
const body = {
|
|
138
|
-
name,
|
|
139
|
-
type,
|
|
140
|
-
};
|
|
141
|
-
const namespace = (0, args_1.getStringFlag)(flags, ['namespace']);
|
|
142
|
-
if (namespace) {
|
|
143
|
-
body.namespace = namespace;
|
|
144
|
-
}
|
|
145
|
-
const dbRef = (0, args_1.getStringFlag)(flags, ['db-ref', 'dbRef']);
|
|
146
|
-
if (dbRef) {
|
|
147
|
-
body.db_ref = dbRef;
|
|
148
|
-
}
|
|
149
|
-
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs`, {
|
|
150
|
-
method: 'POST',
|
|
151
|
-
body,
|
|
152
|
-
});
|
|
153
|
-
if (json) {
|
|
154
|
-
(0, output_1.outputJson)(response, json);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
console.log(`✓ Environment created: ${response.name} (${response.id})`);
|
|
158
|
-
console.log(` Type: ${response.type}`);
|
|
159
|
-
console.log(` Namespace: ${response.namespace || '(none)'}`);
|
|
160
|
-
console.log(` DB Ref: ${response.db_ref || '(none)'}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* eve env deploy [project] <name> --ref <sha> [--direct] [--inputs <json>] [--image-tag <tag>]
|
|
165
|
-
* Deploy to an environment
|
|
166
|
-
* If project is in profile, can use: eve env deploy <name> --ref <sha>
|
|
167
|
-
*/
|
|
168
|
-
async function handleDeploy(positionals, flags, context, json) {
|
|
169
|
-
// Smart positional parsing:
|
|
170
|
-
// - 2 positionals: [project, envName]
|
|
171
|
-
// - 1 positional + project in context: envName
|
|
172
|
-
// - 1 positional + no project in context: assume it's project, error for missing name
|
|
173
|
-
let projectId;
|
|
174
|
-
let envName;
|
|
175
|
-
const flagProject = (0, args_1.getStringFlag)(flags, ['project']);
|
|
176
|
-
const flagName = (0, args_1.getStringFlag)(flags, ['name']);
|
|
177
|
-
if (positionals.length >= 2) {
|
|
178
|
-
projectId = positionals[0];
|
|
179
|
-
envName = positionals[1];
|
|
180
|
-
}
|
|
181
|
-
else if (positionals.length === 1) {
|
|
182
|
-
if (flagProject || context.projectId) {
|
|
183
|
-
// Single positional is the env name
|
|
184
|
-
projectId = flagProject ?? context.projectId;
|
|
185
|
-
envName = positionals[0];
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
// Single positional must be project, no env name
|
|
189
|
-
projectId = positionals[0];
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
projectId = flagProject ?? context.projectId;
|
|
194
|
-
envName = flagName;
|
|
195
|
-
}
|
|
196
|
-
if (!projectId || !envName) {
|
|
197
|
-
throw new Error('Usage: eve env deploy <env> --ref <sha> [--direct] [--inputs <json>] [--image-tag <tag>] [--repo-dir <path>] [--project=<id>]');
|
|
198
|
-
}
|
|
199
|
-
// --ref flag is now required
|
|
200
|
-
const ref = (0, args_1.getStringFlag)(flags, ['ref']);
|
|
201
|
-
if (!ref) {
|
|
202
|
-
throw new Error('Usage: eve env deploy <env> --ref <sha> [options]\n\nThe --ref flag is required (git SHA or commit reference)');
|
|
203
|
-
}
|
|
204
|
-
const repoDir = (0, args_1.getStringFlag)(flags, ['repo-dir', 'repo_dir', 'dir']);
|
|
205
|
-
// Resolve git ref to actual 40-char SHA
|
|
206
|
-
const gitSha = await (0, git_js_1.resolveGitRef)(context, projectId, ref, repoDir);
|
|
207
|
-
if (!json && ref !== gitSha) {
|
|
208
|
-
console.log(`Resolved ref '${ref}' → ${gitSha.substring(0, 8)}...`);
|
|
209
|
-
}
|
|
210
|
-
if (!json) {
|
|
211
|
-
console.log(`Deploying commit ${gitSha.substring(0, 8)} to ${envName}...`);
|
|
212
|
-
}
|
|
213
|
-
// Get manifest hash from server
|
|
214
|
-
const manifest = await (0, client_1.requestJson)(context, `/projects/${projectId}/manifest`);
|
|
215
|
-
if (!json) {
|
|
216
|
-
console.log(`Using manifest ${manifest.manifest_hash.substring(0, 8)}...`);
|
|
217
|
-
}
|
|
218
|
-
// Parse --direct flag (optional boolean)
|
|
219
|
-
const direct = Boolean(flags.direct);
|
|
220
|
-
// Parse --inputs flag (optional JSON)
|
|
221
|
-
let inputs;
|
|
222
|
-
const inputsString = (0, args_1.getStringFlag)(flags, ['inputs']);
|
|
223
|
-
if (inputsString) {
|
|
224
|
-
try {
|
|
225
|
-
inputs = JSON.parse(inputsString);
|
|
226
|
-
if (typeof inputs !== 'object' || inputs === null || Array.isArray(inputs)) {
|
|
227
|
-
throw new Error('Inputs must be a JSON object');
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
throw new Error(`Failed to parse --inputs JSON: ${error instanceof Error ? error.message : String(error)}\n` +
|
|
232
|
-
'Example: --inputs \'{"release_id":"rel_xxx","smoke_test":false}\'');
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
// Parse --image-tag flag (optional)
|
|
236
|
-
const imageTag = (0, args_1.getStringFlag)(flags, ['image-tag', 'image_tag', 'imageTag']);
|
|
237
|
-
// POST deployment
|
|
238
|
-
const body = {
|
|
239
|
-
git_sha: gitSha,
|
|
240
|
-
manifest_hash: manifest.manifest_hash,
|
|
241
|
-
};
|
|
242
|
-
if (direct) {
|
|
243
|
-
body.direct = true;
|
|
244
|
-
}
|
|
245
|
-
if (inputs) {
|
|
246
|
-
body.inputs = inputs;
|
|
247
|
-
}
|
|
248
|
-
if (imageTag) {
|
|
249
|
-
body.image_tag = imageTag;
|
|
250
|
-
}
|
|
251
|
-
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/deploy`, {
|
|
252
|
-
method: 'POST',
|
|
253
|
-
body,
|
|
254
|
-
});
|
|
255
|
-
if (json) {
|
|
256
|
-
(0, output_1.outputJson)(response, json);
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
if (response.pipeline_run) {
|
|
260
|
-
console.log('');
|
|
261
|
-
console.log('Pipeline deployment started.');
|
|
262
|
-
console.log(` Pipeline Run: ${response.pipeline_run.run.id}`);
|
|
263
|
-
console.log(` Pipeline: ${response.pipeline_run.run.pipeline_name}`);
|
|
264
|
-
console.log(` Status: ${response.pipeline_run.run.status}`);
|
|
265
|
-
console.log(` Environment: ${response.environment.name}`);
|
|
266
|
-
const watchFlag = (0, args_1.toBoolean)(flags.watch);
|
|
267
|
-
const shouldWatch = watchFlag ?? true; // default: watch
|
|
268
|
-
if (shouldWatch) {
|
|
269
|
-
const timeoutRaw = (0, args_1.getStringFlag)(flags, ['timeout']);
|
|
270
|
-
const timeoutSeconds = timeoutRaw ? parseInt(timeoutRaw, 10) : 300; // 5 min default for pipeline
|
|
271
|
-
const pipelineResult = await watchPipelineRun(context, projectId, response.pipeline_run.run.pipeline_name, response.pipeline_run.run.id, Number.isFinite(timeoutSeconds) ? timeoutSeconds : 300);
|
|
272
|
-
// After pipeline completes, watch deployment health if it succeeded
|
|
273
|
-
if (pipelineResult === 'succeeded') {
|
|
274
|
-
await watchDeploymentStatus(context, projectId, envName, 120);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
console.log('');
|
|
280
|
-
console.log(`Deployment submitted.`);
|
|
281
|
-
if (response.release) {
|
|
282
|
-
console.log(` Release ID: ${response.release.id}`);
|
|
283
|
-
}
|
|
284
|
-
console.log(` Environment: ${response.environment.name}`);
|
|
285
|
-
console.log(` Namespace: ${response.environment.namespace || '(none)'}`);
|
|
286
|
-
if (response.deployment_status?.k8s_status) {
|
|
287
|
-
const status = response.deployment_status.k8s_status;
|
|
288
|
-
const readiness = `${status.available_replicas}/${status.desired_replicas}`;
|
|
289
|
-
console.log(` Status: ${response.deployment_status.state} (${readiness} ready)`);
|
|
290
|
-
}
|
|
291
|
-
else if (response.deployment_status?.state) {
|
|
292
|
-
console.log(` Status: ${response.deployment_status.state}`);
|
|
293
|
-
}
|
|
294
|
-
const warnings = response.warnings ?? getDeploymentWarnings(response.deployment_status);
|
|
295
|
-
if (warnings.length > 0) {
|
|
296
|
-
console.log('');
|
|
297
|
-
console.log('Warnings:');
|
|
298
|
-
for (const warning of warnings) {
|
|
299
|
-
console.log(` - ${warning}`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
const watchFlag = (0, args_1.toBoolean)(flags.watch);
|
|
303
|
-
const shouldWatch = (watchFlag ?? true)
|
|
304
|
-
&& response.deployment_status?.state !== 'ready';
|
|
305
|
-
if (shouldWatch) {
|
|
306
|
-
const timeoutRaw = (0, args_1.getStringFlag)(flags, ['timeout']);
|
|
307
|
-
const timeoutSeconds = timeoutRaw ? parseInt(timeoutRaw, 10) : 120;
|
|
308
|
-
await watchDeploymentStatus(context, projectId, envName, Number.isFinite(timeoutSeconds) ? timeoutSeconds : 120);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* eve env logs <project> <env> <service>
|
|
314
|
-
* Fetch logs for a service in an environment (k8s-only)
|
|
315
|
-
*/
|
|
316
|
-
async function handleLogs(positionals, flags, context, json) {
|
|
317
|
-
const projectId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
318
|
-
const envName = positionals[1] ?? (0, args_1.getStringFlag)(flags, ['env', 'name']);
|
|
319
|
-
const service = positionals[2] ?? (0, args_1.getStringFlag)(flags, ['service']);
|
|
320
|
-
if (!projectId || !envName || !service) {
|
|
321
|
-
throw new Error('Usage: eve env logs <project> <env> <service> [--since <seconds>] [--tail <n>] [--grep <text>]');
|
|
322
|
-
}
|
|
323
|
-
const query = buildQuery({
|
|
324
|
-
since: (0, args_1.getStringFlag)(flags, ['since']),
|
|
325
|
-
tail: (0, args_1.getStringFlag)(flags, ['tail']),
|
|
326
|
-
grep: (0, args_1.getStringFlag)(flags, ['grep']),
|
|
327
|
-
});
|
|
328
|
-
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/services/${service}/logs${query}`);
|
|
329
|
-
if (json) {
|
|
330
|
-
(0, output_1.outputJson)(response, json);
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
if (!response.logs.length) {
|
|
334
|
-
console.log('No logs found.');
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
for (const entry of response.logs) {
|
|
338
|
-
console.log(`[${entry.timestamp}] ${entry.line}`);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* eve env diagnose <project> <env>
|
|
343
|
-
* Diagnose deployment health for an environment (k8s-only)
|
|
344
|
-
*/
|
|
345
|
-
async function handleDiagnose(positionals, flags, context, json) {
|
|
346
|
-
const projectId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
347
|
-
const envName = positionals[1] ?? (0, args_1.getStringFlag)(flags, ['env', 'name']);
|
|
348
|
-
if (!projectId || !envName) {
|
|
349
|
-
throw new Error('Usage: eve env diagnose <project> <env> [--events <n>]');
|
|
350
|
-
}
|
|
351
|
-
const query = buildQuery({
|
|
352
|
-
events: (0, args_1.getStringFlag)(flags, ['events']),
|
|
353
|
-
});
|
|
354
|
-
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/diagnose${query}`);
|
|
355
|
-
if (json) {
|
|
356
|
-
(0, output_1.outputJson)(response, json);
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
formatEnvDiagnose(response);
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* eve env delete <name> [--project=<id>] [--force]
|
|
363
|
-
* Delete an environment
|
|
364
|
-
*/
|
|
365
|
-
async function handleDelete(positionals, flags, context, json) {
|
|
366
|
-
const projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
367
|
-
const envName = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['name']);
|
|
368
|
-
const force = Boolean(flags.force);
|
|
369
|
-
if (!projectId || !envName) {
|
|
370
|
-
throw new Error('Usage: eve env delete <name> [--project=<id>] [--force]');
|
|
371
|
-
}
|
|
372
|
-
// Prompt for confirmation unless --force is set
|
|
373
|
-
if (!force) {
|
|
374
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
375
|
-
try {
|
|
376
|
-
const answer = await rl.question(`Are you sure you want to delete environment "${envName}"? [y/N]: `);
|
|
377
|
-
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
378
|
-
console.log('Deletion cancelled.');
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
finally {
|
|
383
|
-
rl.close();
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
try {
|
|
387
|
-
await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}`, {
|
|
388
|
-
method: 'DELETE',
|
|
389
|
-
});
|
|
390
|
-
if (json) {
|
|
391
|
-
(0, output_1.outputJson)({ success: true, environment: envName }, json);
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
console.log(`Environment "${envName}" deleted successfully.`);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
catch (error) {
|
|
398
|
-
const err = error;
|
|
399
|
-
const message = err.message;
|
|
400
|
-
// Handle specific error cases
|
|
401
|
-
if (message.includes('404')) {
|
|
402
|
-
throw new Error(`Environment "${envName}" not found in project ${projectId}`);
|
|
403
|
-
}
|
|
404
|
-
else if (message.includes('409')) {
|
|
405
|
-
throw new Error(`Cannot delete environment "${envName}": environment has active deployments or resources`);
|
|
406
|
-
}
|
|
407
|
-
else {
|
|
408
|
-
throw error;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
// ============================================================================
|
|
413
|
-
// Helper Functions
|
|
414
|
-
// ============================================================================
|
|
415
|
-
/**
|
|
416
|
-
* Build query string from parameters
|
|
417
|
-
*/
|
|
418
|
-
function buildQuery(params) {
|
|
419
|
-
const search = new URLSearchParams();
|
|
420
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
421
|
-
if (value === undefined || value === '')
|
|
422
|
-
return;
|
|
423
|
-
search.set(key, String(value));
|
|
424
|
-
});
|
|
425
|
-
const query = search.toString();
|
|
426
|
-
return query ? `?${query}` : '';
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Format environments as a human-readable table
|
|
430
|
-
*/
|
|
431
|
-
function formatEnvironmentsTable(environments) {
|
|
432
|
-
if (environments.length === 0) {
|
|
433
|
-
console.log('No environments found.');
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
// Calculate column widths
|
|
437
|
-
const nameWidth = Math.max(4, ...environments.map((e) => e.name.length));
|
|
438
|
-
const typeWidth = Math.max(4, ...environments.map((e) => e.type.length));
|
|
439
|
-
const namespaceWidth = Math.max(9, ...environments.map((e) => e.namespace?.length ?? 0));
|
|
440
|
-
// Header
|
|
441
|
-
const header = [
|
|
442
|
-
padRight('Name', nameWidth),
|
|
443
|
-
padRight('Type', typeWidth),
|
|
444
|
-
padRight('Namespace', namespaceWidth),
|
|
445
|
-
'Current Release',
|
|
446
|
-
].join(' ');
|
|
447
|
-
console.log(header);
|
|
448
|
-
console.log('-'.repeat(header.length));
|
|
449
|
-
// Rows
|
|
450
|
-
for (const env of environments) {
|
|
451
|
-
const releaseDisplay = env.current_release_id
|
|
452
|
-
? env.current_release_id.substring(0, 12) + '...'
|
|
453
|
-
: '-';
|
|
454
|
-
const row = [
|
|
455
|
-
padRight(env.name, nameWidth),
|
|
456
|
-
padRight(env.type, typeWidth),
|
|
457
|
-
padRight(env.namespace || '-', namespaceWidth),
|
|
458
|
-
releaseDisplay,
|
|
459
|
-
].join(' ');
|
|
460
|
-
console.log(row);
|
|
461
|
-
}
|
|
462
|
-
console.log('');
|
|
463
|
-
console.log(`Total: ${environments.length} environment(s)`);
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* Format a single environment's details
|
|
467
|
-
*/
|
|
468
|
-
function formatEnvironmentDetails(env, health) {
|
|
469
|
-
console.log(`Environment: ${env.name}`);
|
|
470
|
-
console.log('');
|
|
471
|
-
console.log(` ID: ${env.id}`);
|
|
472
|
-
console.log(` Project: ${env.project_id}`);
|
|
473
|
-
console.log(` Type: ${env.type}`);
|
|
474
|
-
console.log(` Namespace: ${env.namespace || '(none)'}`);
|
|
475
|
-
console.log(` Database Ref: ${env.db_ref || '(none)'}`);
|
|
476
|
-
console.log(` Current Release: ${env.current_release_id || '(none)'}`);
|
|
477
|
-
if (health) {
|
|
478
|
-
console.log('');
|
|
479
|
-
console.log(` Deployment Status: ${health.status}`);
|
|
480
|
-
if (health.deployment) {
|
|
481
|
-
console.log(` Deployment Ready: ${health.deployment.available_replicas}/${health.deployment.desired_replicas}`);
|
|
482
|
-
}
|
|
483
|
-
if (health.warnings && health.warnings.length > 0) {
|
|
484
|
-
console.log(' Warnings:');
|
|
485
|
-
for (const warning of health.warnings) {
|
|
486
|
-
console.log(` - ${warning}`);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
if (env.overrides && Object.keys(env.overrides).length > 0) {
|
|
491
|
-
console.log('');
|
|
492
|
-
console.log(' Overrides:');
|
|
493
|
-
for (const [key, value] of Object.entries(env.overrides)) {
|
|
494
|
-
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
console.log('');
|
|
498
|
-
console.log(` Created: ${formatDate(env.created_at)}`);
|
|
499
|
-
console.log(` Updated: ${formatDate(env.updated_at)}`);
|
|
500
|
-
}
|
|
501
|
-
function formatEnvDiagnose(report) {
|
|
502
|
-
console.log(`Environment Diagnose: ${report.env_name}`);
|
|
503
|
-
console.log('');
|
|
504
|
-
console.log(` Namespace: ${report.namespace || '(none)'}`);
|
|
505
|
-
console.log(` Status: ${report.status}`);
|
|
506
|
-
console.log(` Ready: ${report.ready ? 'yes' : 'no'}`);
|
|
507
|
-
console.log(` K8s: ${report.k8s_available ? 'available' : 'unavailable'}`);
|
|
508
|
-
if (report.warnings && report.warnings.length > 0) {
|
|
509
|
-
console.log('');
|
|
510
|
-
console.log('Warnings:');
|
|
511
|
-
for (const warning of report.warnings) {
|
|
512
|
-
console.log(` - ${warning}`);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
if (report.deployments.length > 0) {
|
|
516
|
-
console.log('');
|
|
517
|
-
console.log('Deployments:');
|
|
518
|
-
const nameWidth = Math.max(4, ...report.deployments.map((d) => d.name.length));
|
|
519
|
-
const readyWidth = Math.max(5, ...report.deployments.map((d) => `${d.available_replicas}/${d.desired_replicas}`.length));
|
|
520
|
-
const header = [
|
|
521
|
-
padRight('Name', nameWidth),
|
|
522
|
-
padRight('Ready', readyWidth),
|
|
523
|
-
'Status',
|
|
524
|
-
].join(' ');
|
|
525
|
-
console.log(header);
|
|
526
|
-
console.log('-'.repeat(header.length));
|
|
527
|
-
for (const deployment of report.deployments) {
|
|
528
|
-
const readiness = `${deployment.available_replicas}/${deployment.desired_replicas}`;
|
|
529
|
-
const status = deployment.ready ? 'ready' : 'not-ready';
|
|
530
|
-
console.log([
|
|
531
|
-
padRight(deployment.name, nameWidth),
|
|
532
|
-
padRight(readiness, readyWidth),
|
|
533
|
-
status,
|
|
534
|
-
].join(' '));
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
if (report.pods.length > 0) {
|
|
538
|
-
console.log('');
|
|
539
|
-
console.log('Pods:');
|
|
540
|
-
const nameWidth = Math.max(4, ...report.pods.map((p) => p.name.length));
|
|
541
|
-
const phaseWidth = Math.max(5, ...report.pods.map((p) => p.phase.length));
|
|
542
|
-
const restartsWidth = Math.max(8, ...report.pods.map((p) => String(p.restarts).length));
|
|
543
|
-
const header = [
|
|
544
|
-
padRight('Name', nameWidth),
|
|
545
|
-
padRight('Phase', phaseWidth),
|
|
546
|
-
padRight('Restarts', restartsWidth),
|
|
547
|
-
'Ready',
|
|
548
|
-
'Age',
|
|
549
|
-
].join(' ');
|
|
550
|
-
console.log(header);
|
|
551
|
-
console.log('-'.repeat(header.length));
|
|
552
|
-
for (const pod of report.pods) {
|
|
553
|
-
console.log([
|
|
554
|
-
padRight(pod.name, nameWidth),
|
|
555
|
-
padRight(pod.phase, phaseWidth),
|
|
556
|
-
padRight(String(pod.restarts), restartsWidth),
|
|
557
|
-
pod.ready ? 'yes' : 'no',
|
|
558
|
-
pod.age,
|
|
559
|
-
].join(' '));
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
if (report.events.length > 0) {
|
|
563
|
-
console.log('');
|
|
564
|
-
console.log('Events:');
|
|
565
|
-
for (const event of report.events) {
|
|
566
|
-
const timestamp = event.timestamp ?? 'unknown';
|
|
567
|
-
const reason = event.reason ?? 'Unknown';
|
|
568
|
-
const message = event.message ?? '';
|
|
569
|
-
console.log(` [${timestamp}] ${event.type} ${reason}: ${message}`);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
function getDeploymentWarnings(status) {
|
|
574
|
-
if (!status)
|
|
575
|
-
return [];
|
|
576
|
-
const warnings = [];
|
|
577
|
-
if (status.state !== 'ready') {
|
|
578
|
-
warnings.push(`Deployment state: ${status.state}`);
|
|
579
|
-
}
|
|
580
|
-
if (status.k8s_status) {
|
|
581
|
-
const { available_replicas, desired_replicas, ready, conditions } = status.k8s_status;
|
|
582
|
-
if (!ready) {
|
|
583
|
-
warnings.push(`Deployment replicas not ready (${available_replicas}/${desired_replicas})`);
|
|
584
|
-
}
|
|
585
|
-
for (const condition of conditions) {
|
|
586
|
-
if (condition.status !== 'True' && condition.message) {
|
|
587
|
-
warnings.push(`${condition.type}: ${condition.message}`);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
return Array.from(new Set(warnings));
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Poll a pipeline run until it reaches a terminal status.
|
|
595
|
-
* Returns the final status string.
|
|
596
|
-
*/
|
|
597
|
-
async function watchPipelineRun(context, projectId, pipelineName, runId, timeoutSeconds) {
|
|
598
|
-
const start = Date.now();
|
|
599
|
-
const pollIntervalMs = 3000;
|
|
600
|
-
const terminalStatuses = ['succeeded', 'failed', 'cancelled'];
|
|
601
|
-
console.log('');
|
|
602
|
-
console.log('Watching pipeline run...');
|
|
603
|
-
while ((Date.now() - start) / 1000 < timeoutSeconds) {
|
|
604
|
-
const detail = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines/${pipelineName}/runs/${runId}`);
|
|
605
|
-
const elapsed = Math.floor((Date.now() - start) / 1000);
|
|
606
|
-
const stepSummary = detail.steps
|
|
607
|
-
.map(s => `${s.step_name}:${s.status}`)
|
|
608
|
-
.join(', ');
|
|
609
|
-
console.log(` [${elapsed}s] ${detail.run.status} (${stepSummary || 'no steps'})`);
|
|
610
|
-
if (terminalStatuses.includes(detail.run.status)) {
|
|
611
|
-
if (detail.run.status === 'succeeded') {
|
|
612
|
-
console.log(' Pipeline run succeeded.');
|
|
613
|
-
}
|
|
614
|
-
else if (detail.run.status === 'failed') {
|
|
615
|
-
console.log(` Pipeline run failed.`);
|
|
616
|
-
// Show error from failed steps
|
|
617
|
-
for (const step of detail.steps) {
|
|
618
|
-
if (step.status === 'failed') {
|
|
619
|
-
console.log(` Step "${step.step_name}" failed.`);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
else {
|
|
624
|
-
console.log(` Pipeline run ${detail.run.status}.`);
|
|
625
|
-
}
|
|
626
|
-
return detail.run.status;
|
|
627
|
-
}
|
|
628
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
629
|
-
}
|
|
630
|
-
console.log(` Pipeline run did not complete within ${timeoutSeconds}s.`);
|
|
631
|
-
console.log(` Run "eve pipeline show-run ${pipelineName} ${runId}" to check status.`);
|
|
632
|
-
return 'timeout';
|
|
633
|
-
}
|
|
634
|
-
async function watchDeploymentStatus(context, projectId, envName, timeoutSeconds) {
|
|
635
|
-
const start = Date.now();
|
|
636
|
-
const pollIntervalMs = 3000;
|
|
637
|
-
console.log('');
|
|
638
|
-
console.log('Watching deployment status...');
|
|
639
|
-
while ((Date.now() - start) / 1000 < timeoutSeconds) {
|
|
640
|
-
const health = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/health`);
|
|
641
|
-
const elapsed = Math.floor((Date.now() - start) / 1000);
|
|
642
|
-
const readiness = health.deployment
|
|
643
|
-
? `${health.deployment.available_replicas}/${health.deployment.desired_replicas}`
|
|
644
|
-
: 'n/a';
|
|
645
|
-
console.log(` [${elapsed}s] ${health.status} (${readiness} ready)`);
|
|
646
|
-
if (health.ready) {
|
|
647
|
-
console.log(' Deployment is ready.');
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
651
|
-
}
|
|
652
|
-
console.log(` Timeout after ${timeoutSeconds}s. Run "eve env diagnose ${projectId} ${envName}" for details.`);
|
|
653
|
-
}
|
|
654
|
-
/**
|
|
655
|
-
* Format a date string for display
|
|
656
|
-
*/
|
|
657
|
-
function formatDate(dateStr) {
|
|
658
|
-
try {
|
|
659
|
-
const date = new Date(dateStr);
|
|
660
|
-
return date.toLocaleString();
|
|
661
|
-
}
|
|
662
|
-
catch {
|
|
663
|
-
return dateStr;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* Pad a string to the right with spaces
|
|
668
|
-
*/
|
|
669
|
-
function padRight(str, width) {
|
|
670
|
-
if (str.length >= width)
|
|
671
|
-
return str;
|
|
672
|
-
return str + ' '.repeat(width - str.length);
|
|
673
|
-
}
|