bktide 1.0.1755267617 → 1.0.1755559112
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 +107 -1
- package/WORKFLOW_README.md +1 -1
- package/completions/bktide-dynamic.fish +171 -0
- package/completions/bktide.bash +124 -0
- package/completions/bktide.fish +107 -0
- package/completions/bktide.zsh +139 -0
- package/dist/commands/BaseCommand.js +7 -7
- package/dist/commands/BaseCommand.js.map +1 -1
- package/dist/commands/GenerateCompletions.js +238 -0
- package/dist/commands/GenerateCompletions.js.map +1 -0
- package/dist/commands/ListAnnotations.js +7 -0
- package/dist/commands/ListAnnotations.js.map +1 -1
- package/dist/commands/ListBuilds.js +67 -3
- package/dist/commands/ListBuilds.js.map +1 -1
- package/dist/commands/ListOrganizations.js +6 -0
- package/dist/commands/ListOrganizations.js.map +1 -1
- package/dist/commands/ListPipelines.js +87 -12
- package/dist/commands/ListPipelines.js.map +1 -1
- package/dist/commands/ManageToken.js +32 -9
- package/dist/commands/ManageToken.js.map +1 -1
- package/dist/commands/ShowBuild.js +88 -0
- package/dist/commands/ShowBuild.js.map +1 -0
- package/dist/commands/ShowViewer.js +7 -1
- package/dist/commands/ShowViewer.js.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/formatters/FormatterFactory.js +4 -0
- package/dist/formatters/FormatterFactory.js.map +1 -1
- package/dist/formatters/annotations/PlainTextFormatter.js +37 -9
- package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/build-detail/AlfredFormatter.js +113 -0
- package/dist/formatters/build-detail/AlfredFormatter.js.map +1 -0
- package/dist/formatters/build-detail/Formatter.js +3 -0
- package/dist/formatters/build-detail/Formatter.js.map +1 -0
- package/dist/formatters/build-detail/JsonFormatter.js +132 -0
- package/dist/formatters/build-detail/JsonFormatter.js.map +1 -0
- package/dist/formatters/build-detail/PlainTextFormatter.js +680 -0
- package/dist/formatters/build-detail/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/build-detail/index.js +21 -0
- package/dist/formatters/build-detail/index.js.map +1 -0
- package/dist/formatters/builds/PlainTextFormatter.js +82 -60
- package/dist/formatters/builds/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/errors/AlfredFormatter.js +20 -0
- package/dist/formatters/errors/AlfredFormatter.js.map +1 -1
- package/dist/formatters/errors/PlainTextFormatter.js +121 -23
- package/dist/formatters/errors/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/organizations/PlainTextFormatter.js +37 -6
- package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -1
- package/dist/formatters/pipelines/Formatter.js.map +1 -1
- package/dist/formatters/pipelines/JsonFormatter.js.map +1 -1
- package/dist/formatters/pipelines/PlainTextFormatter.js +165 -19
- package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/token/AlfredFormatter.js +15 -2
- package/dist/formatters/token/AlfredFormatter.js.map +1 -1
- package/dist/formatters/token/PlainTextFormatter.js +56 -18
- package/dist/formatters/token/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/viewer/PlainTextFormatter.js +8 -7
- package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -1
- package/dist/graphql/queries.js +181 -0
- package/dist/graphql/queries.js.map +1 -1
- package/dist/index.js +67 -6
- package/dist/index.js.map +1 -1
- package/dist/services/BuildkiteClient.js +61 -1
- package/dist/services/BuildkiteClient.js.map +1 -1
- package/dist/services/CredentialManager.js +80 -10
- package/dist/services/CredentialManager.js.map +1 -1
- package/dist/ui/help.js +69 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/progress.js +356 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/reporter.js +111 -0
- package/dist/ui/reporter.js.map +1 -0
- package/dist/ui/responsive-table.js +183 -0
- package/dist/ui/responsive-table.js.map +1 -0
- package/dist/ui/spinner.js +20 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/symbols.js +46 -0
- package/dist/ui/symbols.js.map +1 -0
- package/dist/ui/table.js +32 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/ui/theme.js +280 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/width.js +111 -0
- package/dist/ui/width.js.map +1 -0
- package/dist/utils/alfred.js +6 -0
- package/dist/utils/alfred.js.map +1 -0
- package/dist/utils/cli-error-handler.js +35 -20
- package/dist/utils/cli-error-handler.js.map +1 -1
- package/dist/utils/pagination.js +92 -0
- package/dist/utils/pagination.js.map +1 -0
- package/info.plist +51 -218
- package/package.json +24 -5
|
@@ -2,6 +2,8 @@ import { BaseCommand } from './BaseCommand.js';
|
|
|
2
2
|
import { getBuildFormatter } from '../formatters/index.js';
|
|
3
3
|
import Fuse from 'fuse.js';
|
|
4
4
|
import { logger } from '../services/logger.js';
|
|
5
|
+
import { Reporter } from '../ui/reporter.js';
|
|
6
|
+
import { Progress } from '../ui/progress.js';
|
|
5
7
|
export class ListBuilds extends BaseCommand {
|
|
6
8
|
constructor(options) {
|
|
7
9
|
super(options);
|
|
@@ -13,8 +15,12 @@ export class ListBuilds extends BaseCommand {
|
|
|
13
15
|
logger.debug('Starting ViewerBuildsCommandHandler execution');
|
|
14
16
|
}
|
|
15
17
|
try {
|
|
18
|
+
const format = options.format || 'plain';
|
|
19
|
+
const reporter = new Reporter(format, options.quiet, options.tips);
|
|
20
|
+
const viewerSpinner = Progress.spinner('Fetching viewer info...', { format });
|
|
16
21
|
// First, get the current user's information using GraphQL
|
|
17
22
|
const viewerData = await this.client.getViewer();
|
|
23
|
+
viewerSpinner.stop();
|
|
18
24
|
if (!viewerData?.viewer?.user?.uuid) {
|
|
19
25
|
logger.error('Failed to get current user UUID information');
|
|
20
26
|
return 1;
|
|
@@ -43,12 +49,35 @@ export class ListBuilds extends BaseCommand {
|
|
|
43
49
|
// Initialize results array
|
|
44
50
|
let allBuilds = [];
|
|
45
51
|
let accessErrors = [];
|
|
46
|
-
|
|
52
|
+
// Use progress bar for multiple orgs, spinner for single org
|
|
53
|
+
const useProgressBar = orgs.length > 1 && format === 'plain';
|
|
54
|
+
const progress = useProgressBar ? Progress.bar({
|
|
55
|
+
total: orgs.length,
|
|
56
|
+
label: 'Fetching builds from organizations',
|
|
57
|
+
format: format
|
|
58
|
+
}) : null;
|
|
59
|
+
// Create a spinner for single-org scenario
|
|
60
|
+
let fetchSpinner = !useProgressBar ? Progress.spinner(undefined, { format }) : null;
|
|
61
|
+
for (let i = 0; i < orgs.length; i++) {
|
|
62
|
+
const org = orgs[i];
|
|
47
63
|
try {
|
|
64
|
+
if (progress) {
|
|
65
|
+
progress.update(i, `Fetching builds from ${org}`);
|
|
66
|
+
}
|
|
67
|
+
else if (fetchSpinner) {
|
|
68
|
+
fetchSpinner.update(`Fetching builds from ${org}…`, `Fetching builds from ${org}…`);
|
|
69
|
+
}
|
|
48
70
|
// First check if the user has access to this organization
|
|
49
71
|
const hasAccess = await this.restClient.hasOrganizationAccess(org);
|
|
50
72
|
if (!hasAccess) {
|
|
51
73
|
accessErrors.push(`You don't have access to organization ${org}`);
|
|
74
|
+
if (progress) {
|
|
75
|
+
// Continue to next org with progress bar
|
|
76
|
+
progress.update(i + 1, `No access to ${org}`);
|
|
77
|
+
}
|
|
78
|
+
else if (fetchSpinner) {
|
|
79
|
+
fetchSpinner.fail(`No access to ${org}`);
|
|
80
|
+
}
|
|
52
81
|
continue;
|
|
53
82
|
}
|
|
54
83
|
const builds = await this.restClient.getBuilds(org, {
|
|
@@ -63,12 +92,23 @@ export class ListBuilds extends BaseCommand {
|
|
|
63
92
|
logger.debug(`Received ${builds.length} builds from org ${org}`);
|
|
64
93
|
}
|
|
65
94
|
allBuilds = allBuilds.concat(builds);
|
|
95
|
+
if (!progress && fetchSpinner) {
|
|
96
|
+
fetchSpinner.stop();
|
|
97
|
+
}
|
|
66
98
|
}
|
|
67
99
|
catch (error) {
|
|
68
100
|
// Log unexpected errors but continue processing other orgs
|
|
69
101
|
logger.error(error, `Error fetching builds for org ${org}`);
|
|
102
|
+
if (!progress && fetchSpinner) {
|
|
103
|
+
fetchSpinner.stop();
|
|
104
|
+
}
|
|
70
105
|
}
|
|
71
106
|
}
|
|
107
|
+
// Complete the progress bar
|
|
108
|
+
if (progress) {
|
|
109
|
+
const successOrgs = orgs.length - accessErrors.length;
|
|
110
|
+
progress.complete(`Retrieved ${allBuilds.length} builds from ${successOrgs}/${orgs.length} organizations`);
|
|
111
|
+
}
|
|
72
112
|
// Prepare formatter options
|
|
73
113
|
const formatterOptions = {
|
|
74
114
|
debug: options.debug,
|
|
@@ -116,10 +156,34 @@ export class ListBuilds extends BaseCommand {
|
|
|
116
156
|
logger.debug(`Filtered to ${allBuilds.length} builds matching '${options.filter}'`);
|
|
117
157
|
}
|
|
118
158
|
}
|
|
119
|
-
const format = options.format || 'plain';
|
|
120
159
|
const formatter = getBuildFormatter(format);
|
|
121
160
|
const output = formatter.formatBuilds(allBuilds, formatterOptions);
|
|
122
|
-
|
|
161
|
+
// Output data directly to stdout to ensure proper ordering
|
|
162
|
+
if (format === 'plain') {
|
|
163
|
+
process.stdout.write(output + '\n');
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
logger.console(output);
|
|
167
|
+
}
|
|
168
|
+
// Add contextual next-steps hints AFTER showing the data
|
|
169
|
+
if (allBuilds.length > 0) {
|
|
170
|
+
const tips = [];
|
|
171
|
+
const buildCount = parseInt(perPage, 10);
|
|
172
|
+
if (allBuilds.length === buildCount) {
|
|
173
|
+
tips.push(`Use --count ${buildCount * 2} to see more builds`);
|
|
174
|
+
}
|
|
175
|
+
// If filtering is not active, suggest filtering options
|
|
176
|
+
if (!options.state && !options.branch && !options.pipeline) {
|
|
177
|
+
tips.push('Filter by state: --state failed');
|
|
178
|
+
tips.push('Filter by branch: --branch main');
|
|
179
|
+
tips.push('Filter by pipeline: --pipeline <name>');
|
|
180
|
+
}
|
|
181
|
+
// Display all tips at once
|
|
182
|
+
if (tips.length > 0) {
|
|
183
|
+
// Use individual style for consistency with current output
|
|
184
|
+
tips.forEach(tip => reporter.tip(tip));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
123
187
|
if (options.debug) {
|
|
124
188
|
const executeDuration = Number(process.hrtime.bigint() - executeStartTime) / 1000000;
|
|
125
189
|
logger.debug(`ViewerBuildsCommandHandler execution completed in ${executeDuration.toFixed(2)}ms`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListBuilds.js","sourceRoot":"/","sources":["commands/ListBuilds.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { getBuildFormatter } from '../formatters/index.js';\nimport Fuse from 'fuse.js';\nimport { Build } from '../types/index.js';\nimport { logger } from '../services/logger.js';\nimport { BuildFormatterOptions } from '../formatters/builds/Formatter.js';\n\nexport interface ViewerBuildsOptions extends BaseCommandOptions {\n count?: string;\n page?: string;\n org?: string;\n pipeline?: string;\n branch?: string;\n state?: string;\n}\n\nexport class ListBuilds extends BaseCommand {\n constructor(options?: Partial<ViewerBuildsOptions>) {\n super(options);\n }\n\n async execute(options: ViewerBuildsOptions): Promise<number> {\n await this.ensureInitialized();\n \n const executeStartTime = process.hrtime.bigint();\n if (options.debug) {\n logger.debug('Starting ViewerBuildsCommandHandler execution');\n }\n \n try {\n // First, get the current user's information using GraphQL\n const viewerData = await this.client.getViewer();\n \n if (!viewerData?.viewer?.user?.uuid) {\n logger.error('Failed to get current user UUID information');\n return 1;\n }\n \n const userId = viewerData.viewer.user.uuid;\n const userName = viewerData.viewer.user.name || 'Current user';\n const userEmail = viewerData.viewer.user.email;\n \n // Use the REST API to get builds by the current user\n const perPage = options.count || '10';\n const page = options.page || '1';\n \n // If organization is not specified, we need to fetch organizations first\n let orgs: string[] = [];\n if (!options.org) {\n // Try to fetch the user's organizations\n try {\n orgs = await this.client.getViewerOrganizationSlugs();\n } catch (error) {\n logger.error(error as any, 'Failed to determine your organizations');\n return 1;\n }\n } else {\n orgs = [options.org];\n }\n \n // Initialize results array\n let allBuilds: Build[] = [];\n let accessErrors: string[] = [];\n \n for (const org of orgs) {\n try {\n // First check if the user has access to this organization\n const hasAccess = await this.restClient.hasOrganizationAccess(org);\n if (!hasAccess) {\n accessErrors.push(`You don't have access to organization ${org}`);\n continue;\n }\n \n const builds = await this.restClient.getBuilds(org, {\n creator: userId,\n pipeline: options.pipeline,\n branch: options.branch,\n state: options.state,\n per_page: perPage,\n page: page\n });\n \n if (options.debug) {\n logger.debug(`Received ${builds.length} builds from org ${org}`);\n }\n \n allBuilds = allBuilds.concat(builds);\n } catch (error) {\n // Log unexpected errors but continue processing other orgs\n logger.error(error, `Error fetching builds for org ${org}`);\n }\n }\n \n // Prepare formatter options\n const formatterOptions: BuildFormatterOptions = {\n debug: options.debug,\n organizationsCount: orgs.length,\n orgSpecified: !!options.org,\n userName,\n userEmail,\n userId\n };\n \n // Handle the case where we have no builds due to access issues\n if (allBuilds.length === 0 && accessErrors.length > 0) {\n formatterOptions.hasError = true;\n formatterOptions.errorType = 'access';\n formatterOptions.accessErrors = accessErrors;\n \n if (options.org) {\n formatterOptions.errorMessage = `No builds found for ${userName} (${userEmail}) in organization ${options.org}. ${accessErrors[0]}`;\n } else {\n formatterOptions.errorMessage = `No builds found for ${userName} (${userEmail}). Try specifying an organization with --org to narrow your search.`;\n }\n \n const format = options.format || 'plain';\n const formatter = getBuildFormatter(format);\n const output = formatter.formatBuilds(allBuilds, formatterOptions);\n logger.console(output);\n return 1;\n }\n \n // Limit to the requested number of builds\n allBuilds = allBuilds.slice(0, parseInt(perPage, 10));\n \n // Apply fuzzy filter if specified\n if (options.filter) {\n if (options.debug) {\n logger.debug(`Applying fuzzy filter '${options.filter}' to ${allBuilds.length} builds`);\n }\n \n // Configure Fuse for fuzzy searching\n const fuse = new Fuse(allBuilds, {\n keys: ['pipeline.name', 'branch', 'message', 'creator.name', 'state'],\n threshold: 0.4,\n includeScore: true,\n shouldSort: true\n });\n \n // Perform the fuzzy search\n const searchResults = fuse.search(options.filter);\n allBuilds = searchResults.map(result => result.item);\n \n if (options.debug) {\n logger.debug(`Filtered to ${allBuilds.length} builds matching '${options.filter}'`);\n }\n }\n \n const format = options.format || 'plain';\n const formatter = getBuildFormatter(format);\n const output = formatter.formatBuilds(allBuilds, formatterOptions);\n logger.console(output);\n \n if (options.debug) {\n const executeDuration = Number(process.hrtime.bigint() - executeStartTime) / 1000000;\n logger.debug(`ViewerBuildsCommandHandler execution completed in ${executeDuration.toFixed(2)}ms`);\n }\n \n return 0; // Success\n } catch (error) {\n // Only unexpected errors should reach here\n // Let the base command handle the error display\n this.handleError(error, options.debug);\n return 1; // Error\n }\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"ListBuilds.js","sourceRoot":"/","sources":["commands/ListBuilds.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { getBuildFormatter } from '../formatters/index.js';\nimport Fuse from 'fuse.js';\nimport { Build } from '../types/index.js';\nimport { logger } from '../services/logger.js';\nimport { BuildFormatterOptions } from '../formatters/builds/Formatter.js';\nimport { Reporter } from '../ui/reporter.js';\n\nimport { Progress } from '../ui/progress.js';\n\nexport interface ViewerBuildsOptions extends BaseCommandOptions {\n count?: string;\n page?: string;\n org?: string;\n pipeline?: string;\n branch?: string;\n state?: string;\n tips?: boolean;\n}\n\nexport class ListBuilds extends BaseCommand {\n constructor(options?: Partial<ViewerBuildsOptions>) {\n super(options);\n }\n\n async execute(options: ViewerBuildsOptions): Promise<number> {\n await this.ensureInitialized();\n \n const executeStartTime = process.hrtime.bigint();\n if (options.debug) {\n logger.debug('Starting ViewerBuildsCommandHandler execution');\n }\n \n try {\n const format = options.format || 'plain';\n const reporter = new Reporter(format, options.quiet, options.tips);\n const viewerSpinner = Progress.spinner('Fetching viewer info...', { format });\n // First, get the current user's information using GraphQL\n const viewerData = await this.client.getViewer();\n viewerSpinner.stop();\n \n if (!viewerData?.viewer?.user?.uuid) {\n logger.error('Failed to get current user UUID information');\n return 1;\n }\n \n const userId = viewerData.viewer.user.uuid;\n const userName = viewerData.viewer.user.name || 'Current user';\n const userEmail = viewerData.viewer.user.email;\n \n // Use the REST API to get builds by the current user\n const perPage = options.count || '10';\n const page = options.page || '1';\n \n // If organization is not specified, we need to fetch organizations first\n let orgs: string[] = [];\n if (!options.org) {\n // Try to fetch the user's organizations\n try {\n orgs = await this.client.getViewerOrganizationSlugs();\n } catch (error) {\n logger.error(error as any, 'Failed to determine your organizations');\n return 1;\n }\n } else {\n orgs = [options.org];\n }\n \n // Initialize results array\n let allBuilds: Build[] = [];\n let accessErrors: string[] = [];\n \n // Use progress bar for multiple orgs, spinner for single org\n const useProgressBar = orgs.length > 1 && format === 'plain';\n const progress = useProgressBar ? Progress.bar({\n total: orgs.length,\n label: 'Fetching builds from organizations',\n format: format\n }) : null;\n \n // Create a spinner for single-org scenario\n let fetchSpinner = !useProgressBar ? Progress.spinner(undefined, { format }) : null;\n \n for (let i = 0; i < orgs.length; i++) {\n const org = orgs[i];\n \n try {\n if (progress) {\n progress.update(i, `Fetching builds from ${org}`);\n } else if (fetchSpinner) {\n fetchSpinner.update(`Fetching builds from ${org}…`, `Fetching builds from ${org}…`);\n }\n \n // First check if the user has access to this organization\n const hasAccess = await this.restClient.hasOrganizationAccess(org);\n if (!hasAccess) {\n accessErrors.push(`You don't have access to organization ${org}`);\n if (progress) {\n // Continue to next org with progress bar\n progress.update(i + 1, `No access to ${org}`);\n } else if (fetchSpinner) {\n fetchSpinner.fail(`No access to ${org}`);\n }\n continue;\n }\n \n const builds = await this.restClient.getBuilds(org, {\n creator: userId,\n pipeline: options.pipeline,\n branch: options.branch,\n state: options.state,\n per_page: perPage,\n page: page\n });\n \n if (options.debug) {\n logger.debug(`Received ${builds.length} builds from org ${org}`);\n }\n \n allBuilds = allBuilds.concat(builds);\n \n if (!progress && fetchSpinner) {\n fetchSpinner.stop();\n }\n } catch (error) {\n // Log unexpected errors but continue processing other orgs\n logger.error(error, `Error fetching builds for org ${org}`);\n if (!progress && fetchSpinner) {\n fetchSpinner.stop();\n }\n }\n }\n \n // Complete the progress bar\n if (progress) {\n const successOrgs = orgs.length - accessErrors.length;\n progress.complete(`Retrieved ${allBuilds.length} builds from ${successOrgs}/${orgs.length} organizations`);\n }\n \n // Prepare formatter options\n const formatterOptions: BuildFormatterOptions = {\n debug: options.debug,\n organizationsCount: orgs.length,\n orgSpecified: !!options.org,\n userName,\n userEmail,\n userId\n };\n \n // Handle the case where we have no builds due to access issues\n if (allBuilds.length === 0 && accessErrors.length > 0) {\n formatterOptions.hasError = true;\n formatterOptions.errorType = 'access';\n formatterOptions.accessErrors = accessErrors;\n \n if (options.org) {\n formatterOptions.errorMessage = `No builds found for ${userName} (${userEmail}) in organization ${options.org}. ${accessErrors[0]}`;\n } else {\n formatterOptions.errorMessage = `No builds found for ${userName} (${userEmail}). Try specifying an organization with --org to narrow your search.`;\n }\n \n const format = options.format || 'plain';\n const formatter = getBuildFormatter(format);\n const output = formatter.formatBuilds(allBuilds, formatterOptions);\n logger.console(output);\n return 1;\n }\n \n // Limit to the requested number of builds\n allBuilds = allBuilds.slice(0, parseInt(perPage, 10));\n \n // Apply fuzzy filter if specified\n if (options.filter) {\n if (options.debug) {\n logger.debug(`Applying fuzzy filter '${options.filter}' to ${allBuilds.length} builds`);\n }\n \n // Configure Fuse for fuzzy searching\n const fuse = new Fuse(allBuilds, {\n keys: ['pipeline.name', 'branch', 'message', 'creator.name', 'state'],\n threshold: 0.4,\n includeScore: true,\n shouldSort: true\n });\n \n // Perform the fuzzy search\n const searchResults = fuse.search(options.filter);\n allBuilds = searchResults.map(result => result.item);\n \n if (options.debug) {\n logger.debug(`Filtered to ${allBuilds.length} builds matching '${options.filter}'`);\n }\n }\n \n const formatter = getBuildFormatter(format);\n const output = formatter.formatBuilds(allBuilds, formatterOptions);\n \n // Output data directly to stdout to ensure proper ordering\n if (format === 'plain') {\n process.stdout.write(output + '\\n');\n } else {\n logger.console(output);\n }\n \n // Add contextual next-steps hints AFTER showing the data\n if (allBuilds.length > 0) {\n const tips: string[] = [];\n const buildCount = parseInt(perPage, 10);\n \n if (allBuilds.length === buildCount) {\n tips.push(`Use --count ${buildCount * 2} to see more builds`);\n }\n \n // If filtering is not active, suggest filtering options\n if (!options.state && !options.branch && !options.pipeline) {\n tips.push('Filter by state: --state failed');\n tips.push('Filter by branch: --branch main');\n tips.push('Filter by pipeline: --pipeline <name>');\n }\n \n // Display all tips at once\n if (tips.length > 0) {\n // Use individual style for consistency with current output\n tips.forEach(tip => reporter.tip(tip));\n }\n }\n \n if (options.debug) {\n const executeDuration = Number(process.hrtime.bigint() - executeStartTime) / 1000000;\n logger.debug(`ViewerBuildsCommandHandler execution completed in ${executeDuration.toFixed(2)}ms`);\n }\n \n return 0; // Success\n } catch (error) {\n // Only unexpected errors should reach here\n // Let the base command handle the error display\n this.handleError(error, options.debug);\n return 1; // Error\n }\n }\n}"]}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { BaseCommand } from './BaseCommand.js';
|
|
2
2
|
import { logger } from '../services/logger.js';
|
|
3
3
|
import { FormatterType } from '../formatters/index.js';
|
|
4
|
+
import { Progress } from '../ui/progress.js';
|
|
4
5
|
export class ListOrganizations extends BaseCommand {
|
|
5
6
|
constructor(options) {
|
|
6
7
|
super(options);
|
|
7
8
|
}
|
|
8
9
|
async execute(options = {}) {
|
|
10
|
+
const format = options.format || 'plain';
|
|
11
|
+
const spinner = Progress.spinner('Fetching organizations…', { format });
|
|
9
12
|
try {
|
|
10
13
|
const organizations = await this.client.getOrganizations();
|
|
14
|
+
spinner.stop();
|
|
11
15
|
if (options.debug) {
|
|
12
16
|
logger.debug(`Fetched ${organizations.length} organizations`);
|
|
13
17
|
}
|
|
@@ -16,9 +20,11 @@ export class ListOrganizations extends BaseCommand {
|
|
|
16
20
|
// Format and output the organizations
|
|
17
21
|
const output = formatter.formatOrganizations(organizations, { debug: options.debug });
|
|
18
22
|
logger.console(output);
|
|
23
|
+
// Success is implicit - data display confirms retrieval
|
|
19
24
|
return 0; // Success
|
|
20
25
|
}
|
|
21
26
|
catch (error) {
|
|
27
|
+
spinner.stop();
|
|
22
28
|
this.handleError(error, options.debug);
|
|
23
29
|
return 1; // Error
|
|
24
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListOrganizations.js","sourceRoot":"/","sources":["commands/ListOrganizations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAyB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"ListOrganizations.js","sourceRoot":"/","sources":["commands/ListOrganizations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAyB,MAAM,wBAAwB,CAAC;AAE9E,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK7C,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAChD,YAAY,OAAsC;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,UAA+B,EAAE;QACpD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC;QACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,yBAAyB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAExE,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;YAC3D,OAAO,CAAC,IAAI,EAAE,CAAC;YAEf,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAClB,MAAM,CAAC,KAAK,CAAC,WAAW,aAAa,CAAC,MAAM,gBAAgB,CAAC,CAAC;YAChE,CAAC;YAED,gCAAgC;YAChC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,YAAY,EAAE,OAAO,CAA0B,CAAC;YAElG,sCAAsC;YACtC,MAAM,MAAM,GAAG,SAAS,CAAC,mBAAmB,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YACtF,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACvB,wDAAwD;YAExD,OAAO,CAAC,CAAC,CAAC,UAAU;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YACvC,OAAO,CAAC,CAAC,CAAC,QAAQ;QACpB,CAAC;IACH,CAAC;CACF","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\nimport { FormatterType, OrganizationFormatter } from '../formatters/index.js';\n\nimport { Progress } from '../ui/progress.js';\n\nexport interface OrganizationOptions extends BaseCommandOptions {\n}\n\nexport class ListOrganizations extends BaseCommand {\n constructor(options?: Partial<OrganizationOptions>) {\n super(options);\n }\n \n public async execute(options: OrganizationOptions = {}): Promise<number> { \n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching organizations…', { format });\n \n try {\n const organizations = await this.client.getOrganizations();\n spinner.stop();\n \n if (options.debug) {\n logger.debug(`Fetched ${organizations.length} organizations`);\n }\n \n // Get the appropriate formatter\n const formatter = this.getFormatter(FormatterType.ORGANIZATION, options) as OrganizationFormatter;\n \n // Format and output the organizations\n const output = formatter.formatOrganizations(organizations, { debug: options.debug });\n logger.console(output);\n // Success is implicit - data display confirms retrieval\n \n return 0; // Success\n } catch (error) {\n spinner.stop();\n this.handleError(error, options.debug);\n return 1; // Error\n }\n }\n} "]}
|
|
@@ -2,8 +2,10 @@ import { BaseCommand } from './BaseCommand.js';
|
|
|
2
2
|
import { getPipelineFormatter } from '../formatters/index.js';
|
|
3
3
|
import Fuse from 'fuse.js';
|
|
4
4
|
import { logger } from '../services/logger.js';
|
|
5
|
+
import { Progress } from '../ui/progress.js';
|
|
5
6
|
export class ListPipelines extends BaseCommand {
|
|
6
|
-
BATCH_SIZE =
|
|
7
|
+
BATCH_SIZE = 50; // Reasonable batch size for API calls
|
|
8
|
+
DEFAULT_LIMIT = 50; // Default number of pipelines to show
|
|
7
9
|
constructor(options) {
|
|
8
10
|
super(options);
|
|
9
11
|
}
|
|
@@ -25,6 +27,7 @@ export class ListPipelines extends BaseCommand {
|
|
|
25
27
|
else {
|
|
26
28
|
await this.listPipelines([org], options);
|
|
27
29
|
}
|
|
30
|
+
// Success is implicit - data display confirms retrieval
|
|
28
31
|
return 0; // Success
|
|
29
32
|
}
|
|
30
33
|
catch (error) {
|
|
@@ -34,14 +37,44 @@ export class ListPipelines extends BaseCommand {
|
|
|
34
37
|
}
|
|
35
38
|
async listPipelines(organizations, options) {
|
|
36
39
|
let allPipelines = [];
|
|
37
|
-
|
|
40
|
+
let totalBeforeFilter = 0;
|
|
41
|
+
let hasMorePipelines = false; // Track if there are more pipelines available beyond what we fetched
|
|
42
|
+
// Use progress bar for multiple orgs, spinner for single org
|
|
43
|
+
const format = options.format || 'plain';
|
|
44
|
+
const useProgressBar = organizations.length > 1 && format === 'plain';
|
|
45
|
+
const orgProgress = useProgressBar ? Progress.bar({
|
|
46
|
+
total: organizations.length,
|
|
47
|
+
label: 'Processing organizations',
|
|
48
|
+
format: format
|
|
49
|
+
}) : null;
|
|
50
|
+
for (let orgIndex = 0; orgIndex < organizations.length; orgIndex++) {
|
|
51
|
+
const org = organizations[orgIndex];
|
|
52
|
+
// Use different progress indicators based on context
|
|
53
|
+
let spinner = null;
|
|
54
|
+
const pageProgress = useProgressBar ? Progress.spinner(`Loading pipelines from ${org}...`, { format }) : null;
|
|
55
|
+
if (!useProgressBar) {
|
|
56
|
+
// For single org, use spinner (existing behavior)
|
|
57
|
+
spinner = Progress.spinner(`Fetching pipelines from ${org}…`, { format });
|
|
58
|
+
}
|
|
38
59
|
try {
|
|
39
60
|
const batchSize = this.BATCH_SIZE;
|
|
40
61
|
let hasNextPage = true;
|
|
41
62
|
let cursor = null;
|
|
42
|
-
|
|
43
|
-
const resultLimit =
|
|
63
|
+
// Use default limit if no count specified
|
|
64
|
+
const resultLimit = options.count !== undefined
|
|
65
|
+
? parseInt(options.count, 10)
|
|
66
|
+
: this.DEFAULT_LIMIT;
|
|
67
|
+
// Update org progress if using progress bar
|
|
68
|
+
if (orgProgress) {
|
|
69
|
+
orgProgress.update(orgIndex, `Organization: ${org}`);
|
|
70
|
+
}
|
|
71
|
+
let pageCount = 0;
|
|
72
|
+
let orgPipelineCount = 0;
|
|
44
73
|
while (hasNextPage && allPipelines.length < resultLimit) {
|
|
74
|
+
pageCount++;
|
|
75
|
+
if (pageProgress) {
|
|
76
|
+
pageProgress.update(pageCount, `Loading ${org} (page ${pageCount})...`);
|
|
77
|
+
}
|
|
45
78
|
if (options.debug) {
|
|
46
79
|
logger.debug(`Fetching batch of pipelines from org ${org}, cursor: ${cursor || 'initial'}`);
|
|
47
80
|
}
|
|
@@ -63,6 +96,7 @@ export class ListPipelines extends BaseCommand {
|
|
|
63
96
|
organization: org
|
|
64
97
|
};
|
|
65
98
|
});
|
|
99
|
+
orgPipelineCount += pipelines.length;
|
|
66
100
|
allPipelines = allPipelines.concat(pipelines);
|
|
67
101
|
}
|
|
68
102
|
// Check if we need to fetch more pages
|
|
@@ -74,21 +108,51 @@ export class ListPipelines extends BaseCommand {
|
|
|
74
108
|
logger.debug(`More pages available, cursor: ${cursor}`);
|
|
75
109
|
}
|
|
76
110
|
}
|
|
77
|
-
//
|
|
78
|
-
if (
|
|
111
|
+
// Stop after getting enough results
|
|
112
|
+
if (allPipelines.length >= resultLimit) {
|
|
113
|
+
// If we hit the limit and there are more pages, remember that
|
|
114
|
+
if (hasNextPage) {
|
|
115
|
+
hasMorePipelines = true;
|
|
116
|
+
}
|
|
79
117
|
break;
|
|
80
118
|
}
|
|
81
119
|
}
|
|
120
|
+
// Stop the appropriate progress indicator
|
|
121
|
+
if (pageProgress) {
|
|
122
|
+
pageProgress.stop();
|
|
123
|
+
if (options.debug) {
|
|
124
|
+
logger.debug(`Loaded ${orgPipelineCount} pipelines from ${org} in ${pageCount} pages`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (spinner) {
|
|
128
|
+
spinner.stop();
|
|
129
|
+
}
|
|
82
130
|
}
|
|
83
131
|
catch (error) {
|
|
132
|
+
// Clean up any active progress indicators
|
|
133
|
+
if (spinner) {
|
|
134
|
+
spinner.stop();
|
|
135
|
+
}
|
|
136
|
+
if (pageProgress) {
|
|
137
|
+
pageProgress.stop();
|
|
138
|
+
}
|
|
84
139
|
throw new Error(`Error fetching pipelines for organization ${org}`, { cause: error });
|
|
85
140
|
}
|
|
86
141
|
}
|
|
87
|
-
//
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
142
|
+
// Complete the org progress bar if used
|
|
143
|
+
if (orgProgress) {
|
|
144
|
+
orgProgress.complete(`Loaded ${allPipelines.length} pipelines from ${organizations.length} organizations`);
|
|
145
|
+
}
|
|
146
|
+
// Apply limit and track truncation
|
|
147
|
+
const requestedLimit = options.count
|
|
148
|
+
? parseInt(options.count, 10)
|
|
149
|
+
: this.DEFAULT_LIMIT;
|
|
150
|
+
const truncated = allPipelines.length > requestedLimit;
|
|
151
|
+
if (allPipelines.length > requestedLimit) {
|
|
152
|
+
allPipelines = allPipelines.slice(0, requestedLimit);
|
|
91
153
|
}
|
|
154
|
+
// Track total before filter for context
|
|
155
|
+
totalBeforeFilter = allPipelines.length;
|
|
92
156
|
if (options.filter && allPipelines.length > 0) {
|
|
93
157
|
if (options.debug) {
|
|
94
158
|
logger.debug(`Applying fuzzy filter '${options.filter}' to ${allPipelines.length} pipelines`);
|
|
@@ -105,9 +169,20 @@ export class ListPipelines extends BaseCommand {
|
|
|
105
169
|
logger.debug(`Filtered to ${allPipelines.length} pipelines matching '${options.filter}'`);
|
|
106
170
|
}
|
|
107
171
|
}
|
|
108
|
-
|
|
172
|
+
// Prepare formatter options with context
|
|
173
|
+
const formatterOptions = {
|
|
174
|
+
debug: options.debug,
|
|
175
|
+
filterActive: !!options.filter,
|
|
176
|
+
filterText: options.filter,
|
|
177
|
+
truncated: truncated || hasMorePipelines, // Either truncated locally or more available on server
|
|
178
|
+
hasMoreAvailable: hasMorePipelines,
|
|
179
|
+
totalBeforeFilter: totalBeforeFilter,
|
|
180
|
+
requestedLimit: requestedLimit,
|
|
181
|
+
organizationsCount: organizations.length,
|
|
182
|
+
orgSpecified: !!options.org
|
|
183
|
+
};
|
|
109
184
|
const formatter = getPipelineFormatter(format);
|
|
110
|
-
const output = formatter.formatPipelines(allPipelines, organizations);
|
|
185
|
+
const output = formatter.formatPipelines(allPipelines, organizations, formatterOptions);
|
|
111
186
|
logger.console(output);
|
|
112
187
|
}
|
|
113
188
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListPipelines.js","sourceRoot":"/","sources":["commands/ListPipelines.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { getPipelineFormatter } from '../formatters/index.js';\nimport Fuse from 'fuse.js';\nimport { Pipeline } from '../types/index.js';\nimport { logger } from '../services/logger.js';\nexport interface PipelineOptions extends BaseCommandOptions {\n org?: string;\n count?: string;\n}\n\nexport class ListPipelines extends BaseCommand {\n readonly BATCH_SIZE = 500;\n \n constructor(options?: Partial<PipelineOptions>) {\n super(options);\n }\n \n async execute(options: PipelineOptions): Promise<number> {\n await this.ensureInitialized();\n \n try {\n // Need to get organization info if not provided\n const org = options.org;\n if (!org) {\n try {\n const orgs = await this.client.getViewerOrganizationSlugs();\n await this.listPipelines(orgs, options);\n } catch (error) {\n logger.error(error as any, 'Failed to determine your organizations');\n throw new Error('Failed to determine your organizations', { cause: error });\n }\n } else {\n await this.listPipelines([org], options);\n }\n \n return 0; // Success\n } catch (error) {\n this.handleError(error, options.debug);\n return 1; // Error\n }\n }\n \n private async listPipelines(organizations: string[], options: PipelineOptions): Promise<void> {\n let allPipelines: Pipeline[] = [];\n \n for (const org of organizations) {\n try {\n const batchSize = this.BATCH_SIZE;\n let hasNextPage = true;\n let cursor: string | null = null;\n const limitResults = options.count !== undefined;\n const resultLimit = limitResults ? parseInt(options.count as string, 10) : Infinity;\n \n while (hasNextPage && allPipelines.length < resultLimit) {\n if (options.debug) {\n logger.debug(`Fetching batch of pipelines from org ${org}, cursor: ${cursor || 'initial'}`);\n }\n \n const data = await this.client.getPipelines(org, batchSize, cursor || undefined);\n \n if (data?.organization?.pipelines?.edges) {\n // Add org information to each pipeline for display\n const pipelines = data.organization.pipelines.edges\n .filter(edge => edge !== null && edge.node !== null)\n .map(edge => {\n const node = edge!.node!;\n return {\n uuid: node.uuid || '',\n id: node.id || '',\n name: node.name || '',\n slug: node.slug || '',\n description: node.description,\n url: node.url || '',\n repository: node.repository,\n organization: org\n } as Pipeline;\n });\n \n allPipelines = allPipelines.concat(pipelines);\n }\n \n // Check if we need to fetch more pages\n hasNextPage = data?.organization?.pipelines?.pageInfo?.hasNextPage || false;\n cursor = data?.organization?.pipelines?.pageInfo?.endCursor || null;\n \n if (options.debug) {\n logger.debug(`Fetched batch of ${data?.organization?.pipelines?.edges?.length || 0} pipelines from org ${org}`);\n if (hasNextPage) {\n logger.debug(`More pages available, cursor: ${cursor}`);\n }\n }\n \n // If we're limiting results, stop after getting enough\n if (limitResults && allPipelines.length >= resultLimit) {\n break;\n }\n }\n } catch (error) {\n throw new Error(`Error fetching pipelines for organization ${org}`, { cause: error });\n }\n }\n \n // Apply limit if specified\n if (options.count) {\n const limit = parseInt(options.count, 10);\n allPipelines = allPipelines.slice(0, limit);\n }\n \n if (options.filter && allPipelines.length > 0) {\n if (options.debug) {\n logger.debug(`Applying fuzzy filter '${options.filter}' to ${allPipelines.length} pipelines`);\n }\n \n const fuse = new Fuse(allPipelines, {\n keys: ['name', 'slug', 'description'],\n threshold: 0.4,\n includeScore: true,\n shouldSort: true\n });\n \n const searchResults = fuse.search(options.filter);\n allPipelines = searchResults.map(result => result.item);\n \n if (options.debug) {\n logger.debug(`Filtered to ${allPipelines.length} pipelines matching '${options.filter}'`);\n }\n }\n \n const format = options.format || 'plain';\n const formatter = getPipelineFormatter(format);\n const output = formatter.formatPipelines(allPipelines, organizations);\n \n logger.console(output);\n }\n} "]}
|
|
1
|
+
{"version":3,"file":"ListPipelines.js","sourceRoot":"/","sources":["commands/ListPipelines.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { getPipelineFormatter } from '../formatters/index.js';\nimport { PipelineFormatterOptions } from '../formatters/pipelines/Formatter.js';\nimport Fuse from 'fuse.js';\nimport { Pipeline } from '../types/index.js';\nimport { logger } from '../services/logger.js';\n\nimport { Progress } from '../ui/progress.js';\nexport interface PipelineOptions extends BaseCommandOptions {\n org?: string;\n count?: string;\n filter?: string;\n}\n\nexport class ListPipelines extends BaseCommand {\n readonly BATCH_SIZE = 50; // Reasonable batch size for API calls\n readonly DEFAULT_LIMIT = 50; // Default number of pipelines to show\n \n constructor(options?: Partial<PipelineOptions>) {\n super(options);\n }\n \n async execute(options: PipelineOptions): Promise<number> {\n await this.ensureInitialized();\n \n try {\n\n // Need to get organization info if not provided\n const org = options.org;\n if (!org) {\n try {\n const orgs = await this.client.getViewerOrganizationSlugs();\n await this.listPipelines(orgs, options);\n } catch (error) {\n logger.error(error as any, 'Failed to determine your organizations');\n throw new Error('Failed to determine your organizations', { cause: error });\n }\n } else {\n await this.listPipelines([org], options);\n }\n \n // Success is implicit - data display confirms retrieval\n return 0; // Success\n } catch (error) {\n this.handleError(error, options.debug);\n return 1; // Error\n }\n }\n \n private async listPipelines(organizations: string[], options: PipelineOptions): Promise<void> {\n let allPipelines: Pipeline[] = [];\n let totalBeforeFilter = 0;\n let hasMorePipelines = false; // Track if there are more pipelines available beyond what we fetched\n \n // Use progress bar for multiple orgs, spinner for single org\n const format = options.format || 'plain';\n const useProgressBar = organizations.length > 1 && format === 'plain';\n const orgProgress = useProgressBar ? Progress.bar({\n total: organizations.length,\n label: 'Processing organizations',\n format: format\n }) : null;\n \n for (let orgIndex = 0; orgIndex < organizations.length; orgIndex++) {\n const org = organizations[orgIndex];\n \n // Use different progress indicators based on context\n let spinner = null;\n const pageProgress = useProgressBar ? Progress.spinner(\n `Loading pipelines from ${org}...`,\n { format }\n ) : null;\n \n if (!useProgressBar) {\n // For single org, use spinner (existing behavior)\n spinner = Progress.spinner(`Fetching pipelines from ${org}…`, { format });\n }\n \n try {\n const batchSize = this.BATCH_SIZE;\n let hasNextPage = true;\n let cursor: string | null = null;\n // Use default limit if no count specified\n const resultLimit = options.count !== undefined \n ? parseInt(options.count as string, 10) \n : this.DEFAULT_LIMIT;\n \n // Update org progress if using progress bar\n if (orgProgress) {\n orgProgress.update(orgIndex, `Organization: ${org}`);\n }\n \n let pageCount = 0;\n let orgPipelineCount = 0;\n \n while (hasNextPage && allPipelines.length < resultLimit) {\n pageCount++;\n \n if (pageProgress) {\n pageProgress.update(pageCount, `Loading ${org} (page ${pageCount})...`);\n }\n \n if (options.debug) {\n logger.debug(`Fetching batch of pipelines from org ${org}, cursor: ${cursor || 'initial'}`);\n }\n \n const data = await this.client.getPipelines(org, batchSize, cursor || undefined);\n \n if (data?.organization?.pipelines?.edges) {\n // Add org information to each pipeline for display\n const pipelines = data.organization.pipelines.edges\n .filter(edge => edge !== null && edge.node !== null)\n .map(edge => {\n const node = edge!.node!;\n return {\n uuid: node.uuid || '',\n id: node.id || '',\n name: node.name || '',\n slug: node.slug || '',\n description: node.description,\n url: node.url || '',\n repository: node.repository,\n organization: org\n } as Pipeline;\n });\n \n orgPipelineCount += pipelines.length;\n allPipelines = allPipelines.concat(pipelines);\n }\n \n // Check if we need to fetch more pages\n hasNextPage = data?.organization?.pipelines?.pageInfo?.hasNextPage || false;\n cursor = data?.organization?.pipelines?.pageInfo?.endCursor || null;\n \n if (options.debug) {\n logger.debug(`Fetched batch of ${data?.organization?.pipelines?.edges?.length || 0} pipelines from org ${org}`);\n if (hasNextPage) {\n logger.debug(`More pages available, cursor: ${cursor}`);\n }\n }\n \n // Stop after getting enough results\n if (allPipelines.length >= resultLimit) {\n // If we hit the limit and there are more pages, remember that\n if (hasNextPage) {\n hasMorePipelines = true;\n }\n break;\n }\n }\n \n // Stop the appropriate progress indicator\n if (pageProgress) {\n pageProgress.stop();\n if (options.debug) {\n logger.debug(`Loaded ${orgPipelineCount} pipelines from ${org} in ${pageCount} pages`);\n }\n } else if (spinner) {\n spinner.stop();\n }\n } catch (error) {\n // Clean up any active progress indicators \n if (spinner) {\n spinner.stop();\n }\n if (pageProgress) {\n pageProgress.stop();\n }\n throw new Error(`Error fetching pipelines for organization ${org}`, { cause: error });\n }\n }\n \n // Complete the org progress bar if used\n if (orgProgress) {\n orgProgress.complete(`Loaded ${allPipelines.length} pipelines from ${organizations.length} organizations`);\n }\n \n // Apply limit and track truncation\n const requestedLimit = options.count \n ? parseInt(options.count, 10) \n : this.DEFAULT_LIMIT;\n \n const truncated = allPipelines.length > requestedLimit;\n \n if (allPipelines.length > requestedLimit) {\n allPipelines = allPipelines.slice(0, requestedLimit);\n }\n \n // Track total before filter for context\n totalBeforeFilter = allPipelines.length;\n \n if (options.filter && allPipelines.length > 0) {\n if (options.debug) {\n logger.debug(`Applying fuzzy filter '${options.filter}' to ${allPipelines.length} pipelines`);\n }\n \n const fuse = new Fuse(allPipelines, {\n keys: ['name', 'slug', 'description'],\n threshold: 0.4,\n includeScore: true,\n shouldSort: true\n });\n \n const searchResults = fuse.search(options.filter);\n allPipelines = searchResults.map(result => result.item);\n \n if (options.debug) {\n logger.debug(`Filtered to ${allPipelines.length} pipelines matching '${options.filter}'`);\n }\n }\n \n // Prepare formatter options with context\n const formatterOptions: PipelineFormatterOptions = {\n debug: options.debug,\n filterActive: !!options.filter,\n filterText: options.filter,\n truncated: truncated || hasMorePipelines, // Either truncated locally or more available on server\n hasMoreAvailable: hasMorePipelines,\n totalBeforeFilter: totalBeforeFilter,\n requestedLimit: requestedLimit,\n organizationsCount: organizations.length,\n orgSpecified: !!options.org\n };\n \n const formatter = getPipelineFormatter(format);\n const output = formatter.formatPipelines(allPipelines, organizations, formatterOptions);\n \n logger.console(output);\n }\n} "]}
|
|
@@ -2,11 +2,15 @@ import { BaseCommand } from './BaseCommand.js';
|
|
|
2
2
|
import { logger } from '../services/logger.js';
|
|
3
3
|
import prompts from 'prompts';
|
|
4
4
|
import { FormatterFactory, FormatterType } from '../formatters/FormatterFactory.js';
|
|
5
|
+
import { isRunningInAlfred } from '../utils/alfred.js';
|
|
6
|
+
import { Reporter } from '../ui/reporter.js';
|
|
5
7
|
export class ManageToken extends BaseCommand {
|
|
6
8
|
formatter;
|
|
9
|
+
reporter;
|
|
7
10
|
constructor(options) {
|
|
8
11
|
super(options);
|
|
9
12
|
this.formatter = FormatterFactory.getFormatter(FormatterType.TOKEN, options?.format);
|
|
13
|
+
this.reporter = new Reporter(options?.format || 'plain', options?.quiet, options?.tips);
|
|
10
14
|
}
|
|
11
15
|
static get requiresToken() {
|
|
12
16
|
return false;
|
|
@@ -18,6 +22,12 @@ export class ManageToken extends BaseCommand {
|
|
|
18
22
|
if (options.store) {
|
|
19
23
|
const { success, errors } = await this.storeToken();
|
|
20
24
|
if (success) {
|
|
25
|
+
// Add next-steps hints after successful token storage (no redundant success message)
|
|
26
|
+
this.reporter.tips([
|
|
27
|
+
'Verify access with: bktide token --check',
|
|
28
|
+
'Explore your organizations: bktide orgs',
|
|
29
|
+
'List pipelines: bktide pipelines'
|
|
30
|
+
]);
|
|
21
31
|
return 0;
|
|
22
32
|
}
|
|
23
33
|
else {
|
|
@@ -30,7 +40,7 @@ export class ManageToken extends BaseCommand {
|
|
|
30
40
|
await this.resetToken();
|
|
31
41
|
}
|
|
32
42
|
else if (options.check) {
|
|
33
|
-
const { errors } = await this.checkToken();
|
|
43
|
+
const { errors } = await this.checkToken({ format: options.format });
|
|
34
44
|
if (errors.length > 0) {
|
|
35
45
|
const formattedErrors = this.formatter.formatAuthErrors('validating', errors);
|
|
36
46
|
logger.console(formattedErrors);
|
|
@@ -38,7 +48,7 @@ export class ManageToken extends BaseCommand {
|
|
|
38
48
|
}
|
|
39
49
|
}
|
|
40
50
|
else {
|
|
41
|
-
const { errors } = await this.checkOrStoreToken();
|
|
51
|
+
const { errors } = await this.checkOrStoreToken({ format: options.format });
|
|
42
52
|
if (errors.length > 0) {
|
|
43
53
|
const formattedErrors = this.formatter.formatAuthErrors('checking or storing', errors);
|
|
44
54
|
logger.console(formattedErrors);
|
|
@@ -61,6 +71,9 @@ export class ManageToken extends BaseCommand {
|
|
|
61
71
|
tokenToStore = this.options.token;
|
|
62
72
|
}
|
|
63
73
|
else {
|
|
74
|
+
if (isRunningInAlfred()) {
|
|
75
|
+
return { success: false, errors: [new Error('In Alfred, set token via Workflow Configuration.')] };
|
|
76
|
+
}
|
|
64
77
|
// Otherwise prompt the user
|
|
65
78
|
const response = await prompts({
|
|
66
79
|
type: 'password',
|
|
@@ -79,7 +92,9 @@ export class ManageToken extends BaseCommand {
|
|
|
79
92
|
return { success: false, errors: [new Error('No token provided')] };
|
|
80
93
|
}
|
|
81
94
|
// Validate the token using the CredentialManager
|
|
82
|
-
const validationResult = await BaseCommand.credentialManager.validateToken(tokenToStore
|
|
95
|
+
const validationResult = await BaseCommand.credentialManager.validateToken(tokenToStore, {
|
|
96
|
+
showProgress: true // Show progress when validating during store
|
|
97
|
+
});
|
|
83
98
|
if (!validationResult.canListOrganizations) {
|
|
84
99
|
throw new Error('Token is invalid or does not have access to list organizations');
|
|
85
100
|
}
|
|
@@ -121,8 +136,8 @@ export class ManageToken extends BaseCommand {
|
|
|
121
136
|
logger.console(formattedError);
|
|
122
137
|
}
|
|
123
138
|
}
|
|
124
|
-
async checkOrStoreToken() {
|
|
125
|
-
const { status, errors } = await this.checkToken();
|
|
139
|
+
async checkOrStoreToken(options) {
|
|
140
|
+
const { status, errors } = await this.checkToken(options);
|
|
126
141
|
if (!status.hasToken || !status.isValid) {
|
|
127
142
|
const { success, errors: storeErrors } = await this.storeToken();
|
|
128
143
|
if (success) {
|
|
@@ -134,8 +149,11 @@ export class ManageToken extends BaseCommand {
|
|
|
134
149
|
}
|
|
135
150
|
return { stored: false, errors };
|
|
136
151
|
}
|
|
137
|
-
async checkToken() {
|
|
138
|
-
|
|
152
|
+
async checkToken(options) {
|
|
153
|
+
// In Alfred, check presence of env var as token existence
|
|
154
|
+
const hasToken = isRunningInAlfred()
|
|
155
|
+
? Boolean(process.env.BUILDKITE_API_TOKEN || process.env.BK_TOKEN)
|
|
156
|
+
: await BaseCommand.credentialManager.hasToken();
|
|
139
157
|
let isValid = false;
|
|
140
158
|
let validation = {
|
|
141
159
|
valid: false,
|
|
@@ -145,7 +163,9 @@ export class ManageToken extends BaseCommand {
|
|
|
145
163
|
const errors = [];
|
|
146
164
|
if (hasToken) {
|
|
147
165
|
// Get the token for validation
|
|
148
|
-
const token =
|
|
166
|
+
const token = isRunningInAlfred()
|
|
167
|
+
? (process.env.BUILDKITE_API_TOKEN || process.env.BK_TOKEN)
|
|
168
|
+
: await BaseCommand.credentialManager.getToken();
|
|
149
169
|
if (!token) {
|
|
150
170
|
const tokenStatus = {
|
|
151
171
|
hasToken: false,
|
|
@@ -160,7 +180,10 @@ export class ManageToken extends BaseCommand {
|
|
|
160
180
|
}
|
|
161
181
|
// Validate the token using the CredentialManager
|
|
162
182
|
try {
|
|
163
|
-
validation = await BaseCommand.credentialManager.validateToken(token
|
|
183
|
+
validation = await BaseCommand.credentialManager.validateToken(token, {
|
|
184
|
+
format: options?.format,
|
|
185
|
+
showProgress: false // Don't show progress since we're showing formatted output
|
|
186
|
+
});
|
|
164
187
|
isValid = validation.valid && validation.canListOrganizations;
|
|
165
188
|
}
|
|
166
189
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ManageToken.js","sourceRoot":"/","sources":["commands/ManageToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAWpF,MAAM,OAAO,WAAY,SAAQ,WAAW;IAClC,SAAS,CAAiB;IAElC,YAAY,OAA+B;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,gBAAgB,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAmB,CAAC;IACzG,CAAC;IAED,MAAM,KAAK,aAAa;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAqB;QACjC,IAAI,CAAC;YACH,+DAA+D;YAC/D,6DAA6D;YAE7D,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAClB,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpD,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,CAAC,CAAC;gBACX,CAAC;qBAAM,CAAC;oBACN,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;oBAC3E,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;oBAChC,OAAO,CAAC,CAAC;gBACX,CAAC;YACH,CAAC;iBAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBACzB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1B,CAAC;iBAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBACzB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;oBAC9E,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;oBAChC,OAAO,CAAC,CAAC;gBACX,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAClD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;oBACvF,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;oBAChC,OAAO,CAAC,CAAC;gBACX,CAAC;YACH,CAAC;YAED,OAAO,CAAC,CAAC,CAAC,UAAU;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YACtE,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YAC/B,OAAO,CAAC,CAAC,CAAC,QAAQ;QACpB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC;YACH,IAAI,YAAgC,CAAC;YAErC,0CAA0C;YAC1C,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACvB,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,4BAA4B;gBAC5B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;oBAC7B,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,OAAO;oBACb,OAAO,EAAE,iCAAiC;oBAC1C,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,4BAA4B;iBAC1E,CAAC,CAAC;gBAEH,8CAA8C;gBAC9C,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAAE,CAAC;gBAC5E,CAAC;gBAED,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC;YAChC,CAAC;YAED,iDAAiD;YACjD,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC;YACtE,CAAC;YAED,iDAAiD;YACjD,MAAM,gBAAgB,GAAG,MAAM,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;YAEzF,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,CAAC;gBAC3C,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;YACpF,CAAC;YAED,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;gBAC5B,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,aAAa,CAAC;qBAC/D,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;qBACnF,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE;oBACrB,MAAM,WAAW,GAAG,EAAE,CAAC;oBACvB,IAAI,CAAC,MAAM,CAAC,OAAO;wBAAE,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACjD,IAAI,CAAC,MAAM,CAAC,MAAM;wBAAE,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC/C,IAAI,CAAC,MAAM,CAAC,aAAa;wBAAE,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;oBAC7D,OAAO,GAAG,GAAG,KAAK,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC9C,CAAC,CAAC,CAAC;gBACL,MAAM,IAAI,KAAK,CAAC,mDAAmD,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/F,CAAC;YAED,gCAAgC;YAChC,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,iBAAiB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7C,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YAChE,IAAI,OAAO,GAAG,KAAK,CAAC;YAEpB,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,GAAG,MAAM,WAAW,CAAC,iBAAiB,CAAC,WAAW,EAAE,CAAC;YAC9D,CAAC;YAED,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACjF,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YACtE,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB;QAC7B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACnD,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACxC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACjE,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;YAChD,CAAC;QACH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QAChE,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,UAAU,GAA0B;YACtC,KAAK,EAAE,KAAK;YACZ,oBAAoB,EAAE,KAAK;YAC3B,aAAa,EAAE,EAAE;SAClB,CAAC;QACF,MAAM,MAAM,GAAc,EAAE,CAAC;QAE7B,IAAI,QAAQ,EAAE,CAAC;YACb,+BAA+B;YAC/B,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YAC7D,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,WAAW,GAAgB;oBAC/B,QAAQ,EAAE,KAAK;oBACf,OAAO,EAAE,KAAK;oBACd,UAAU,EAAE;wBACV,KAAK,EAAE,KAAK;wBACZ,oBAAoB,EAAE,KAAK;wBAC3B,aAAa,EAAE,EAAE;qBAClB;iBACF,CAAC;gBACF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;YACzC,CAAC;YAED,iDAAiD;YACjD,IAAI,CAAC;gBACH,UAAU,GAAG,MAAM,WAAW,CAAC,iBAAiB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBACtE,OAAO,GAAG,UAAU,CAAC,KAAK,IAAI,UAAU,CAAC,oBAAoB,CAAC;YAChE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAgB;YAC/B,QAAQ;YACR,OAAO;YACP,UAAU;SACX,CAAC;QAEF,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;QACtE,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAEhC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC;CACF","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\nimport prompts from 'prompts';\nimport { FormatterFactory, FormatterType } from '../formatters/FormatterFactory.js';\nimport { TokenFormatter } from '../formatters/token/Formatter.js';\nimport { TokenStatus, TokenValidationStatus, TokenCheckResult, TokenCheckOrStoreResult, TokenStoreResult } from '../types/credentials.js';\n\nexport interface TokenOptions extends BaseCommandOptions {\n check?: boolean;\n store?: boolean;\n reset?: boolean;\n token?: string;\n}\n\nexport class ManageToken extends BaseCommand {\n private formatter: TokenFormatter;\n\n constructor(options?: Partial<TokenOptions>) {\n super(options);\n this.formatter = FormatterFactory.getFormatter(FormatterType.TOKEN, options?.format) as TokenFormatter;\n }\n\n static get requiresToken(): boolean {\n return false;\n }\n\n async execute(options: TokenOptions): Promise<number> {\n try {\n // Handle option priorities: if multiple options are provided, \n // we'll process them in this priority: store > reset > check\n \n if (options.store) {\n const { success, errors } = await this.storeToken();\n if (success) {\n return 0;\n } else {\n const formattedErrors = this.formatter.formatAuthErrors('storing', errors);\n logger.console(formattedErrors);\n return 1;\n }\n } else if (options.reset) {\n await this.resetToken();\n } else if (options.check) {\n const { errors } = await this.checkToken();\n if (errors.length > 0) {\n const formattedErrors = this.formatter.formatAuthErrors('validating', errors);\n logger.console(formattedErrors);\n return 0;\n }\n } else {\n const { errors } = await this.checkOrStoreToken();\n if (errors.length > 0) {\n const formattedErrors = this.formatter.formatAuthErrors('checking or storing', errors);\n logger.console(formattedErrors);\n return 0;\n }\n }\n \n return 0; // Success\n } catch (error) {\n const formattedError = this.formatter.formatError('executing', error);\n logger.console(formattedError);\n return 1; // Error\n }\n }\n\n private async storeToken(): Promise<TokenStoreResult> {\n try {\n let tokenToStore: string | undefined;\n\n // If token is provided in options, use it\n if (this.options.token) {\n tokenToStore = this.options.token;\n } else {\n // Otherwise prompt the user\n const response = await prompts({\n type: 'password',\n name: 'token',\n message: 'Enter your Buildkite API token:',\n validate: value => value.length > 0 ? true : 'Please enter a valid token'\n });\n \n // Check if user cancelled the prompt (Ctrl+C)\n if (!response.token) {\n return { success: false, errors: [new Error('Token storage cancelled')] };\n }\n \n tokenToStore = response.token;\n }\n\n // Ensure we have a valid token before proceeding\n if (!tokenToStore) {\n return { success: false, errors: [new Error('No token provided')] };\n }\n \n // Validate the token using the CredentialManager\n const validationResult = await BaseCommand.credentialManager.validateToken(tokenToStore);\n \n if (!validationResult.canListOrganizations) {\n throw new Error('Token is invalid or does not have access to list organizations');\n }\n\n if (!validationResult.valid) {\n const invalidOrgs = Object.entries(validationResult.organizations)\n .filter(([_, status]) => !status.graphql || !status.builds || !status.organizations)\n .map(([org, status]) => {\n const invalidApis = [];\n if (!status.graphql) invalidApis.push('GraphQL');\n if (!status.builds) invalidApis.push('Builds');\n if (!status.organizations) invalidApis.push('Organizations');\n return `${org} (${invalidApis.join(', ')})`;\n });\n throw new Error(`Token has limited access in some organizations: ${invalidOrgs.join(', ')}`);\n }\n \n // Store the token if it's valid\n const success = await BaseCommand.credentialManager.saveToken(tokenToStore);\n \n return { success, errors: [] };\n } catch (error) {\n return { success: false, errors: [error] };\n }\n }\n\n private async resetToken(): Promise<void> {\n try {\n const hadToken = await BaseCommand.credentialManager.hasToken();\n let success = false;\n \n if (hadToken) {\n success = await BaseCommand.credentialManager.deleteToken();\n }\n \n const formattedResult = this.formatter.formatTokenResetResult(success, hadToken);\n logger.console(formattedResult);\n } catch (error) {\n const formattedError = this.formatter.formatError('resetting', error);\n logger.console(formattedError);\n }\n }\n\n private async checkOrStoreToken(): Promise<TokenCheckOrStoreResult> {\n const { status, errors } = await this.checkToken();\n if (!status.hasToken || !status.isValid) {\n const { success, errors: storeErrors } = await this.storeToken();\n if (success) {\n return { stored: true, errors: [] };\n } else {\n return { stored: false, errors: storeErrors };\n }\n }\n return { stored: false, errors };\n }\n\n private async checkToken(): Promise<TokenCheckResult> {\n const hasToken = await BaseCommand.credentialManager.hasToken();\n let isValid = false;\n let validation: TokenValidationStatus = { \n valid: false, \n canListOrganizations: false,\n organizations: {} \n };\n const errors: unknown[] = [];\n\n if (hasToken) {\n // Get the token for validation\n const token = await BaseCommand.credentialManager.getToken();\n if (!token) {\n const tokenStatus: TokenStatus = {\n hasToken: false,\n isValid: false,\n validation: { \n valid: false, \n canListOrganizations: false,\n organizations: {} \n }\n };\n return { status: tokenStatus, errors };\n }\n\n // Validate the token using the CredentialManager\n try {\n validation = await BaseCommand.credentialManager.validateToken(token);\n isValid = validation.valid && validation.canListOrganizations;\n } catch (error) {\n errors.push(error);\n }\n }\n \n const tokenStatus: TokenStatus = {\n hasToken,\n isValid,\n validation\n };\n \n const formattedResult = this.formatter.formatTokenStatus(tokenStatus);\n logger.console(formattedResult);\n \n return { status: tokenStatus, errors };\n }\n} "]}
|
|
1
|
+
{"version":3,"file":"ManageToken.js","sourceRoot":"/","sources":["commands/ManageToken.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\nimport prompts from 'prompts';\nimport { FormatterFactory, FormatterType } from '../formatters/FormatterFactory.js';\nimport { TokenFormatter } from '../formatters/token/Formatter.js';\nimport { TokenStatus, TokenValidationStatus, TokenCheckResult, TokenCheckOrStoreResult, TokenStoreResult } from '../types/credentials.js';\nimport { isRunningInAlfred } from '../utils/alfred.js';\nimport { Reporter } from '../ui/reporter.js';\n\nexport interface TokenOptions extends BaseCommandOptions {\n check?: boolean;\n store?: boolean;\n reset?: boolean;\n token?: string;\n tips?: boolean;\n}\n\nexport class ManageToken extends BaseCommand {\n private formatter: TokenFormatter;\n private reporter: Reporter;\n\n constructor(options?: Partial<TokenOptions>) {\n super(options);\n this.formatter = FormatterFactory.getFormatter(FormatterType.TOKEN, options?.format) as TokenFormatter;\n this.reporter = new Reporter(options?.format || 'plain', options?.quiet, options?.tips);\n }\n\n static get requiresToken(): boolean {\n return false;\n }\n\n async execute(options: TokenOptions): Promise<number> {\n try {\n // Handle option priorities: if multiple options are provided, \n // we'll process them in this priority: store > reset > check\n \n if (options.store) {\n const { success, errors } = await this.storeToken();\n if (success) {\n // Add next-steps hints after successful token storage (no redundant success message)\n this.reporter.tips([\n 'Verify access with: bktide token --check',\n 'Explore your organizations: bktide orgs',\n 'List pipelines: bktide pipelines'\n ]);\n return 0;\n } else {\n const formattedErrors = this.formatter.formatAuthErrors('storing', errors);\n logger.console(formattedErrors);\n return 1;\n }\n } else if (options.reset) {\n await this.resetToken();\n } else if (options.check) {\n const { errors } = await this.checkToken({ format: options.format });\n if (errors.length > 0) {\n const formattedErrors = this.formatter.formatAuthErrors('validating', errors);\n logger.console(formattedErrors);\n return 0;\n }\n } else {\n const { errors } = await this.checkOrStoreToken({ format: options.format });\n if (errors.length > 0) {\n const formattedErrors = this.formatter.formatAuthErrors('checking or storing', errors);\n logger.console(formattedErrors);\n return 0;\n }\n }\n \n return 0; // Success\n } catch (error) {\n const formattedError = this.formatter.formatError('executing', error);\n logger.console(formattedError);\n return 1; // Error\n }\n }\n\n private async storeToken(): Promise<TokenStoreResult> {\n try {\n let tokenToStore: string | undefined;\n\n // If token is provided in options, use it\n if (this.options.token) {\n tokenToStore = this.options.token;\n } else {\n if (isRunningInAlfred()) {\n return { success: false, errors: [new Error('In Alfred, set token via Workflow Configuration.')] };\n }\n // Otherwise prompt the user\n const response = await prompts({\n type: 'password',\n name: 'token',\n message: 'Enter your Buildkite API token:',\n validate: value => value.length > 0 ? true : 'Please enter a valid token'\n });\n \n // Check if user cancelled the prompt (Ctrl+C)\n if (!response.token) {\n return { success: false, errors: [new Error('Token storage cancelled')] };\n }\n \n tokenToStore = response.token;\n }\n\n // Ensure we have a valid token before proceeding\n if (!tokenToStore) {\n return { success: false, errors: [new Error('No token provided')] };\n }\n \n // Validate the token using the CredentialManager\n const validationResult = await BaseCommand.credentialManager.validateToken(tokenToStore, {\n showProgress: true // Show progress when validating during store\n });\n \n if (!validationResult.canListOrganizations) {\n throw new Error('Token is invalid or does not have access to list organizations');\n }\n\n if (!validationResult.valid) {\n const invalidOrgs = Object.entries(validationResult.organizations)\n .filter(([_, status]) => !status.graphql || !status.builds || !status.organizations)\n .map(([org, status]) => {\n const invalidApis = [];\n if (!status.graphql) invalidApis.push('GraphQL');\n if (!status.builds) invalidApis.push('Builds');\n if (!status.organizations) invalidApis.push('Organizations');\n return `${org} (${invalidApis.join(', ')})`;\n });\n throw new Error(`Token has limited access in some organizations: ${invalidOrgs.join(', ')}`);\n }\n \n // Store the token if it's valid\n const success = await BaseCommand.credentialManager.saveToken(tokenToStore);\n \n return { success, errors: [] };\n } catch (error) {\n return { success: false, errors: [error] };\n }\n }\n\n private async resetToken(): Promise<void> {\n try {\n const hadToken = await BaseCommand.credentialManager.hasToken();\n let success = false;\n \n if (hadToken) {\n success = await BaseCommand.credentialManager.deleteToken();\n }\n \n const formattedResult = this.formatter.formatTokenResetResult(success, hadToken);\n logger.console(formattedResult);\n } catch (error) {\n const formattedError = this.formatter.formatError('resetting', error);\n logger.console(formattedError);\n }\n }\n\n private async checkOrStoreToken(options?: { format?: string }): Promise<TokenCheckOrStoreResult> {\n const { status, errors } = await this.checkToken(options);\n if (!status.hasToken || !status.isValid) {\n const { success, errors: storeErrors } = await this.storeToken();\n if (success) {\n return { stored: true, errors: [] };\n } else {\n return { stored: false, errors: storeErrors };\n }\n }\n return { stored: false, errors };\n }\n\n private async checkToken(options?: { format?: string }): Promise<TokenCheckResult> {\n // In Alfred, check presence of env var as token existence\n const hasToken = isRunningInAlfred()\n ? Boolean(process.env.BUILDKITE_API_TOKEN || process.env.BK_TOKEN)\n : await BaseCommand.credentialManager.hasToken();\n let isValid = false;\n let validation: TokenValidationStatus = { \n valid: false, \n canListOrganizations: false,\n organizations: {} \n };\n const errors: unknown[] = [];\n\n if (hasToken) {\n // Get the token for validation\n const token = isRunningInAlfred()\n ? (process.env.BUILDKITE_API_TOKEN || process.env.BK_TOKEN)\n : await BaseCommand.credentialManager.getToken();\n if (!token) {\n const tokenStatus: TokenStatus = {\n hasToken: false,\n isValid: false,\n validation: { \n valid: false, \n canListOrganizations: false,\n organizations: {} \n }\n };\n return { status: tokenStatus, errors };\n }\n\n // Validate the token using the CredentialManager\n try {\n validation = await BaseCommand.credentialManager.validateToken(token, {\n format: options?.format,\n showProgress: false // Don't show progress since we're showing formatted output\n });\n isValid = validation.valid && validation.canListOrganizations;\n } catch (error) {\n errors.push(error);\n }\n }\n \n const tokenStatus: TokenStatus = {\n hasToken,\n isValid,\n validation\n };\n \n const formattedResult = this.formatter.formatTokenStatus(tokenStatus);\n logger.console(formattedResult);\n \n return { status: tokenStatus, errors };\n }\n} "]}
|