@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.
@@ -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
- }