@eve-horizon/cli 0.2.7 → 0.2.9
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/build.js +50 -10
- package/dist/commands/env.js +53 -1
- package/dist/commands/pipeline.js +195 -2
- package/dist/lib/help.js +15 -1
- package/package.json +1 -1
package/dist/commands/build.js
CHANGED
|
@@ -5,6 +5,19 @@ const args_1 = require("../lib/args");
|
|
|
5
5
|
const client_1 = require("../lib/client");
|
|
6
6
|
const output_1 = require("../lib/output");
|
|
7
7
|
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const ERROR_CODES = {
|
|
9
|
+
auth_error: { code: 'auth_error', label: 'Authentication Error', hint: "Check GITHUB_TOKEN via 'eve secrets set'" },
|
|
10
|
+
clone_error: { code: 'clone_error', label: 'Git Clone Error', hint: "Verify repo URL and access. Check 'eve secrets list'" },
|
|
11
|
+
build_error: { code: 'build_error', label: 'Build Error', hint: "Run 'eve build diagnose <build_id>' for full output" },
|
|
12
|
+
timeout_error: { code: 'timeout_error', label: 'Timeout Error', hint: 'Consider increasing timeout or checking resources' },
|
|
13
|
+
resource_error: { code: 'resource_error', label: 'Resource Error', hint: 'Check disk space and memory on build worker' },
|
|
14
|
+
registry_error: { code: 'registry_error', label: 'Registry Error', hint: "Check registry credentials via 'eve secrets list'" },
|
|
15
|
+
deploy_error: { code: 'deploy_error', label: 'Deploy Error', hint: "Run 'eve env diagnose <project> <env>'" },
|
|
16
|
+
unknown_error: { code: 'unknown_error', label: 'Unknown Error', hint: "Run 'eve build diagnose <build_id>' or 'eve job diagnose <job_id>'" },
|
|
17
|
+
};
|
|
18
|
+
function getErrorCodeInfo(code) {
|
|
19
|
+
return ERROR_CODES[code] ?? ERROR_CODES.unknown_error;
|
|
20
|
+
}
|
|
8
21
|
// ---------------------------------------------------------------------------
|
|
9
22
|
// Entry point
|
|
10
23
|
// ---------------------------------------------------------------------------
|
|
@@ -154,6 +167,17 @@ async function handleRuns(positionals, flags, context, json) {
|
|
|
154
167
|
}
|
|
155
168
|
formatRunList(response.data);
|
|
156
169
|
}
|
|
170
|
+
function formatLogTimestamp(timestamp) {
|
|
171
|
+
if (!timestamp)
|
|
172
|
+
return '';
|
|
173
|
+
try {
|
|
174
|
+
const d = new Date(timestamp);
|
|
175
|
+
return `[${d.toLocaleTimeString('en-US', { hour12: false })}] `;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return '';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
157
181
|
async function handleLogs(positionals, flags, context, json) {
|
|
158
182
|
const buildId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['id']);
|
|
159
183
|
const runId = (0, args_1.getStringFlag)(flags, ['run']);
|
|
@@ -171,20 +195,26 @@ async function handleLogs(positionals, flags, context, json) {
|
|
|
171
195
|
return;
|
|
172
196
|
}
|
|
173
197
|
for (const entry of logs.logs) {
|
|
198
|
+
const prefix = formatLogTimestamp(entry.timestamp);
|
|
174
199
|
const line = entry.line;
|
|
175
200
|
if (typeof line.message === 'string') {
|
|
176
|
-
console.log(line.message);
|
|
177
|
-
continue;
|
|
201
|
+
console.log(`${prefix}${line.message}`);
|
|
178
202
|
}
|
|
179
|
-
if (Array.isArray(line.lines)) {
|
|
203
|
+
else if (Array.isArray(line.lines)) {
|
|
180
204
|
for (const item of line.lines) {
|
|
181
205
|
if (typeof item === 'string') {
|
|
182
|
-
console.log(item);
|
|
206
|
+
console.log(`${prefix}${item}`);
|
|
183
207
|
}
|
|
184
208
|
}
|
|
185
|
-
continue;
|
|
186
209
|
}
|
|
187
|
-
|
|
210
|
+
else {
|
|
211
|
+
console.log(`${prefix}${JSON.stringify(line)}`);
|
|
212
|
+
}
|
|
213
|
+
if (line.level === 'error' && typeof line.error_code === 'string') {
|
|
214
|
+
const info = getErrorCodeInfo(line.error_code);
|
|
215
|
+
console.log(`${prefix} Type: ${info.label}`);
|
|
216
|
+
console.log(`${prefix} Hint: ${info.hint}`);
|
|
217
|
+
}
|
|
188
218
|
}
|
|
189
219
|
}
|
|
190
220
|
async function handleArtifacts(positionals, flags, context, json) {
|
|
@@ -255,17 +285,22 @@ async function handleDiagnose(positionals, flags, context, json) {
|
|
|
255
285
|
const line = entry.line;
|
|
256
286
|
if (typeof line.message === 'string') {
|
|
257
287
|
console.log(line.message);
|
|
258
|
-
continue;
|
|
259
288
|
}
|
|
260
|
-
if (Array.isArray(line.lines)) {
|
|
289
|
+
else if (Array.isArray(line.lines)) {
|
|
261
290
|
for (const item of line.lines) {
|
|
262
291
|
if (typeof item === 'string') {
|
|
263
292
|
console.log(item);
|
|
264
293
|
}
|
|
265
294
|
}
|
|
266
|
-
continue;
|
|
267
295
|
}
|
|
268
|
-
|
|
296
|
+
else {
|
|
297
|
+
console.log(JSON.stringify(line));
|
|
298
|
+
}
|
|
299
|
+
if (line.level === 'error' && typeof line.error_code === 'string') {
|
|
300
|
+
const info = getErrorCodeInfo(line.error_code);
|
|
301
|
+
console.log(` Type: ${info.label}`);
|
|
302
|
+
console.log(` Hint: ${info.hint}`);
|
|
303
|
+
}
|
|
269
304
|
}
|
|
270
305
|
}
|
|
271
306
|
else {
|
|
@@ -320,6 +355,11 @@ function formatRunList(runs) {
|
|
|
320
355
|
if (run.error_message) {
|
|
321
356
|
console.log(` Error: ${run.error_message}`);
|
|
322
357
|
}
|
|
358
|
+
if (run.error_code) {
|
|
359
|
+
const info = getErrorCodeInfo(run.error_code);
|
|
360
|
+
console.log(` Error Type: ${info.label}`);
|
|
361
|
+
console.log(` Hint: ${info.hint}`);
|
|
362
|
+
}
|
|
323
363
|
}
|
|
324
364
|
console.log('');
|
|
325
365
|
console.log(`Total: ${runs.length} runs`);
|
package/dist/commands/env.js
CHANGED
|
@@ -267,11 +267,22 @@ async function handleDeploy(positionals, flags, context, json) {
|
|
|
267
267
|
else {
|
|
268
268
|
if (response.pipeline_run) {
|
|
269
269
|
console.log('');
|
|
270
|
-
console.log('Pipeline deployment
|
|
270
|
+
console.log('Pipeline deployment started.');
|
|
271
271
|
console.log(` Pipeline Run: ${response.pipeline_run.run.id}`);
|
|
272
272
|
console.log(` Pipeline: ${response.pipeline_run.run.pipeline_name}`);
|
|
273
273
|
console.log(` Status: ${response.pipeline_run.run.status}`);
|
|
274
274
|
console.log(` Environment: ${response.environment.name}`);
|
|
275
|
+
const watchFlag = (0, args_1.toBoolean)(flags.watch);
|
|
276
|
+
const shouldWatch = watchFlag ?? true; // default: watch
|
|
277
|
+
if (shouldWatch) {
|
|
278
|
+
const timeoutRaw = (0, args_1.getStringFlag)(flags, ['timeout']);
|
|
279
|
+
const timeoutSeconds = timeoutRaw ? parseInt(timeoutRaw, 10) : 300; // 5 min default for pipeline
|
|
280
|
+
const pipelineResult = await watchPipelineRun(context, projectId, response.pipeline_run.run.pipeline_name, response.pipeline_run.run.id, Number.isFinite(timeoutSeconds) ? timeoutSeconds : 300);
|
|
281
|
+
// After pipeline completes, watch deployment health if it succeeded
|
|
282
|
+
if (pipelineResult === 'succeeded') {
|
|
283
|
+
await watchDeploymentStatus(context, projectId, envName, 120);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
275
286
|
return;
|
|
276
287
|
}
|
|
277
288
|
console.log('');
|
|
@@ -603,6 +614,47 @@ function getDeploymentWarnings(status) {
|
|
|
603
614
|
}
|
|
604
615
|
return Array.from(new Set(warnings));
|
|
605
616
|
}
|
|
617
|
+
/**
|
|
618
|
+
* Poll a pipeline run until it reaches a terminal status.
|
|
619
|
+
* Returns the final status string.
|
|
620
|
+
*/
|
|
621
|
+
async function watchPipelineRun(context, projectId, pipelineName, runId, timeoutSeconds) {
|
|
622
|
+
const start = Date.now();
|
|
623
|
+
const pollIntervalMs = 3000;
|
|
624
|
+
const terminalStatuses = ['succeeded', 'failed', 'cancelled'];
|
|
625
|
+
console.log('');
|
|
626
|
+
console.log('Watching pipeline run...');
|
|
627
|
+
while ((Date.now() - start) / 1000 < timeoutSeconds) {
|
|
628
|
+
const detail = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines/${pipelineName}/runs/${runId}`);
|
|
629
|
+
const elapsed = Math.floor((Date.now() - start) / 1000);
|
|
630
|
+
const stepSummary = detail.steps
|
|
631
|
+
.map(s => `${s.step_name}:${s.status}`)
|
|
632
|
+
.join(', ');
|
|
633
|
+
console.log(` [${elapsed}s] ${detail.run.status} (${stepSummary || 'no steps'})`);
|
|
634
|
+
if (terminalStatuses.includes(detail.run.status)) {
|
|
635
|
+
if (detail.run.status === 'succeeded') {
|
|
636
|
+
console.log(' Pipeline run succeeded.');
|
|
637
|
+
}
|
|
638
|
+
else if (detail.run.status === 'failed') {
|
|
639
|
+
console.log(` Pipeline run failed.`);
|
|
640
|
+
// Show error from failed steps
|
|
641
|
+
for (const step of detail.steps) {
|
|
642
|
+
if (step.status === 'failed') {
|
|
643
|
+
console.log(` Step "${step.step_name}" failed.`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
console.log(` Pipeline run ${detail.run.status}.`);
|
|
649
|
+
}
|
|
650
|
+
return detail.run.status;
|
|
651
|
+
}
|
|
652
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
653
|
+
}
|
|
654
|
+
console.log(` Pipeline run did not complete within ${timeoutSeconds}s.`);
|
|
655
|
+
console.log(` Run "eve pipeline show-run ${pipelineName} ${runId}" to check status.`);
|
|
656
|
+
return 'timeout';
|
|
657
|
+
}
|
|
606
658
|
async function watchDeploymentStatus(context, projectId, envName, timeoutSeconds) {
|
|
607
659
|
const start = Date.now();
|
|
608
660
|
const pollIntervalMs = 3000;
|
|
@@ -35,7 +35,8 @@ async function handlePipeline(subcommand, positionals, flags, context) {
|
|
|
35
35
|
' show-run <pipeline> <run-id> - show pipeline run status and steps\n' +
|
|
36
36
|
' approve <run-id> - approve a blocked pipeline run\n' +
|
|
37
37
|
' cancel <run-id> [--reason <text>] - cancel pipeline run\n' +
|
|
38
|
-
' logs <pipeline> <run-id> [--step <name>] - show logs for pipeline run'
|
|
38
|
+
' logs <pipeline> <run-id> [--step <name>] - show logs for pipeline run\n' +
|
|
39
|
+
' Options: --follow (-f) stream live');
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
async function handleList(positionals, flags, context, json) {
|
|
@@ -150,6 +151,24 @@ function formatPipelineRunDetail(detail) {
|
|
|
150
151
|
if (step.error_message) {
|
|
151
152
|
console.log(` Error: ${step.error_message}`);
|
|
152
153
|
}
|
|
154
|
+
// Task 3.1: Show structured error code info when available
|
|
155
|
+
const errorCode = step.error_code;
|
|
156
|
+
if (errorCode) {
|
|
157
|
+
const info = getErrorCodeInfo(errorCode);
|
|
158
|
+
console.log(` Type: ${info.label}`);
|
|
159
|
+
console.log(` Hint: ${info.hint}`);
|
|
160
|
+
}
|
|
161
|
+
// Task 2.4: Surface build_id hints on failure
|
|
162
|
+
if (step.status === 'failed' && step.step_type === 'build') {
|
|
163
|
+
const buildId = step.output_json?.build_id
|
|
164
|
+
?? step.result_json?.build_id;
|
|
165
|
+
if (buildId) {
|
|
166
|
+
console.log(` Hint: Run 'eve build diagnose ${buildId}' for full build details`);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
console.log(` Hint: Run 'eve build diagnose' with the build ID for details`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
153
172
|
}
|
|
154
173
|
console.log('');
|
|
155
174
|
console.log(`Total: ${steps.length} steps`);
|
|
@@ -326,7 +345,11 @@ async function handleLogs(positionals, flags, context, json) {
|
|
|
326
345
|
const stepName = (0, args_1.getStringFlag)(flags, ['step']);
|
|
327
346
|
const projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
328
347
|
if (!pipelineName || !runId || !projectId) {
|
|
329
|
-
throw new Error('Usage: eve pipeline logs <pipeline_name> <run-id> [--step <step_name>] [--project <id>]');
|
|
348
|
+
throw new Error('Usage: eve pipeline logs <pipeline_name> <run-id> [--step <step_name>] [--follow] [--project <id>]');
|
|
349
|
+
}
|
|
350
|
+
const follow = Boolean(flags.follow) || Boolean(flags.f);
|
|
351
|
+
if (follow) {
|
|
352
|
+
return handlePipelineFollow(context, pipelineName, runId, stepName ?? null);
|
|
330
353
|
}
|
|
331
354
|
// First get the run details to know which steps exist
|
|
332
355
|
const runDetail = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines/${pipelineName}/runs/${runId}`);
|
|
@@ -367,6 +390,24 @@ async function handleLogs(positionals, flags, context, json) {
|
|
|
367
390
|
if (step.error_message) {
|
|
368
391
|
console.log(`Error: ${step.error_message}`);
|
|
369
392
|
}
|
|
393
|
+
// Show structured error code info when available
|
|
394
|
+
const errorCode = step.error_code;
|
|
395
|
+
if (errorCode) {
|
|
396
|
+
const info = getErrorCodeInfo(errorCode);
|
|
397
|
+
console.log(`Type: ${info.label}`);
|
|
398
|
+
console.log(`Hint: ${info.hint}`);
|
|
399
|
+
}
|
|
400
|
+
// Surface build_id hints on failure
|
|
401
|
+
if (step.status === 'failed' && step.step_type === 'build') {
|
|
402
|
+
const buildId = step.output_json?.build_id
|
|
403
|
+
?? step.result_json?.build_id;
|
|
404
|
+
if (buildId) {
|
|
405
|
+
console.log(`Hint: Run 'eve build diagnose ${buildId}' for full build details`);
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
console.log(`Hint: Run 'eve build diagnose' with the build ID for details`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
370
411
|
if (step.result_text) {
|
|
371
412
|
console.log('');
|
|
372
413
|
console.log('Result:');
|
|
@@ -384,6 +425,158 @@ async function handleLogs(positionals, flags, context, json) {
|
|
|
384
425
|
if (!stepName) {
|
|
385
426
|
console.log(`Total steps: ${stepsToShow.length}`);
|
|
386
427
|
}
|
|
428
|
+
// Fetch actual logs from the REST endpoint
|
|
429
|
+
const logsUrl = stepName
|
|
430
|
+
? `/pipeline-runs/${runId}/logs?step=${encodeURIComponent(stepName)}`
|
|
431
|
+
: `/pipeline-runs/${runId}/logs`;
|
|
432
|
+
try {
|
|
433
|
+
const logsResp = await (0, client_1.requestJson)(context, logsUrl);
|
|
434
|
+
if (logsResp?.logs && Array.isArray(logsResp.logs) && logsResp.logs.length > 0) {
|
|
435
|
+
console.log('\n--- Logs ---');
|
|
436
|
+
for (const entry of logsResp.logs) {
|
|
437
|
+
const ts = entry.timestamp ? formatPipelineTime(entry.timestamp) : '';
|
|
438
|
+
const step = entry.step_name ? `[${entry.step_name}] ` : '';
|
|
439
|
+
const content = entry.content ?? {};
|
|
440
|
+
if (content.message) {
|
|
441
|
+
console.log(`${ts}${step}${content.message}`);
|
|
442
|
+
}
|
|
443
|
+
else if (content.lines && Array.isArray(content.lines)) {
|
|
444
|
+
for (const line of content.lines) {
|
|
445
|
+
console.log(`${ts}${step}${line}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
// Logs endpoint may not exist yet; silently skip
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function handlePipelineFollow(context, pipelineName, runId, stepFilter) {
|
|
456
|
+
const endpoint = stepFilter
|
|
457
|
+
? `${context.apiUrl}/pipeline-runs/${runId}/steps/${encodeURIComponent(stepFilter)}/stream`
|
|
458
|
+
: `${context.apiUrl}/pipeline-runs/${runId}/stream`;
|
|
459
|
+
console.log(`Following pipeline run ${runId}...`);
|
|
460
|
+
const headers = {
|
|
461
|
+
Accept: 'text/event-stream',
|
|
462
|
+
};
|
|
463
|
+
if (context.token) {
|
|
464
|
+
headers.Authorization = `Bearer ${context.token}`;
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
const response = await fetch(endpoint, { headers });
|
|
468
|
+
if (!response.ok) {
|
|
469
|
+
const text = await response.text();
|
|
470
|
+
throw new Error(`HTTP ${response.status}: ${text}`);
|
|
471
|
+
}
|
|
472
|
+
if (!response.body) {
|
|
473
|
+
throw new Error('No response body received');
|
|
474
|
+
}
|
|
475
|
+
const reader = response.body.getReader();
|
|
476
|
+
const decoder = new TextDecoder();
|
|
477
|
+
let buffer = '';
|
|
478
|
+
while (true) {
|
|
479
|
+
const { done, value } = await reader.read();
|
|
480
|
+
if (done)
|
|
481
|
+
break;
|
|
482
|
+
buffer += decoder.decode(value, { stream: true });
|
|
483
|
+
const lines = buffer.split('\n');
|
|
484
|
+
buffer = lines.pop() ?? '';
|
|
485
|
+
let currentEvent = '';
|
|
486
|
+
let currentData = '';
|
|
487
|
+
for (const line of lines) {
|
|
488
|
+
if (line.startsWith('event:')) {
|
|
489
|
+
currentEvent = line.slice(6).trim();
|
|
490
|
+
}
|
|
491
|
+
else if (line.startsWith('data:')) {
|
|
492
|
+
currentData = line.slice(5).trim();
|
|
493
|
+
}
|
|
494
|
+
else if (line === '' && currentData) {
|
|
495
|
+
processPipelineSSEEvent(currentEvent, currentData);
|
|
496
|
+
currentEvent = '';
|
|
497
|
+
currentData = '';
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
// Process any remaining data in buffer
|
|
502
|
+
if (buffer.trim()) {
|
|
503
|
+
const remainingLines = buffer.split('\n');
|
|
504
|
+
let currentEvent = '';
|
|
505
|
+
let currentData = '';
|
|
506
|
+
for (const line of remainingLines) {
|
|
507
|
+
if (line.startsWith('event:')) {
|
|
508
|
+
currentEvent = line.slice(6).trim();
|
|
509
|
+
}
|
|
510
|
+
else if (line.startsWith('data:')) {
|
|
511
|
+
currentData = line.slice(5).trim();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (currentData) {
|
|
515
|
+
processPipelineSSEEvent(currentEvent, currentData);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
console.log('');
|
|
519
|
+
console.log('Stream ended.');
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
const err = error;
|
|
523
|
+
console.error(`Error following pipeline run: ${err.message}`);
|
|
524
|
+
process.exit(1);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
function processPipelineSSEEvent(eventType, dataStr) {
|
|
528
|
+
try {
|
|
529
|
+
const data = JSON.parse(dataStr);
|
|
530
|
+
if (eventType === 'log') {
|
|
531
|
+
const stepName = data.step_name ?? '???';
|
|
532
|
+
const content = data.line ?? {};
|
|
533
|
+
const timestamp = data.timestamp;
|
|
534
|
+
const timeStr = timestamp ? formatPipelineTime(timestamp) : '';
|
|
535
|
+
if (content.message) {
|
|
536
|
+
console.log(`${timeStr}[${stepName}] ${content.message}`);
|
|
537
|
+
}
|
|
538
|
+
else if (content.lines && Array.isArray(content.lines)) {
|
|
539
|
+
for (const l of content.lines) {
|
|
540
|
+
console.log(`${timeStr}[${stepName}] ${l}`);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
console.log(`${timeStr}[${stepName}] ${JSON.stringify(content)}`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
else if (eventType === 'complete') {
|
|
548
|
+
console.log(`\nPipeline run completed: ${data.status}`);
|
|
549
|
+
}
|
|
550
|
+
else if (eventType === 'error') {
|
|
551
|
+
console.error(`\nPipeline run failed: ${data.errorMessage ?? data.status}`);
|
|
552
|
+
process.exit(1);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
catch {
|
|
556
|
+
// Ignore malformed events
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function formatPipelineTime(timestamp) {
|
|
560
|
+
try {
|
|
561
|
+
const d = new Date(timestamp);
|
|
562
|
+
return `[${d.toLocaleTimeString('en-US', { hour12: false })}] `;
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
return '';
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
const ERROR_CODES = {
|
|
569
|
+
auth_error: { code: 'auth_error', label: 'Authentication Error', hint: "Check GITHUB_TOKEN via 'eve secrets set'" },
|
|
570
|
+
clone_error: { code: 'clone_error', label: 'Git Clone Error', hint: "Verify repo URL and access. Check 'eve secrets list'" },
|
|
571
|
+
build_error: { code: 'build_error', label: 'Build Error', hint: "Run 'eve build diagnose <build_id>' for full output" },
|
|
572
|
+
timeout_error: { code: 'timeout_error', label: 'Timeout Error', hint: 'Consider increasing timeout or checking resources' },
|
|
573
|
+
resource_error: { code: 'resource_error', label: 'Resource Error', hint: 'Check disk space and memory on build worker' },
|
|
574
|
+
registry_error: { code: 'registry_error', label: 'Registry Error', hint: "Check registry credentials via 'eve secrets list'" },
|
|
575
|
+
deploy_error: { code: 'deploy_error', label: 'Deploy Error', hint: "Run 'eve env diagnose <project> <env>'" },
|
|
576
|
+
unknown_error: { code: 'unknown_error', label: 'Unknown Error', hint: "Run 'eve build diagnose <build_id>' or 'eve job diagnose <job_id>'" },
|
|
577
|
+
};
|
|
578
|
+
function getErrorCodeInfo(code) {
|
|
579
|
+
return ERROR_CODES[code] ?? ERROR_CODES.unknown_error;
|
|
387
580
|
}
|
|
388
581
|
function buildQuery(params) {
|
|
389
582
|
const search = new URLSearchParams();
|
package/dist/lib/help.js
CHANGED
|
@@ -991,8 +991,22 @@ for cloud deployments. Credentials are stored per-profile.`,
|
|
|
991
991
|
usage: 'eve pipeline cancel <run-id> [--reason <text>]',
|
|
992
992
|
examples: ['eve pipeline cancel prun_xxx --reason "superseded"'],
|
|
993
993
|
},
|
|
994
|
+
logs: {
|
|
995
|
+
description: 'Show logs for a pipeline run',
|
|
996
|
+
usage: 'eve pipeline logs <pipeline> <run-id> [--step <name>] [--follow]',
|
|
997
|
+
options: [
|
|
998
|
+
'--step <name> Show logs for a specific step only',
|
|
999
|
+
'--follow (-f) Stream live logs via SSE',
|
|
1000
|
+
'--project <id> Project ID (uses profile default)',
|
|
1001
|
+
],
|
|
1002
|
+
examples: [
|
|
1003
|
+
'eve pipeline logs deploy-test prun_xxx',
|
|
1004
|
+
'eve pipeline logs deploy-test prun_xxx --step build',
|
|
1005
|
+
'eve pipeline logs deploy-test prun_xxx --follow',
|
|
1006
|
+
],
|
|
1007
|
+
},
|
|
994
1008
|
},
|
|
995
|
-
examples: ['eve pipeline list', 'eve pipeline run deploy-test --ref abc123 --env test'],
|
|
1009
|
+
examples: ['eve pipeline list', 'eve pipeline run deploy-test --ref abc123 --env test', 'eve pipeline logs deploy-test prun_xxx --follow'],
|
|
996
1010
|
},
|
|
997
1011
|
workflow: {
|
|
998
1012
|
description: 'Inspect workflows defined in the project manifest (read-only in Phase 1).',
|