@eve-horizon/cli 0.2.12 → 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,629 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handlePipeline = handlePipeline;
4
- const args_1 = require("../lib/args");
5
- const client_1 = require("../lib/client");
6
- const output_1 = require("../lib/output");
7
- const git_js_1 = require("../lib/git.js");
8
- async function handlePipeline(subcommand, positionals, flags, context) {
9
- const json = Boolean(flags.json);
10
- switch (subcommand) {
11
- case 'list':
12
- return handleList(positionals, flags, context, json);
13
- case 'show':
14
- return handleShow(positionals, flags, context, json);
15
- case 'run':
16
- return handleRun(positionals, flags, context, json);
17
- case 'runs':
18
- return handleRuns(positionals, flags, context, json);
19
- case 'show-run':
20
- return handleShowRun(positionals, flags, context, json);
21
- case 'approve':
22
- return handleApprove(positionals, flags, context, json);
23
- case 'cancel':
24
- return handleCancel(positionals, flags, context, json);
25
- case 'logs':
26
- return handleLogs(positionals, flags, context, json);
27
- default:
28
- throw new Error('Usage: eve pipeline <list|show|run|runs|show-run|approve|cancel|logs>\n' +
29
- ' list [project] - list pipelines for a project\n' +
30
- ' show <project> <name> - show pipeline definition\n' +
31
- ' run <name> --ref <sha> - create and run a new pipeline\n' +
32
- ' Options: --env, --inputs <json>, --only <step>\n' +
33
- ' runs [project] - list recent pipeline runs\n' +
34
- ' Options: --limit, --status, --name <pipeline>\n' +
35
- ' show-run <pipeline> <run-id> - show pipeline run status and steps\n' +
36
- ' approve <run-id> - approve a blocked pipeline run\n' +
37
- ' cancel <run-id> [--reason <text>] - cancel pipeline run\n' +
38
- ' logs <pipeline> <run-id> [--step <name>] - show logs for pipeline run\n' +
39
- ' Options: --follow (-f) stream live');
40
- }
41
- }
42
- async function handleList(positionals, flags, context, json) {
43
- const projectId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
44
- if (!projectId) {
45
- throw new Error('Usage: eve pipeline list [project] [--project=<id>]');
46
- }
47
- const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines`);
48
- if (json) {
49
- (0, output_1.outputJson)(response, json);
50
- return;
51
- }
52
- if (response.data.length === 0) {
53
- console.log('No pipelines found.');
54
- return;
55
- }
56
- formatPipelines(response.data);
57
- }
58
- async function handleShow(positionals, flags, context, json) {
59
- const projectId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
60
- const name = positionals[1] ?? (0, args_1.getStringFlag)(flags, ['name']);
61
- if (!projectId || !name) {
62
- throw new Error('Usage: eve pipeline show <project> <name> [--project=<id>] [--name=<name>]');
63
- }
64
- const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines/${name}`);
65
- if (json) {
66
- (0, output_1.outputJson)(response, json);
67
- return;
68
- }
69
- formatPipeline(response);
70
- }
71
- function formatPipelines(pipelines) {
72
- console.log('Pipelines:');
73
- for (const pipeline of pipelines) {
74
- const stepCount = Array.isArray(pipeline.definition?.steps)
75
- ? pipeline.definition.steps.length
76
- : null;
77
- const suffix = stepCount === null ? '' : ` (${stepCount} steps)`;
78
- console.log(`- ${pipeline.name}${suffix}`);
79
- }
80
- }
81
- function formatPipeline(pipeline) {
82
- console.log(`Pipeline: ${pipeline.name}`);
83
- console.log('Definition:');
84
- console.log(JSON.stringify(pipeline.definition, null, 2));
85
- }
86
- function formatPipelineRunList(runs) {
87
- console.log('Recent pipeline runs:');
88
- console.log('');
89
- // Table header
90
- console.log('Run ID'.padEnd(30) + 'Pipeline'.padEnd(20) + 'Status'.padEnd(20) + 'Created');
91
- console.log('-'.repeat(100));
92
- for (const run of runs) {
93
- const runId = run.id.padEnd(30);
94
- const pipeline = run.pipeline_name.padEnd(20);
95
- const status = run.status.padEnd(20);
96
- const created = new Date(run.created_at).toLocaleString();
97
- console.log(`${runId}${pipeline}${status}${created}`);
98
- }
99
- console.log('');
100
- console.log(`Total: ${runs.length} runs`);
101
- }
102
- function formatPipelineRunDetail(detail) {
103
- const { run, steps } = detail;
104
- console.log(`Run ID: ${run.id}`);
105
- console.log(`Pipeline: ${run.pipeline_name}`);
106
- console.log(`Status: ${run.status}`);
107
- if (run.env_name) {
108
- console.log(`Environment: ${run.env_name}`);
109
- }
110
- if (run.git_sha) {
111
- console.log(`Git SHA: ${run.git_sha}`);
112
- }
113
- // Display preview URL if present in step_outputs
114
- if ('step_outputs' in run && run.step_outputs) {
115
- const deployOutput = run.step_outputs.deploy;
116
- if (deployOutput?.preview_url) {
117
- console.log(`Preview: ${deployOutput.preview_url}`);
118
- }
119
- }
120
- if (run.started_at) {
121
- console.log(`Started: ${run.started_at}`);
122
- }
123
- if (run.completed_at) {
124
- console.log(`Completed: ${run.completed_at}`);
125
- }
126
- if (run.error_message) {
127
- console.log(`Error: ${run.error_message}`);
128
- }
129
- console.log('');
130
- console.log('Steps:');
131
- console.log('');
132
- if (steps.length === 0) {
133
- console.log('No steps found.');
134
- return;
135
- }
136
- // Table header
137
- console.log('Step'.padEnd(25) + 'Type'.padEnd(12) + 'Status'.padEnd(15) + 'Duration');
138
- console.log('-'.repeat(80));
139
- for (const step of steps) {
140
- const name = step.step_name.padEnd(25);
141
- const type = step.step_type.padEnd(12);
142
- const status = step.status.padEnd(15);
143
- let duration = '-';
144
- if (step.duration_ms !== null) {
145
- duration = `${step.duration_ms}ms`;
146
- }
147
- else if (step.started_at && !step.completed_at) {
148
- duration = 'running...';
149
- }
150
- console.log(`${name}${type}${status}${duration}`);
151
- if (step.error_message) {
152
- console.log(` Error: ${step.error_message}`);
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
- }
172
- }
173
- console.log('');
174
- console.log(`Total: ${steps.length} steps`);
175
- }
176
- async function handleRun(positionals, flags, context, json) {
177
- const pipelineName = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['name']);
178
- const projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
179
- const env = (0, args_1.getStringFlag)(flags, ['env']);
180
- const ref = (0, args_1.getStringFlag)(flags, ['ref']);
181
- const only = (0, args_1.getStringFlag)(flags, ['only']);
182
- const wait = Boolean(flags.wait);
183
- const timeout = (0, args_1.getStringFlag)(flags, ['timeout']);
184
- const inputsRaw = (0, args_1.getStringFlag)(flags, ['inputs']);
185
- const repoDir = (0, args_1.getStringFlag)(flags, ['repo-dir', 'repo_dir', 'dir']);
186
- if (!pipelineName || !projectId || !ref) {
187
- throw new Error('Usage: eve pipeline run <name> --ref <sha> [--env <env>] [--project <id>] [--repo-dir <path>] [--wait] [--inputs <json>] [--only <step>]');
188
- }
189
- // Resolve git ref to actual 40-char SHA
190
- const gitSha = await (0, git_js_1.resolveGitRef)(context, projectId, ref, repoDir);
191
- if (!json && ref !== gitSha) {
192
- console.log(`Resolved ref '${ref}' → ${gitSha.substring(0, 8)}...`);
193
- }
194
- let inputs;
195
- if (inputsRaw) {
196
- try {
197
- inputs = JSON.parse(inputsRaw);
198
- }
199
- catch (error) {
200
- throw new Error(`Invalid JSON for --inputs: ${error instanceof Error ? error.message : 'unknown error'}`);
201
- }
202
- }
203
- // Emit event before creating the pipeline run
204
- await emitPipelineRunEvent(context, projectId, pipelineName, { env, ref: gitSha, inputs });
205
- if (only) {
206
- const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines/${pipelineName}/runs`, {
207
- method: 'POST',
208
- body: { git_sha: gitSha, env_name: env, inputs, only },
209
- });
210
- if (json) {
211
- (0, output_1.outputJson)(response, json);
212
- return;
213
- }
214
- console.log('Pipeline run created (job graph).');
215
- console.log(`Run ID: ${response.run.id}`);
216
- console.log(`Jobs: ${response.jobs.length}`);
217
- for (const job of response.jobs) {
218
- const name = job.step_name ?? job.id;
219
- console.log(`- ${name} (${job.execution_type}) [${job.phase}]`);
220
- }
221
- return;
222
- }
223
- const query = new URLSearchParams();
224
- if (wait)
225
- query.set('wait', 'true');
226
- if (timeout)
227
- query.set('timeout', timeout);
228
- const queryString = query.toString();
229
- const url = `/projects/${projectId}/pipelines/${pipelineName}/run${queryString ? `?${queryString}` : ''}`;
230
- const response = await (0, client_1.requestJson)(context, url, {
231
- method: 'POST',
232
- body: { ref: gitSha, env, inputs },
233
- });
234
- if (json) {
235
- (0, output_1.outputJson)(response, json);
236
- return;
237
- }
238
- console.log('Pipeline run created.');
239
- console.log('');
240
- formatPipelineRunDetail(response);
241
- }
242
- async function handleRuns(positionals, flags, context, json) {
243
- // Support both: eve pipeline runs [project] OR eve pipeline runs <pipeline_name> [project]
244
- // If first arg looks like a project ID, treat as project filter
245
- // Otherwise treat as pipeline name for backward compat
246
- const firstArg = positionals[0];
247
- const secondArg = positionals[1];
248
- let projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
249
- let pipelineName = (0, args_1.getStringFlag)(flags, ['name']);
250
- // Determine if first arg is project or pipeline name
251
- if (firstArg) {
252
- if (firstArg.startsWith('proj_') || firstArg.startsWith('org_')) {
253
- projectId = firstArg;
254
- }
255
- else {
256
- pipelineName = firstArg;
257
- if (secondArg) {
258
- projectId = secondArg;
259
- }
260
- }
261
- }
262
- if (!projectId) {
263
- throw new Error('Usage: eve pipeline runs [project] [--project <id>] [--name <pipeline>] [--limit N] [--status <status>]');
264
- }
265
- const query = buildQuery({
266
- limit: (0, args_1.getStringFlag)(flags, ['limit']),
267
- offset: (0, args_1.getStringFlag)(flags, ['offset']),
268
- status: (0, args_1.getStringFlag)(flags, ['status']),
269
- });
270
- // If pipeline name specified, use per-pipeline endpoint
271
- // Otherwise list all runs for the project (when that endpoint exists)
272
- const url = pipelineName
273
- ? `/projects/${projectId}/pipelines/${pipelineName}/runs${query}`
274
- : `/projects/${projectId}/pipelines/${pipelineName || '__all'}/runs${query}`;
275
- const response = await (0, client_1.requestJson)(context, url);
276
- if (json) {
277
- (0, output_1.outputJson)(response, json);
278
- return;
279
- }
280
- if (response.data.length === 0) {
281
- console.log('No pipeline runs found.');
282
- return;
283
- }
284
- formatPipelineRunList(response.data);
285
- }
286
- async function handleShowRun(positionals, flags, context, json) {
287
- // Signature: eve pipeline show-run <pipeline_name> <run-id>
288
- const pipelineName = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['name']);
289
- const runId = positionals[1] ?? (0, args_1.getStringFlag)(flags, ['run']);
290
- const projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
291
- if (!pipelineName || !runId || !projectId) {
292
- throw new Error('Usage: eve pipeline show-run <pipeline_name> <run-id> [--project <id>]');
293
- }
294
- const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines/${pipelineName}/runs/${runId}`);
295
- if (json) {
296
- (0, output_1.outputJson)(response, json);
297
- return;
298
- }
299
- formatPipelineRunDetail(response);
300
- }
301
- async function handleApprove(positionals, flags, context, json) {
302
- const runId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['run']);
303
- if (!runId) {
304
- throw new Error('Usage: eve pipeline approve <run-id>');
305
- }
306
- const response = await (0, client_1.requestJson)(context, `/pipeline-runs/${runId}/approve`, { method: 'POST' });
307
- if (json) {
308
- (0, output_1.outputJson)(response, json);
309
- return;
310
- }
311
- console.log(`Approved pipeline run ${runId}.`);
312
- console.log('');
313
- formatPipelineRunDetail(response);
314
- }
315
- async function handleCancel(positionals, flags, context, json) {
316
- const runId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['run']);
317
- const reason = (0, args_1.getStringFlag)(flags, ['reason']);
318
- if (!runId) {
319
- throw new Error('Usage: eve pipeline cancel <run-id> [--reason <text>]');
320
- }
321
- const response = await (0, client_1.requestJson)(context, `/pipeline-runs/${runId}/cancel`, {
322
- method: 'POST',
323
- body: reason ? { reason } : {},
324
- });
325
- if (json) {
326
- (0, output_1.outputJson)(response, json);
327
- return;
328
- }
329
- console.log(`Cancelled pipeline run ${runId}.`);
330
- console.log('');
331
- formatPipelineRunDetail(response);
332
- }
333
- async function handleLogs(positionals, flags, context, json) {
334
- const pipelineName = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['name']);
335
- const runId = positionals[1] ?? (0, args_1.getStringFlag)(flags, ['run']);
336
- const stepName = (0, args_1.getStringFlag)(flags, ['step']);
337
- const projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
338
- if (!pipelineName || !runId || !projectId) {
339
- throw new Error('Usage: eve pipeline logs <pipeline_name> <run-id> [--step <step_name>] [--follow] [--project <id>]');
340
- }
341
- const follow = Boolean(flags.follow) || Boolean(flags.f);
342
- if (follow) {
343
- return handlePipelineFollow(context, pipelineName, runId, stepName ?? null);
344
- }
345
- // First get the run details to know which steps exist
346
- const runDetail = await (0, client_1.requestJson)(context, `/projects/${projectId}/pipelines/${pipelineName}/runs/${runId}`);
347
- if (json) {
348
- (0, output_1.outputJson)(runDetail, json);
349
- return;
350
- }
351
- console.log(`Pipeline run: ${runDetail.run.id}`);
352
- console.log(`Pipeline: ${runDetail.run.pipeline_name}`);
353
- console.log(`Status: ${runDetail.run.status}`);
354
- console.log('');
355
- // Filter steps if specific step requested
356
- const stepsToShow = stepName
357
- ? runDetail.steps.filter(s => s.step_name === stepName)
358
- : runDetail.steps;
359
- if (stepsToShow.length === 0) {
360
- if (stepName) {
361
- console.log(`No step found with name: ${stepName}`);
362
- }
363
- else {
364
- console.log('No steps found for this pipeline run.');
365
- }
366
- return;
367
- }
368
- // Show logs for each step
369
- for (const step of stepsToShow) {
370
- console.log(`Step: ${step.step_name} (${step.step_type})`);
371
- console.log(`Status: ${step.status}`);
372
- if (step.started_at) {
373
- console.log(`Started: ${step.started_at}`);
374
- }
375
- if (step.completed_at) {
376
- console.log(`Completed: ${step.completed_at}`);
377
- }
378
- if (step.duration_ms !== null) {
379
- console.log(`Duration: ${step.duration_ms}ms`);
380
- }
381
- if (step.error_message) {
382
- console.log(`Error: ${step.error_message}`);
383
- }
384
- // Show structured error code info when available
385
- const errorCode = step.error_code;
386
- if (errorCode) {
387
- const info = getErrorCodeInfo(errorCode);
388
- console.log(`Type: ${info.label}`);
389
- console.log(`Hint: ${info.hint}`);
390
- }
391
- // Surface build_id hints on failure
392
- if (step.status === 'failed' && step.step_type === 'build') {
393
- const buildId = step.output_json?.build_id
394
- ?? step.result_json?.build_id;
395
- if (buildId) {
396
- console.log(`Hint: Run 'eve build diagnose ${buildId}' for full build details`);
397
- }
398
- else {
399
- console.log(`Hint: Run 'eve build diagnose' with the build ID for details`);
400
- }
401
- }
402
- if (step.result_text) {
403
- console.log('');
404
- console.log('Result:');
405
- console.log(step.result_text);
406
- }
407
- if (step.result_json) {
408
- console.log('');
409
- console.log('Result JSON:');
410
- console.log(JSON.stringify(step.result_json, null, 2));
411
- }
412
- console.log('');
413
- console.log('---');
414
- console.log('');
415
- }
416
- if (!stepName) {
417
- console.log(`Total steps: ${stepsToShow.length}`);
418
- }
419
- // Fetch actual logs from the REST endpoint
420
- const logsUrl = stepName
421
- ? `/pipeline-runs/${runId}/logs?step=${encodeURIComponent(stepName)}`
422
- : `/pipeline-runs/${runId}/logs`;
423
- try {
424
- const logsResp = await (0, client_1.requestJson)(context, logsUrl);
425
- if (logsResp?.logs && Array.isArray(logsResp.logs) && logsResp.logs.length > 0) {
426
- console.log('\n--- Logs ---');
427
- for (const entry of logsResp.logs) {
428
- const ts = entry.timestamp ? formatPipelineTime(entry.timestamp) : '';
429
- const step = entry.step_name ? `[${entry.step_name}] ` : '';
430
- const content = entry.content ?? {};
431
- if (content.message) {
432
- console.log(`${ts}${step}${content.message}`);
433
- }
434
- else if (content.lines && Array.isArray(content.lines)) {
435
- for (const line of content.lines) {
436
- console.log(`${ts}${step}${line}`);
437
- }
438
- }
439
- }
440
- }
441
- }
442
- catch {
443
- // Logs endpoint may not exist yet; silently skip
444
- }
445
- }
446
- async function handlePipelineFollow(context, pipelineName, runId, stepFilter) {
447
- const endpoint = stepFilter
448
- ? `${context.apiUrl}/pipeline-runs/${runId}/steps/${encodeURIComponent(stepFilter)}/stream`
449
- : `${context.apiUrl}/pipeline-runs/${runId}/stream`;
450
- console.log(`Following pipeline run ${runId}...`);
451
- const headers = {
452
- Accept: 'text/event-stream',
453
- };
454
- if (context.token) {
455
- headers.Authorization = `Bearer ${context.token}`;
456
- }
457
- try {
458
- const response = await fetch(endpoint, { headers });
459
- if (!response.ok) {
460
- const text = await response.text();
461
- throw new Error(`HTTP ${response.status}: ${text}`);
462
- }
463
- if (!response.body) {
464
- throw new Error('No response body received');
465
- }
466
- const reader = response.body.getReader();
467
- const decoder = new TextDecoder();
468
- let buffer = '';
469
- while (true) {
470
- const { done, value } = await reader.read();
471
- if (done)
472
- break;
473
- buffer += decoder.decode(value, { stream: true });
474
- const lines = buffer.split('\n');
475
- buffer = lines.pop() ?? '';
476
- let currentEvent = '';
477
- let currentData = '';
478
- for (const line of lines) {
479
- if (line.startsWith('event:')) {
480
- currentEvent = line.slice(6).trim();
481
- }
482
- else if (line.startsWith('data:')) {
483
- currentData = line.slice(5).trim();
484
- }
485
- else if (line === '' && currentData) {
486
- processPipelineSSEEvent(currentEvent, currentData);
487
- currentEvent = '';
488
- currentData = '';
489
- }
490
- }
491
- }
492
- // Process any remaining data in buffer
493
- if (buffer.trim()) {
494
- const remainingLines = buffer.split('\n');
495
- let currentEvent = '';
496
- let currentData = '';
497
- for (const line of remainingLines) {
498
- if (line.startsWith('event:')) {
499
- currentEvent = line.slice(6).trim();
500
- }
501
- else if (line.startsWith('data:')) {
502
- currentData = line.slice(5).trim();
503
- }
504
- }
505
- if (currentData) {
506
- processPipelineSSEEvent(currentEvent, currentData);
507
- }
508
- }
509
- console.log('');
510
- console.log('Stream ended.');
511
- }
512
- catch (error) {
513
- const err = error;
514
- console.error(`Error following pipeline run: ${err.message}`);
515
- process.exit(1);
516
- }
517
- }
518
- function processPipelineSSEEvent(eventType, dataStr) {
519
- try {
520
- const data = JSON.parse(dataStr);
521
- if (eventType === 'log') {
522
- const stepName = data.step_name ?? '???';
523
- const content = data.line ?? {};
524
- const timestamp = data.timestamp;
525
- const timeStr = timestamp ? formatPipelineTime(timestamp) : '';
526
- if (content.message) {
527
- console.log(`${timeStr}[${stepName}] ${content.message}`);
528
- }
529
- else if (content.lines && Array.isArray(content.lines)) {
530
- for (const l of content.lines) {
531
- console.log(`${timeStr}[${stepName}] ${l}`);
532
- }
533
- }
534
- else {
535
- console.log(`${timeStr}[${stepName}] ${JSON.stringify(content)}`);
536
- }
537
- }
538
- else if (eventType === 'complete') {
539
- console.log(`\nPipeline run completed: ${data.status}`);
540
- }
541
- else if (eventType === 'error') {
542
- console.error(`\nPipeline run failed: ${data.errorMessage ?? data.status}`);
543
- process.exit(1);
544
- }
545
- }
546
- catch {
547
- // Ignore malformed events
548
- }
549
- }
550
- function formatPipelineTime(timestamp) {
551
- try {
552
- const d = new Date(timestamp);
553
- return `[${d.toLocaleTimeString('en-US', { hour12: false })}] `;
554
- }
555
- catch {
556
- return '';
557
- }
558
- }
559
- const ERROR_CODES = {
560
- auth_error: { code: 'auth_error', label: 'Authentication Error', hint: "Check GITHUB_TOKEN via 'eve secrets set'" },
561
- clone_error: { code: 'clone_error', label: 'Git Clone Error', hint: "Verify repo URL and access. Check 'eve secrets list'" },
562
- build_error: { code: 'build_error', label: 'Build Error', hint: "Run 'eve build diagnose <build_id>' for full output" },
563
- timeout_error: { code: 'timeout_error', label: 'Timeout Error', hint: 'Consider increasing timeout or checking resources' },
564
- resource_error: { code: 'resource_error', label: 'Resource Error', hint: 'Check disk space and memory on build worker' },
565
- registry_error: { code: 'registry_error', label: 'Registry Error', hint: "Check registry credentials via 'eve secrets list'" },
566
- deploy_error: { code: 'deploy_error', label: 'Deploy Error', hint: "Run 'eve env diagnose <project> <env>'" },
567
- unknown_error: { code: 'unknown_error', label: 'Unknown Error', hint: "Run 'eve build diagnose <build_id>' or 'eve job diagnose <job_id>'" },
568
- };
569
- function getErrorCodeInfo(code) {
570
- return ERROR_CODES[code] ?? ERROR_CODES.unknown_error;
571
- }
572
- function buildQuery(params) {
573
- const search = new URLSearchParams();
574
- Object.entries(params).forEach(([key, value]) => {
575
- if (value === undefined || value === '')
576
- return;
577
- search.set(key, String(value));
578
- });
579
- const query = search.toString();
580
- return query ? `?${query}` : '';
581
- }
582
- /**
583
- * Emit an event before creating a pipeline run.
584
- * Fire-and-forget operation - logs warning on failure but doesn't block the command.
585
- */
586
- async function emitPipelineRunEvent(context, projectId, pipelineName, options) {
587
- try {
588
- const eventBody = {
589
- type: 'pipeline.run',
590
- source: 'manual',
591
- actor_type: 'user',
592
- actor_id: 'cli-user',
593
- };
594
- // Add optional fields
595
- if (options.env) {
596
- eventBody.env_name = options.env;
597
- }
598
- if (options.ref) {
599
- // Heuristic: if ref looks like a SHA (40 hex chars), treat as SHA; otherwise as branch
600
- const isSha = /^[0-9a-f]{40}$/i.test(options.ref);
601
- if (isSha) {
602
- eventBody.ref_sha = options.ref;
603
- }
604
- else {
605
- // Could be a branch name, short SHA, or tag - store in both for maximum compatibility
606
- eventBody.ref_sha = options.ref;
607
- eventBody.ref_branch = options.ref;
608
- }
609
- }
610
- // Build payload with pipeline name and inputs
611
- const payload = {
612
- pipeline_name: pipelineName,
613
- };
614
- if (options.inputs) {
615
- payload.inputs = options.inputs;
616
- }
617
- eventBody.payload_json = payload;
618
- // Fire-and-forget: emit event but don't block on failure
619
- await (0, client_1.requestJson)(context, `/projects/${projectId}/events`, {
620
- method: 'POST',
621
- body: eventBody,
622
- allowError: true,
623
- });
624
- }
625
- catch (error) {
626
- // Log warning but don't fail the command
627
- console.warn('Warning: Failed to emit pipeline.run event:', error instanceof Error ? error.message : 'unknown error');
628
- }
629
- }