bktide 1.0.1755655078 → 1.0.1765378562
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 +67 -19
- 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/parseBuildkiteReference.js +93 -0
- package/dist/utils/parseBuildkiteReference.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,25 +37,35 @@ echo 'source <(bktide completions zsh)' >> ~/.zshrc
|
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
Completions provide:
|
|
40
|
-
- Command suggestions (`bktide <Tab>`)
|
|
41
|
-
- Option completions (`bktide builds --<Tab>`)
|
|
42
|
-
- Value completions (`bktide --format <Tab>`)
|
|
40
|
+
- Command suggestions (ie `bktide <Tab>`)
|
|
41
|
+
- Option completions (ie `bktide builds --<Tab>`)
|
|
42
|
+
- Value completions (ie `bktide --format <Tab>`)
|
|
43
43
|
- Dynamic completions for organizations and pipelines (Fish with jq installed)
|
|
44
44
|
|
|
45
45
|
See [Shell Completions Guide](docs/shell-completions.md) for detailed installation and troubleshooting.
|
|
46
46
|
|
|
47
47
|
## Documentation
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
- [
|
|
53
|
-
- [
|
|
54
|
-
- [
|
|
55
|
-
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions
|
|
56
|
-
- [Alfred Integration
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
Our documentation is organized by audience to help you find what you need:
|
|
50
|
+
|
|
51
|
+
### 📖 [User Documentation](docs/user/) - For end users
|
|
52
|
+
- [Getting Started](docs/user/getting-started.md) - Quick start guide for new users
|
|
53
|
+
- [Authentication](docs/user/authentication.md) - How to authenticate with Buildkite
|
|
54
|
+
- [Shell Completions](docs/user/shell-completions.md) - Setting up auto-completion
|
|
55
|
+
- [Troubleshooting](docs/user/troubleshooting.md) - Common issues and solutions
|
|
56
|
+
- [Alfred Integration](docs/user/alfred/) - macOS Alfred workflow (installation, troubleshooting)
|
|
57
|
+
|
|
58
|
+
### 👨💻 [Developer Documentation](docs/developer/) - For contributors
|
|
59
|
+
- [Contributing Guide](docs/developer/contributing.md) - How to contribute to the project
|
|
60
|
+
- [Development Guide](docs/developer/development.md) - Setup and coding guidelines
|
|
61
|
+
- [Alfred Workflow Development](docs/developer/alfred-workflow-development.md) - Building and packaging
|
|
62
|
+
- [Testing Strategy](docs/developer/testing/README.md) - Testing approach and procedures
|
|
63
|
+
|
|
64
|
+
### 📚 [Reference Documentation](docs/reference/) - For everyone
|
|
65
|
+
- [Changelogs](docs/reference/) - What changed and when
|
|
66
|
+
- [Release Process](docs/reference/releasing.md) - How releases work
|
|
67
|
+
|
|
68
|
+
See [Documentation Overview](docs/README.md) for the complete structure and classification guide.
|
|
59
69
|
|
|
60
70
|
## Testing
|
|
61
71
|
|
|
@@ -67,7 +77,7 @@ npm run test:coverage # Generate coverage report
|
|
|
67
77
|
npm run test:extract-patterns # Extract patterns from real data (requires token)
|
|
68
78
|
```
|
|
69
79
|
|
|
70
|
-
See [Testing
|
|
80
|
+
See [Testing Strategy](docs/developer/testing/README.md) for details on the hybrid testing approach.
|
|
71
81
|
|
|
72
82
|
## Usage
|
|
73
83
|
|
|
@@ -139,7 +149,7 @@ bktide annotations <build>
|
|
|
139
149
|
|
|
140
150
|
The build reference can be specified in two formats:
|
|
141
151
|
- **Slug format**: `org/pipeline/number` (e.g., `gusto/zenpayroll/1287418`)
|
|
142
|
-
- **URL format**:
|
|
152
|
+
- **URL format**: `https://buildkite.com/org/pipeline/builds/number`
|
|
143
153
|
|
|
144
154
|
Additional options:
|
|
145
155
|
```bash
|
|
@@ -165,7 +175,7 @@ View detailed information about a specific build including jobs and annotations.
|
|
|
165
175
|
bktide build org/pipeline/123
|
|
166
176
|
|
|
167
177
|
# View build by URL format
|
|
168
|
-
bktide build
|
|
178
|
+
bktide build https://buildkite.com/org/pipeline/builds/123
|
|
169
179
|
```
|
|
170
180
|
|
|
171
181
|
Additional options:
|
|
@@ -183,6 +193,44 @@ bktide build org/pipeline/123 --annotations
|
|
|
183
193
|
bktide build org/pipeline/123 --jobs --failed --annotations
|
|
184
194
|
```
|
|
185
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
|
+
|
|
186
234
|
### Generate Shell Completions
|
|
187
235
|
|
|
188
236
|
```bash
|
|
@@ -315,12 +363,12 @@ Available log levels (from most to least verbose):
|
|
|
315
363
|
|
|
316
364
|
## Log Files
|
|
317
365
|
|
|
318
|
-
All logs are written to
|
|
366
|
+
All logs are written to `~/.local/state/bktide/logs/cli.log` in JSON format, which can be processed with tools like jq:
|
|
319
367
|
|
|
320
368
|
```bash
|
|
321
369
|
# View recent errors
|
|
322
|
-
cat
|
|
370
|
+
cat ~/.local/state/bktide/logs/cli.log | grep -v '"level":30' | jq
|
|
323
371
|
|
|
324
372
|
# Analyze performance
|
|
325
|
-
cat
|
|
373
|
+
cat ~/.local/state/bktide/logs/cli.log | jq 'select(.duration != null) | {msg, duration}'
|
|
326
374
|
```
|
|
@@ -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":"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","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"]}
|