bktide 1.0.1765203819 → 1.0.1768353932
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/README.md +38 -0
- package/dist/commands/SmartShow.js +250 -0
- package/dist/commands/SmartShow.js.map +1 -0
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/formatters/pipeline-detail/AlfredFormatter.js +57 -0
- package/dist/formatters/pipeline-detail/AlfredFormatter.js.map +1 -0
- package/dist/formatters/pipeline-detail/Formatter.js +7 -0
- package/dist/formatters/pipeline-detail/Formatter.js.map +1 -0
- package/dist/formatters/pipeline-detail/JsonFormatter.js +11 -0
- package/dist/formatters/pipeline-detail/JsonFormatter.js.map +1 -0
- package/dist/formatters/pipeline-detail/PlainFormatter.js +55 -0
- package/dist/formatters/pipeline-detail/PlainFormatter.js.map +1 -0
- package/dist/formatters/pipeline-detail/index.js +5 -0
- package/dist/formatters/pipeline-detail/index.js.map +1 -0
- package/dist/formatters/step-logs/AlfredFormatter.js +72 -0
- package/dist/formatters/step-logs/AlfredFormatter.js.map +1 -0
- package/dist/formatters/step-logs/Formatter.js +7 -0
- package/dist/formatters/step-logs/Formatter.js.map +1 -0
- package/dist/formatters/step-logs/JsonFormatter.js +11 -0
- package/dist/formatters/step-logs/JsonFormatter.js.map +1 -0
- package/dist/formatters/step-logs/PlainFormatter.js +47 -0
- package/dist/formatters/step-logs/PlainFormatter.js.map +1 -0
- package/dist/formatters/step-logs/index.js +5 -0
- package/dist/formatters/step-logs/index.js.map +1 -0
- package/dist/graphql/queries.js +22 -0
- package/dist/graphql/queries.js.map +1 -1
- package/dist/index.js +45 -4
- package/dist/index.js.map +1 -1
- package/dist/services/BuildkiteClient.js +18 -1
- package/dist/services/BuildkiteClient.js.map +1 -1
- package/dist/services/BuildkiteRestClient.js +73 -0
- package/dist/services/BuildkiteRestClient.js.map +1 -1
- package/dist/types/buildkite.js.map +1 -1
- package/dist/utils/formatUtils.js +91 -0
- package/dist/utils/formatUtils.js.map +1 -0
- package/dist/utils/parseBuildRef.js +12 -1
- package/dist/utils/parseBuildRef.js.map +1 -1
- package/dist/utils/parseBuildkiteReference.js +93 -0
- package/dist/utils/parseBuildkiteReference.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,6 +193,44 @@ bktide build org/pipeline/123 --annotations
|
|
|
193
193
|
bktide build org/pipeline/123 --jobs --failed --annotations
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
+
### Smart Reference Command
|
|
197
|
+
|
|
198
|
+
Paste any Buildkite URL or use short-hand formats, and bktide will figure out what to show.
|
|
199
|
+
|
|
200
|
+
**Supported formats:**
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Pipeline view (shows metadata + recent builds)
|
|
204
|
+
bktide gusto/schemaflow
|
|
205
|
+
bktide https://buildkite.com/gusto/schemaflow
|
|
206
|
+
|
|
207
|
+
# Build view (shows comprehensive build details)
|
|
208
|
+
bktide gusto/schemaflow/76
|
|
209
|
+
bktide gusto/schemaflow#76
|
|
210
|
+
bktide https://buildkite.com/gusto/schemaflow/builds/76
|
|
211
|
+
|
|
212
|
+
# Step logs (shows build context + step logs)
|
|
213
|
+
bktide https://buildkite.com/gusto/schemaflow/builds/76?sid=019adb19-bd83-4149-b2a7-ece1d7a41c9d
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Log display options:**
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Show last 50 lines (default)
|
|
220
|
+
bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id>
|
|
221
|
+
|
|
222
|
+
# Show all lines
|
|
223
|
+
bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id> --full
|
|
224
|
+
|
|
225
|
+
# Show last N lines
|
|
226
|
+
bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id> --lines 100
|
|
227
|
+
|
|
228
|
+
# Save logs to file
|
|
229
|
+
bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id> --save logs.txt
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Note:** Viewing step logs requires `read_build_logs` scope on your API token.
|
|
233
|
+
|
|
196
234
|
### Generate Shell Completions
|
|
197
235
|
|
|
198
236
|
```bash
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { BaseCommand } from './BaseCommand.js';
|
|
2
|
+
import { parseBuildkiteReference } from '../utils/parseBuildkiteReference.js';
|
|
3
|
+
import { logger } from '../services/logger.js';
|
|
4
|
+
import { ShowBuild } from './ShowBuild.js';
|
|
5
|
+
import { PlainPipelineDetailFormatter, JsonPipelineDetailFormatter, AlfredPipelineDetailFormatter } from '../formatters/pipeline-detail/index.js';
|
|
6
|
+
import { PlainStepLogsFormatter, JsonStepLogsFormatter, AlfredStepLogsFormatter } from '../formatters/step-logs/index.js';
|
|
7
|
+
import { SEMANTIC_COLORS, formatError } from '../ui/theme.js';
|
|
8
|
+
import { Progress } from '../ui/progress.js';
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
export class SmartShow extends BaseCommand {
|
|
11
|
+
static requiresToken = true;
|
|
12
|
+
async execute(options) {
|
|
13
|
+
if (options.debug) {
|
|
14
|
+
logger.debug('Starting SmartShow command execution', options);
|
|
15
|
+
}
|
|
16
|
+
if (!options.reference) {
|
|
17
|
+
logger.error('Reference is required');
|
|
18
|
+
return 1;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
// Parse the reference
|
|
22
|
+
const ref = parseBuildkiteReference(options.reference);
|
|
23
|
+
if (options.debug) {
|
|
24
|
+
logger.debug('Parsed reference:', ref);
|
|
25
|
+
}
|
|
26
|
+
// Route based on reference type
|
|
27
|
+
switch (ref.type) {
|
|
28
|
+
case 'pipeline':
|
|
29
|
+
return await this.showPipeline(ref, options);
|
|
30
|
+
case 'build':
|
|
31
|
+
return await this.showBuild(ref, options);
|
|
32
|
+
case 'build-with-step':
|
|
33
|
+
return await this.showBuildWithStep(ref, options);
|
|
34
|
+
default:
|
|
35
|
+
logger.error('Unknown reference type');
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error instanceof Error) {
|
|
41
|
+
const errorOutput = formatError(error.message, {
|
|
42
|
+
suggestions: ['Check the reference format', 'Verify you have access to this resource'],
|
|
43
|
+
});
|
|
44
|
+
logger.console(errorOutput);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
logger.error('Unknown error occurred');
|
|
48
|
+
}
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async showPipeline(ref, options) {
|
|
53
|
+
const format = options.format || 'plain';
|
|
54
|
+
const spinner = Progress.spinner('Fetching pipeline details...', { format });
|
|
55
|
+
try {
|
|
56
|
+
// Initialize token first
|
|
57
|
+
this.token = await BaseCommand.getToken(options);
|
|
58
|
+
// Fetch pipeline details
|
|
59
|
+
const pipeline = await this.client.getPipeline(ref.org, ref.pipeline);
|
|
60
|
+
spinner.stop();
|
|
61
|
+
if (!pipeline) {
|
|
62
|
+
logger.error(`Pipeline not found: ${ref.org}/${ref.pipeline}`);
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
// Fetch recent builds using pipeline-specific endpoint
|
|
66
|
+
const builds = await this.restClient.getPipelineBuilds(ref.org, ref.pipeline, {
|
|
67
|
+
per_page: '20',
|
|
68
|
+
});
|
|
69
|
+
// Prepare data for formatter
|
|
70
|
+
const data = {
|
|
71
|
+
org: ref.org,
|
|
72
|
+
pipeline: {
|
|
73
|
+
name: pipeline.name,
|
|
74
|
+
slug: pipeline.slug,
|
|
75
|
+
description: pipeline.description,
|
|
76
|
+
defaultBranch: pipeline.defaultBranch,
|
|
77
|
+
url: pipeline.url,
|
|
78
|
+
repository: pipeline.repository,
|
|
79
|
+
},
|
|
80
|
+
recentBuilds: (builds || []).map((build) => ({
|
|
81
|
+
number: build.number,
|
|
82
|
+
state: build.state,
|
|
83
|
+
branch: build.branch,
|
|
84
|
+
message: build.message,
|
|
85
|
+
startedAt: build.started_at,
|
|
86
|
+
finishedAt: build.finished_at,
|
|
87
|
+
})),
|
|
88
|
+
};
|
|
89
|
+
// Format and display
|
|
90
|
+
let formatter;
|
|
91
|
+
if (format === 'alfred') {
|
|
92
|
+
formatter = new AlfredPipelineDetailFormatter({});
|
|
93
|
+
}
|
|
94
|
+
else if (format === 'json') {
|
|
95
|
+
formatter = new JsonPipelineDetailFormatter({});
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
formatter = new PlainPipelineDetailFormatter({});
|
|
99
|
+
}
|
|
100
|
+
const output = formatter.format(data);
|
|
101
|
+
logger.console(output);
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
spinner.stop();
|
|
106
|
+
if (error instanceof Error) {
|
|
107
|
+
const errorOutput = formatError(error.message, {
|
|
108
|
+
suggestions: ['Check the reference format', 'Verify you have access to this resource'],
|
|
109
|
+
});
|
|
110
|
+
logger.console(errorOutput);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
logger.error('Unknown error occurred');
|
|
114
|
+
}
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async showBuild(ref, options) {
|
|
119
|
+
// Route to ShowBuild with enhanced defaults (--jobs --failed)
|
|
120
|
+
const buildCommand = new ShowBuild(options);
|
|
121
|
+
const buildOptions = {
|
|
122
|
+
...options,
|
|
123
|
+
buildArg: `${ref.org}/${ref.pipeline}/${ref.buildNumber}`,
|
|
124
|
+
jobs: true,
|
|
125
|
+
failed: true,
|
|
126
|
+
};
|
|
127
|
+
return await buildCommand.execute(buildOptions);
|
|
128
|
+
}
|
|
129
|
+
async showBuildWithStep(ref, options) {
|
|
130
|
+
const format = options.format || 'plain';
|
|
131
|
+
const spinner = Progress.spinner('Fetching step logs...', { format });
|
|
132
|
+
try {
|
|
133
|
+
// Initialize token first
|
|
134
|
+
this.token = await BaseCommand.getToken(options);
|
|
135
|
+
// Use REST API to get build with jobs (step.id field needed for matching)
|
|
136
|
+
const build = await this.restClient.getBuild(ref.org, ref.pipeline, ref.buildNumber);
|
|
137
|
+
const jobs = build.jobs || [];
|
|
138
|
+
if (!jobs || jobs.length === 0) {
|
|
139
|
+
spinner.stop();
|
|
140
|
+
logger.error(`Build not found: ${ref.org}/${ref.pipeline}/${ref.buildNumber}`);
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
// Find job by step ID (sid from URL) - step.id is different from job.id
|
|
144
|
+
if (options.debug) {
|
|
145
|
+
logger.debug(`Found ${jobs.length} jobs in build`);
|
|
146
|
+
logger.debug(`Looking for step ID: ${ref.stepId}`);
|
|
147
|
+
// Log first few jobs for debugging
|
|
148
|
+
jobs.slice(0, 3).forEach((j) => {
|
|
149
|
+
logger.debug(` Job: id=${j.id}, step.id=${j.step?.id}, name=${j.name}`);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const job = jobs.find((j) => j.step?.id === ref.stepId);
|
|
153
|
+
if (!job) {
|
|
154
|
+
spinner.stop();
|
|
155
|
+
logger.error(`Step not found in build #${ref.buildNumber}: ${ref.stepId}`);
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
// Use job.id (job UUID) for log fetching, not ref.stepId
|
|
159
|
+
const logData = await this.restClient.getJobLog(ref.org, ref.pipeline, ref.buildNumber, job.id);
|
|
160
|
+
spinner.stop();
|
|
161
|
+
// Parse log content
|
|
162
|
+
const logLines = logData.content.split('\n');
|
|
163
|
+
const totalLines = logLines.length;
|
|
164
|
+
// Determine how many lines to display
|
|
165
|
+
const linesToShow = options.full ? totalLines : (options.lines || 50);
|
|
166
|
+
const startLine = Math.max(0, totalLines - linesToShow);
|
|
167
|
+
const displayedLines = logLines.slice(startLine);
|
|
168
|
+
// Save to file if requested
|
|
169
|
+
if (options.save) {
|
|
170
|
+
await fs.writeFile(options.save, logData.content);
|
|
171
|
+
logger.console(SEMANTIC_COLORS.success(`✓ Log saved to ${options.save} (${this.formatSize(logData.size)}, ${totalLines} lines)`));
|
|
172
|
+
}
|
|
173
|
+
// Prepare data for formatter using REST API fields from build object
|
|
174
|
+
const data = {
|
|
175
|
+
build: {
|
|
176
|
+
org: ref.org,
|
|
177
|
+
pipeline: ref.pipeline,
|
|
178
|
+
number: ref.buildNumber,
|
|
179
|
+
state: build.state || 'unknown',
|
|
180
|
+
startedAt: build.started_at,
|
|
181
|
+
finishedAt: build.finished_at,
|
|
182
|
+
url: build.web_url,
|
|
183
|
+
},
|
|
184
|
+
step: {
|
|
185
|
+
id: job.id,
|
|
186
|
+
label: job.name,
|
|
187
|
+
state: job.state,
|
|
188
|
+
exitStatus: job.exit_status,
|
|
189
|
+
startedAt: job.started_at,
|
|
190
|
+
finishedAt: job.finished_at,
|
|
191
|
+
},
|
|
192
|
+
logs: {
|
|
193
|
+
content: displayedLines.join('\n'),
|
|
194
|
+
size: logData.size,
|
|
195
|
+
totalLines,
|
|
196
|
+
displayedLines: displayedLines.length,
|
|
197
|
+
startLine,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
// Format and display (unless only saving)
|
|
201
|
+
if (!options.save || options.format) {
|
|
202
|
+
let formatter;
|
|
203
|
+
if (format === 'alfred') {
|
|
204
|
+
formatter = new AlfredStepLogsFormatter({ full: options.full, lines: options.lines });
|
|
205
|
+
}
|
|
206
|
+
else if (format === 'json') {
|
|
207
|
+
formatter = new JsonStepLogsFormatter({ full: options.full, lines: options.lines });
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
formatter = new PlainStepLogsFormatter({ full: options.full, lines: options.lines });
|
|
211
|
+
}
|
|
212
|
+
const output = formatter.format(data);
|
|
213
|
+
logger.console(output);
|
|
214
|
+
}
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
spinner.stop();
|
|
219
|
+
if (error instanceof Error) {
|
|
220
|
+
if (error.message.includes('401') || error.message.includes('403')) {
|
|
221
|
+
const errorOutput = formatError('Permission denied', {
|
|
222
|
+
suggestions: [
|
|
223
|
+
'Your API token needs \'read_build_logs\' scope to view logs',
|
|
224
|
+
'Update your token at: https://buildkite.com/user/api-access-tokens',
|
|
225
|
+
],
|
|
226
|
+
});
|
|
227
|
+
logger.console(errorOutput);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
const errorOutput = formatError(error.message, {
|
|
231
|
+
suggestions: ['Check the reference format', 'Verify you have access to this resource'],
|
|
232
|
+
});
|
|
233
|
+
logger.console(errorOutput);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
logger.error('Unknown error occurred');
|
|
238
|
+
}
|
|
239
|
+
return 1;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
formatSize(bytes) {
|
|
243
|
+
if (bytes < 1024)
|
|
244
|
+
return `${bytes} B`;
|
|
245
|
+
if (bytes < 1024 * 1024)
|
|
246
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
247
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=SmartShow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartShow.js","sourceRoot":"/","sources":["commands/SmartShow.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { parseBuildkiteReference, BuildkiteReference } from '../utils/parseBuildkiteReference.js';\nimport { logger } from '../services/logger.js';\nimport { ShowBuild } from './ShowBuild.js';\nimport { PlainPipelineDetailFormatter, JsonPipelineDetailFormatter, AlfredPipelineDetailFormatter } from '../formatters/pipeline-detail/index.js';\nimport type { PipelineDetailData } from '../formatters/pipeline-detail/Formatter.js';\nimport { PlainStepLogsFormatter, JsonStepLogsFormatter, AlfredStepLogsFormatter } from '../formatters/step-logs/index.js';\nimport type { StepLogsData } from '../formatters/step-logs/Formatter.js';\nimport { SEMANTIC_COLORS, formatError } from '../ui/theme.js';\nimport { Progress } from '../ui/progress.js';\nimport * as fs from 'fs/promises';\n\nexport interface SmartShowOptions extends BaseCommandOptions {\n reference: string;\n // Log display options\n full?: boolean;\n lines?: number;\n save?: string;\n}\n\nexport class SmartShow extends BaseCommand {\n static requiresToken = true;\n\n async execute(options: SmartShowOptions): Promise<number> {\n if (options.debug) {\n logger.debug('Starting SmartShow command execution', options);\n }\n\n if (!options.reference) {\n logger.error('Reference is required');\n return 1;\n }\n\n try {\n // Parse the reference\n const ref = parseBuildkiteReference(options.reference);\n \n if (options.debug) {\n logger.debug('Parsed reference:', ref);\n }\n\n // Route based on reference type\n switch (ref.type) {\n case 'pipeline':\n return await this.showPipeline(ref, options);\n case 'build':\n return await this.showBuild(ref, options);\n case 'build-with-step':\n return await this.showBuildWithStep(ref, options);\n default:\n logger.error('Unknown reference type');\n return 1;\n }\n } catch (error) {\n if (error instanceof Error) {\n const errorOutput = formatError(error.message, {\n suggestions: ['Check the reference format', 'Verify you have access to this resource'],\n });\n logger.console(errorOutput);\n } else {\n logger.error('Unknown error occurred');\n }\n return 1;\n }\n }\n\n private async showPipeline(\n ref: Extract<BuildkiteReference, { type: 'pipeline' }>,\n options: SmartShowOptions\n ): Promise<number> {\n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching pipeline details...', { format });\n\n try {\n // Initialize token first\n this.token = await BaseCommand.getToken(options);\n \n // Fetch pipeline details\n const pipeline = await this.client.getPipeline(ref.org, ref.pipeline);\n spinner.stop();\n \n if (!pipeline) {\n logger.error(`Pipeline not found: ${ref.org}/${ref.pipeline}`);\n return 1;\n }\n\n // Fetch recent builds using pipeline-specific endpoint\n const builds = await this.restClient.getPipelineBuilds(ref.org, ref.pipeline, {\n per_page: '20',\n });\n\n // Prepare data for formatter\n const data: PipelineDetailData = {\n org: ref.org,\n pipeline: {\n name: pipeline.name,\n slug: pipeline.slug,\n description: pipeline.description,\n defaultBranch: pipeline.defaultBranch,\n url: pipeline.url,\n repository: pipeline.repository,\n },\n recentBuilds: (builds || []).map((build: any) => ({\n number: build.number,\n state: build.state,\n branch: build.branch,\n message: build.message,\n startedAt: build.started_at,\n finishedAt: build.finished_at,\n })),\n };\n\n // Format and display\n let formatter;\n \n if (format === 'alfred') {\n formatter = new AlfredPipelineDetailFormatter({});\n } else if (format === 'json') {\n formatter = new JsonPipelineDetailFormatter({});\n } else {\n formatter = new PlainPipelineDetailFormatter({});\n }\n\n const output = formatter.format(data);\n logger.console(output);\n\n return 0;\n } catch (error) {\n spinner.stop();\n if (error instanceof Error) {\n const errorOutput = formatError(error.message, {\n suggestions: ['Check the reference format', 'Verify you have access to this resource'],\n });\n logger.console(errorOutput);\n } else {\n logger.error('Unknown error occurred');\n }\n return 1;\n }\n }\n\n private async showBuild(\n ref: Extract<BuildkiteReference, { type: 'build' }>,\n options: SmartShowOptions\n ): Promise<number> {\n // Route to ShowBuild with enhanced defaults (--jobs --failed)\n const buildCommand = new ShowBuild(options);\n \n const buildOptions = {\n ...options,\n buildArg: `${ref.org}/${ref.pipeline}/${ref.buildNumber}`,\n jobs: true,\n failed: true,\n };\n\n return await buildCommand.execute(buildOptions);\n }\n\n private async showBuildWithStep(\n ref: Extract<BuildkiteReference, { type: 'build-with-step' }>,\n options: SmartShowOptions\n ): Promise<number> {\n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching step logs...', { format });\n\n try {\n // Initialize token first\n this.token = await BaseCommand.getToken(options);\n\n // Use REST API to get build with jobs (step.id field needed for matching)\n const build = await this.restClient.getBuild(ref.org, ref.pipeline, ref.buildNumber);\n const jobs = build.jobs || [];\n \n if (!jobs || jobs.length === 0) {\n spinner.stop();\n logger.error(`Build not found: ${ref.org}/${ref.pipeline}/${ref.buildNumber}`);\n return 1;\n }\n\n // Find job by step ID (sid from URL) - step.id is different from job.id\n if (options.debug) {\n logger.debug(`Found ${jobs.length} jobs in build`);\n logger.debug(`Looking for step ID: ${ref.stepId}`);\n // Log first few jobs for debugging\n jobs.slice(0, 3).forEach((j: any) => {\n logger.debug(` Job: id=${j.id}, step.id=${j.step?.id}, name=${j.name}`);\n });\n }\n const job = jobs.find((j: any) => j.step?.id === ref.stepId);\n \n if (!job) {\n spinner.stop();\n logger.error(`Step not found in build #${ref.buildNumber}: ${ref.stepId}`);\n return 1;\n }\n\n // Use job.id (job UUID) for log fetching, not ref.stepId\n const logData = await this.restClient.getJobLog(ref.org, ref.pipeline, ref.buildNumber, job.id);\n spinner.stop();\n\n // Parse log content\n const logLines = logData.content.split('\\n');\n const totalLines = logLines.length;\n \n // Determine how many lines to display\n const linesToShow = options.full ? totalLines : (options.lines || 50);\n const startLine = Math.max(0, totalLines - linesToShow);\n const displayedLines = logLines.slice(startLine);\n\n // Save to file if requested\n if (options.save) {\n await fs.writeFile(options.save, logData.content);\n logger.console(SEMANTIC_COLORS.success(`✓ Log saved to ${options.save} (${this.formatSize(logData.size)}, ${totalLines} lines)`));\n }\n\n // Prepare data for formatter using REST API fields from build object\n const data: StepLogsData = {\n build: {\n org: ref.org,\n pipeline: ref.pipeline,\n number: ref.buildNumber,\n state: build.state || 'unknown',\n startedAt: build.started_at,\n finishedAt: build.finished_at,\n url: build.web_url,\n },\n step: {\n id: job.id,\n label: job.name,\n state: job.state,\n exitStatus: job.exit_status,\n startedAt: job.started_at,\n finishedAt: job.finished_at,\n },\n logs: {\n content: displayedLines.join('\\n'),\n size: logData.size,\n totalLines,\n displayedLines: displayedLines.length,\n startLine,\n },\n };\n\n // Format and display (unless only saving)\n if (!options.save || options.format) {\n let formatter;\n \n if (format === 'alfred') {\n formatter = new AlfredStepLogsFormatter({ full: options.full, lines: options.lines });\n } else if (format === 'json') {\n formatter = new JsonStepLogsFormatter({ full: options.full, lines: options.lines });\n } else {\n formatter = new PlainStepLogsFormatter({ full: options.full, lines: options.lines });\n }\n\n const output = formatter.format(data);\n logger.console(output);\n }\n\n return 0;\n } catch (error) {\n spinner.stop();\n if (error instanceof Error) {\n if (error.message.includes('401') || error.message.includes('403')) {\n const errorOutput = formatError('Permission denied', {\n suggestions: [\n 'Your API token needs \\'read_build_logs\\' scope to view logs',\n 'Update your token at: https://buildkite.com/user/api-access-tokens',\n ],\n });\n logger.console(errorOutput);\n } else {\n const errorOutput = formatError(error.message, {\n suggestions: ['Check the reference format', 'Verify you have access to this resource'],\n });\n logger.console(errorOutput);\n }\n } else {\n logger.error('Unknown error occurred');\n }\n return 1;\n }\n }\n\n private formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n }\n}\n"]}
|
package/dist/commands/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"/","sources":["commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC","sourcesContent":["export * from './BaseCommand.js';\nexport * from './ShowViewer.js';\nexport * from './ListOrganizations.js';\nexport * from './ListBuilds.js';\nexport * from './ListPipelines.js';\nexport * from './ManageToken.js';\nexport * from './ListAnnotations.js';\nexport * from './GenerateCompletions.js';\nexport * from './ShowBuild.js';"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"/","sources":["commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC","sourcesContent":["export * from './BaseCommand.js';\nexport * from './ShowViewer.js';\nexport * from './ListOrganizations.js';\nexport * from './ListBuilds.js';\nexport * from './ListPipelines.js';\nexport * from './ManageToken.js';\nexport * from './ListAnnotations.js';\nexport * from './GenerateCompletions.js';\nexport * from './ShowBuild.js';\nexport * from './SmartShow.js';"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PipelineDetailFormatter } from './Formatter.js';
|
|
2
|
+
export class AlfredPipelineDetailFormatter extends PipelineDetailFormatter {
|
|
3
|
+
name = 'alfred';
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
format(data) {
|
|
8
|
+
const items = [];
|
|
9
|
+
const { pipeline, recentBuilds } = data;
|
|
10
|
+
// Pipeline header item
|
|
11
|
+
items.push({
|
|
12
|
+
uid: `pipeline-${pipeline.slug}`,
|
|
13
|
+
title: pipeline.name,
|
|
14
|
+
subtitle: pipeline.description || `Pipeline: ${pipeline.slug}`,
|
|
15
|
+
arg: pipeline.url,
|
|
16
|
+
icon: { path: 'icons/buildkite.png' },
|
|
17
|
+
valid: true,
|
|
18
|
+
});
|
|
19
|
+
// Recent builds as items
|
|
20
|
+
for (const build of recentBuilds) {
|
|
21
|
+
const stateIcon = this.getStateIcon(build.state);
|
|
22
|
+
items.push({
|
|
23
|
+
uid: `build-${pipeline.slug}-${build.number}`,
|
|
24
|
+
title: `#${build.number} - ${build.message}`,
|
|
25
|
+
subtitle: `${build.state} | ${build.branch}`,
|
|
26
|
+
arg: `${pipeline.url}/builds/${build.number}`,
|
|
27
|
+
icon: { path: stateIcon },
|
|
28
|
+
valid: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const output = { items };
|
|
32
|
+
return JSON.stringify(output, null, 2);
|
|
33
|
+
}
|
|
34
|
+
getStateIcon(state) {
|
|
35
|
+
const stateUpper = state.toUpperCase();
|
|
36
|
+
switch (stateUpper) {
|
|
37
|
+
case 'PASSED':
|
|
38
|
+
return 'icons/passed.png';
|
|
39
|
+
case 'FAILED':
|
|
40
|
+
return 'icons/failed.png';
|
|
41
|
+
case 'RUNNING':
|
|
42
|
+
return 'icons/running.png';
|
|
43
|
+
case 'BLOCKED':
|
|
44
|
+
return 'icons/blocked.png';
|
|
45
|
+
case 'CANCELED':
|
|
46
|
+
case 'CANCELLED':
|
|
47
|
+
return 'icons/unknown.png';
|
|
48
|
+
case 'SCHEDULED':
|
|
49
|
+
return 'icons/scheduled.png';
|
|
50
|
+
case 'SKIPPED':
|
|
51
|
+
return 'icons/skipped.png';
|
|
52
|
+
default:
|
|
53
|
+
return 'icons/unknown.png';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=AlfredFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/AlfredFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAsB,MAAM,gBAAgB,CAAC;AAgB7E,MAAM,OAAO,6BAA8B,SAAQ,uBAAuB;IACxE,IAAI,GAAG,QAAQ,CAAC;IAEhB,YAAY,OAAyB;QACnC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,IAAwB;QAC7B,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QAExC,uBAAuB;QACvB,KAAK,CAAC,IAAI,CAAC;YACT,GAAG,EAAE,YAAY,QAAQ,CAAC,IAAI,EAAE;YAChC,KAAK,EAAE,QAAQ,CAAC,IAAI;YACpB,QAAQ,EAAE,QAAQ,CAAC,WAAW,IAAI,aAAa,QAAQ,CAAC,IAAI,EAAE;YAC9D,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,IAAI,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE;YACrC,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,yBAAyB;QACzB,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC;gBACT,GAAG,EAAE,SAAS,QAAQ,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE;gBAC7C,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,OAAO,EAAE;gBAC5C,QAAQ,EAAE,GAAG,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE;gBAC5C,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,WAAW,KAAK,CAAC,MAAM,EAAE;gBAC7C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBACzB,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAiB,EAAE,KAAK,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IAEO,YAAY,CAAC,KAAa;QAChC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QACvC,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,QAAQ;gBACX,OAAO,kBAAkB,CAAC;YAC5B,KAAK,QAAQ;gBACX,OAAO,kBAAkB,CAAC;YAC5B,KAAK,SAAS;gBACZ,OAAO,mBAAmB,CAAC;YAC7B,KAAK,SAAS;gBACZ,OAAO,mBAAmB,CAAC;YAC7B,KAAK,UAAU,CAAC;YAChB,KAAK,WAAW;gBACd,OAAO,mBAAmB,CAAC;YAC7B,KAAK,WAAW;gBACd,OAAO,qBAAqB,CAAC;YAC/B,KAAK,SAAS;gBACZ,OAAO,mBAAmB,CAAC;YAC7B;gBACE,OAAO,mBAAmB,CAAC;QAC/B,CAAC;IACH,CAAC;CACF","sourcesContent":["import { PipelineDetailFormatter, PipelineDetailData } from './Formatter.js';\nimport { FormatterOptions } from '../BaseFormatter.js';\n\ninterface AlfredItem {\n uid?: string;\n title: string;\n subtitle?: string;\n arg?: string;\n icon?: { path: string };\n valid?: boolean;\n}\n\ninterface AlfredOutput {\n items: AlfredItem[];\n}\n\nexport class AlfredPipelineDetailFormatter extends PipelineDetailFormatter {\n name = 'alfred';\n\n constructor(options: FormatterOptions) {\n super(options);\n }\n\n format(data: PipelineDetailData): string {\n const items: AlfredItem[] = [];\n const { pipeline, recentBuilds } = data;\n\n // Pipeline header item\n items.push({\n uid: `pipeline-${pipeline.slug}`,\n title: pipeline.name,\n subtitle: pipeline.description || `Pipeline: ${pipeline.slug}`,\n arg: pipeline.url,\n icon: { path: 'icons/buildkite.png' },\n valid: true,\n });\n\n // Recent builds as items\n for (const build of recentBuilds) {\n const stateIcon = this.getStateIcon(build.state);\n items.push({\n uid: `build-${pipeline.slug}-${build.number}`,\n title: `#${build.number} - ${build.message}`,\n subtitle: `${build.state} | ${build.branch}`,\n arg: `${pipeline.url}/builds/${build.number}`,\n icon: { path: stateIcon },\n valid: true,\n });\n }\n\n const output: AlfredOutput = { items };\n return JSON.stringify(output, null, 2);\n }\n\n private getStateIcon(state: string): string {\n const stateUpper = state.toUpperCase();\n switch (stateUpper) {\n case 'PASSED':\n return 'icons/passed.png';\n case 'FAILED':\n return 'icons/failed.png';\n case 'RUNNING':\n return 'icons/running.png';\n case 'BLOCKED':\n return 'icons/blocked.png';\n case 'CANCELED':\n case 'CANCELLED':\n return 'icons/unknown.png';\n case 'SCHEDULED':\n return 'icons/scheduled.png';\n case 'SKIPPED':\n return 'icons/skipped.png';\n default:\n return 'icons/unknown.png';\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/Formatter.ts"],"names":[],"mappings":"AAwBA,MAAM,OAAgB,uBAAuB;IAGrB;IAAtB,YAAsB,OAAyB;QAAzB,YAAO,GAAP,OAAO,CAAkB;IAAG,CAAC;CAGpD","sourcesContent":["import { FormatterOptions } from '../BaseFormatter.js';\n\nexport interface PipelineDetailData {\n org: string;\n pipeline: {\n name: string;\n slug: string;\n description?: string;\n defaultBranch?: string;\n url: string;\n repository?: {\n url: string;\n };\n };\n recentBuilds: Array<{\n number: number;\n state: string;\n branch: string;\n message: string;\n startedAt?: string;\n finishedAt?: string;\n }>;\n}\n\nexport abstract class PipelineDetailFormatter {\n abstract name: string;\n \n constructor(protected options: FormatterOptions) {}\n\n abstract format(data: PipelineDetailData): string;\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PipelineDetailFormatter } from './Formatter.js';
|
|
2
|
+
export class JsonPipelineDetailFormatter extends PipelineDetailFormatter {
|
|
3
|
+
name = 'json';
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
format(data) {
|
|
8
|
+
return JSON.stringify(data, null, 2);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=JsonFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonFormatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/JsonFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAsB,MAAM,gBAAgB,CAAC;AAG7E,MAAM,OAAO,2BAA4B,SAAQ,uBAAuB;IACtE,IAAI,GAAG,MAAM,CAAC;IAEd,YAAY,OAAyB;QACnC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,IAAwB;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC;CACF","sourcesContent":["import { PipelineDetailFormatter, PipelineDetailData } from './Formatter.js';\nimport { FormatterOptions } from '../BaseFormatter.js';\n\nexport class JsonPipelineDetailFormatter extends PipelineDetailFormatter {\n name = 'json';\n\n constructor(options: FormatterOptions) {\n super(options);\n }\n\n format(data: PipelineDetailData): string {\n return JSON.stringify(data, null, 2);\n }\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { PipelineDetailFormatter } from './Formatter.js';
|
|
2
|
+
import { SEMANTIC_COLORS, formatTips, TipStyle } from '../../ui/theme.js';
|
|
3
|
+
import { renderTable } from '../../ui/table.js';
|
|
4
|
+
import { formatStatus, formatRelativeDate, truncate } from '../../utils/formatUtils.js';
|
|
5
|
+
export class PlainPipelineDetailFormatter extends PipelineDetailFormatter {
|
|
6
|
+
name = 'plain';
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super(options);
|
|
9
|
+
}
|
|
10
|
+
format(data) {
|
|
11
|
+
const { org, pipeline, recentBuilds } = data;
|
|
12
|
+
const lines = [];
|
|
13
|
+
// Pipeline header
|
|
14
|
+
lines.push(SEMANTIC_COLORS.heading(`Pipeline: ${pipeline.name}`));
|
|
15
|
+
if (pipeline.description) {
|
|
16
|
+
lines.push(SEMANTIC_COLORS.dim(`Description: ${pipeline.description}`));
|
|
17
|
+
}
|
|
18
|
+
if (pipeline.defaultBranch) {
|
|
19
|
+
lines.push(SEMANTIC_COLORS.dim(`Default Branch: ${pipeline.defaultBranch}`));
|
|
20
|
+
}
|
|
21
|
+
if (pipeline.repository?.url) {
|
|
22
|
+
lines.push(SEMANTIC_COLORS.dim(`Repository: ${pipeline.repository.url}`));
|
|
23
|
+
}
|
|
24
|
+
lines.push('');
|
|
25
|
+
// Recent builds
|
|
26
|
+
if (recentBuilds && recentBuilds.length > 0) {
|
|
27
|
+
lines.push(SEMANTIC_COLORS.subheading('Recent Builds'));
|
|
28
|
+
lines.push('');
|
|
29
|
+
const tableRows = [
|
|
30
|
+
['Build', 'Status', 'Branch', 'Message', 'Started'],
|
|
31
|
+
...recentBuilds.map(build => [
|
|
32
|
+
SEMANTIC_COLORS.label(`#${build.number}`),
|
|
33
|
+
formatStatus(build.state),
|
|
34
|
+
build.branch,
|
|
35
|
+
truncate(build.message, 50),
|
|
36
|
+
build.startedAt ? formatRelativeDate(build.startedAt) : '-',
|
|
37
|
+
])
|
|
38
|
+
];
|
|
39
|
+
const table = renderTable(tableRows, { preserveWidths: true });
|
|
40
|
+
lines.push(table);
|
|
41
|
+
// Add tips
|
|
42
|
+
lines.push('');
|
|
43
|
+
const tips = formatTips([
|
|
44
|
+
`View a build: bktide ${org}/${pipeline.slug}/<number>`,
|
|
45
|
+
'Use --format json for machine-readable output',
|
|
46
|
+
], TipStyle.GROUPED);
|
|
47
|
+
lines.push(tips);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
lines.push(SEMANTIC_COLORS.dim('No recent builds found'));
|
|
51
|
+
}
|
|
52
|
+
return lines.join('\n');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=PlainFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlainFormatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/PlainFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAsB,MAAM,gBAAgB,CAAC;AAE7E,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAExF,MAAM,OAAO,4BAA6B,SAAQ,uBAAuB;IACvE,IAAI,GAAG,OAAO,CAAC;IAEf,YAAY,OAAyB;QACnC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,IAAwB;QAC7B,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QAC7C,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,kBAAkB;QAClB,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,aAAa,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAElE,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC1E,CAAC;QAED,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,mBAAmB,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC/E,CAAC;QAED,IAAI,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEf,gBAAgB;QAChB,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,MAAM,SAAS,GAAe;gBAC5B,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;gBACnD,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3B,eAAe,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;oBACzC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC;oBACzB,KAAK,CAAC,MAAM;oBACZ,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;oBAC3B,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG;iBAC5D,CAAC;aACH,CAAC;YAEF,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/D,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClB,WAAW;YACX,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,UAAU,CAAC;gBACtB,wBAAwB,GAAG,IAAI,QAAQ,CAAC,IAAI,WAAW;gBACvD,+CAA+C;aAChD,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF","sourcesContent":["import { PipelineDetailFormatter, PipelineDetailData } from './Formatter.js';\nimport { FormatterOptions } from '../BaseFormatter.js';\nimport { SEMANTIC_COLORS, formatTips, TipStyle } from '../../ui/theme.js';\nimport { renderTable } from '../../ui/table.js';\nimport { formatStatus, formatRelativeDate, truncate } from '../../utils/formatUtils.js';\n\nexport class PlainPipelineDetailFormatter extends PipelineDetailFormatter {\n name = 'plain';\n\n constructor(options: FormatterOptions) {\n super(options);\n }\n\n format(data: PipelineDetailData): string {\n const { org, pipeline, recentBuilds } = data;\n const lines: string[] = [];\n\n // Pipeline header\n lines.push(SEMANTIC_COLORS.heading(`Pipeline: ${pipeline.name}`));\n \n if (pipeline.description) {\n lines.push(SEMANTIC_COLORS.dim(`Description: ${pipeline.description}`));\n }\n \n if (pipeline.defaultBranch) {\n lines.push(SEMANTIC_COLORS.dim(`Default Branch: ${pipeline.defaultBranch}`));\n }\n \n if (pipeline.repository?.url) {\n lines.push(SEMANTIC_COLORS.dim(`Repository: ${pipeline.repository.url}`));\n }\n \n lines.push('');\n\n // Recent builds\n if (recentBuilds && recentBuilds.length > 0) {\n lines.push(SEMANTIC_COLORS.subheading('Recent Builds'));\n lines.push('');\n\n const tableRows: string[][] = [\n ['Build', 'Status', 'Branch', 'Message', 'Started'],\n ...recentBuilds.map(build => [\n SEMANTIC_COLORS.label(`#${build.number}`),\n formatStatus(build.state),\n build.branch,\n truncate(build.message, 50),\n build.startedAt ? formatRelativeDate(build.startedAt) : '-',\n ])\n ];\n\n const table = renderTable(tableRows, { preserveWidths: true });\n lines.push(table);\n // Add tips\n lines.push('');\n const tips = formatTips([\n `View a build: bktide ${org}/${pipeline.slug}/<number>`,\n 'Use --format json for machine-readable output',\n ], TipStyle.GROUPED);\n lines.push(tips);\n } else {\n lines.push(SEMANTIC_COLORS.dim('No recent builds found'));\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"/","sources":["formatters/pipeline-detail/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC","sourcesContent":["export * from './Formatter.js';\nexport * from './PlainFormatter.js';\nexport * from './JsonFormatter.js';\nexport * from './AlfredFormatter.js';\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { StepLogsFormatter } from './Formatter.js';
|
|
2
|
+
export class AlfredStepLogsFormatter extends StepLogsFormatter {
|
|
3
|
+
name = 'alfred';
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
format(data) {
|
|
8
|
+
const items = [];
|
|
9
|
+
const { build, step, logs } = data;
|
|
10
|
+
// Build info item
|
|
11
|
+
items.push({
|
|
12
|
+
uid: `build-${build.org}-${build.pipeline}-${build.number}`,
|
|
13
|
+
title: `Build #${build.number}`,
|
|
14
|
+
subtitle: `${build.state} | ${build.org}/${build.pipeline}`,
|
|
15
|
+
arg: build.url,
|
|
16
|
+
icon: { path: this.getStateIcon(build.state) },
|
|
17
|
+
valid: true,
|
|
18
|
+
});
|
|
19
|
+
// Step info item
|
|
20
|
+
const stepLabel = step.label || `Step ${step.id}`;
|
|
21
|
+
const exitInfo = step.exitStatus !== undefined ? ` (exit ${step.exitStatus})` : '';
|
|
22
|
+
items.push({
|
|
23
|
+
uid: `step-${step.id}`,
|
|
24
|
+
title: stepLabel,
|
|
25
|
+
subtitle: `${step.state}${exitInfo}`,
|
|
26
|
+
arg: build.url,
|
|
27
|
+
icon: { path: this.getStateIcon(step.state) },
|
|
28
|
+
valid: true,
|
|
29
|
+
});
|
|
30
|
+
// Log summary item
|
|
31
|
+
items.push({
|
|
32
|
+
uid: `logs-${step.id}`,
|
|
33
|
+
title: 'Log Output',
|
|
34
|
+
subtitle: `${logs.displayedLines} of ${logs.totalLines} lines | ${this.formatSize(logs.size)}`,
|
|
35
|
+
arg: build.url,
|
|
36
|
+
icon: { path: 'icons/buildkite.png' },
|
|
37
|
+
valid: true,
|
|
38
|
+
});
|
|
39
|
+
const output = { items };
|
|
40
|
+
return JSON.stringify(output, null, 2);
|
|
41
|
+
}
|
|
42
|
+
getStateIcon(state) {
|
|
43
|
+
const stateUpper = state.toUpperCase();
|
|
44
|
+
switch (stateUpper) {
|
|
45
|
+
case 'PASSED':
|
|
46
|
+
return 'icons/passed.png';
|
|
47
|
+
case 'FAILED':
|
|
48
|
+
return 'icons/failed.png';
|
|
49
|
+
case 'RUNNING':
|
|
50
|
+
return 'icons/running.png';
|
|
51
|
+
case 'BLOCKED':
|
|
52
|
+
return 'icons/blocked.png';
|
|
53
|
+
case 'CANCELED':
|
|
54
|
+
case 'CANCELLED':
|
|
55
|
+
return 'icons/unknown.png';
|
|
56
|
+
case 'SCHEDULED':
|
|
57
|
+
return 'icons/scheduled.png';
|
|
58
|
+
case 'SKIPPED':
|
|
59
|
+
return 'icons/skipped.png';
|
|
60
|
+
default:
|
|
61
|
+
return 'icons/unknown.png';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
formatSize(bytes) {
|
|
65
|
+
if (bytes < 1024)
|
|
66
|
+
return `${bytes} B`;
|
|
67
|
+
if (bytes < 1024 * 1024)
|
|
68
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
69
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=AlfredFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/step-logs/AlfredFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { StepLogsFormatter, StepLogsData, StepLogsFormatterOptions } from './Formatter.js';\n\ninterface AlfredItem {\n uid?: string;\n title: string;\n subtitle?: string;\n arg?: string;\n icon?: { path: string };\n valid?: boolean;\n}\n\ninterface AlfredOutput {\n items: AlfredItem[];\n}\n\nexport class AlfredStepLogsFormatter extends StepLogsFormatter {\n name = 'alfred';\n\n constructor(options: StepLogsFormatterOptions) {\n super(options);\n }\n\n format(data: StepLogsData): string {\n const items: AlfredItem[] = [];\n const { build, step, logs } = data;\n\n // Build info item\n items.push({\n uid: `build-${build.org}-${build.pipeline}-${build.number}`,\n title: `Build #${build.number}`,\n subtitle: `${build.state} | ${build.org}/${build.pipeline}`,\n arg: build.url,\n icon: { path: this.getStateIcon(build.state) },\n valid: true,\n });\n\n // Step info item\n const stepLabel = step.label || `Step ${step.id}`;\n const exitInfo = step.exitStatus !== undefined ? ` (exit ${step.exitStatus})` : '';\n items.push({\n uid: `step-${step.id}`,\n title: stepLabel,\n subtitle: `${step.state}${exitInfo}`,\n arg: build.url,\n icon: { path: this.getStateIcon(step.state) },\n valid: true,\n });\n\n // Log summary item\n items.push({\n uid: `logs-${step.id}`,\n title: 'Log Output',\n subtitle: `${logs.displayedLines} of ${logs.totalLines} lines | ${this.formatSize(logs.size)}`,\n arg: build.url,\n icon: { path: 'icons/buildkite.png' },\n valid: true,\n });\n\n const output: AlfredOutput = { items };\n return JSON.stringify(output, null, 2);\n }\n\n private getStateIcon(state: string): string {\n const stateUpper = state.toUpperCase();\n switch (stateUpper) {\n case 'PASSED':\n return 'icons/passed.png';\n case 'FAILED':\n return 'icons/failed.png';\n case 'RUNNING':\n return 'icons/running.png';\n case 'BLOCKED':\n return 'icons/blocked.png';\n case 'CANCELED':\n case 'CANCELLED':\n return 'icons/unknown.png';\n case 'SCHEDULED':\n return 'icons/scheduled.png';\n case 'SKIPPED':\n return 'icons/skipped.png';\n default:\n return 'icons/unknown.png';\n }\n }\n\n private formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/step-logs/Formatter.ts"],"names":[],"mappings":"AAkCA,MAAM,OAAgB,iBAAiB;IAE3B,OAAO,CAA2B;IAE5C,YAAY,OAAiC;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CAGF","sourcesContent":["import { FormatterOptions } from '../BaseFormatter.js';\n\nexport interface StepLogsData {\n build: {\n org: string;\n pipeline: string;\n number: number;\n state: string;\n startedAt?: string;\n finishedAt?: string;\n url: string;\n };\n step: {\n id: string;\n label?: string;\n state: string;\n exitStatus?: number;\n startedAt?: string;\n finishedAt?: string;\n };\n logs: {\n content: string;\n size: number;\n totalLines: number;\n displayedLines: number;\n startLine: number;\n };\n}\n\nexport interface StepLogsFormatterOptions extends FormatterOptions {\n full?: boolean;\n lines?: number;\n}\n\nexport abstract class StepLogsFormatter {\n abstract name: string;\n protected options: StepLogsFormatterOptions;\n\n constructor(options: StepLogsFormatterOptions) {\n this.options = options;\n }\n\n abstract format(data: StepLogsData): string;\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { StepLogsFormatter } from './Formatter.js';
|
|
2
|
+
export class JsonStepLogsFormatter extends StepLogsFormatter {
|
|
3
|
+
name = 'json';
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
format(data) {
|
|
8
|
+
return JSON.stringify(data, null, 2);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=JsonFormatter.js.map
|