UNPKG

bktide

Version:

Command-line interface for Buildkite CI/CD workflows with rich shell completions (Fish, Bash, Zsh) and Alfred workflow integration for macOS power users

189 lines 8.87 kB
import { BaseCommand } from './BaseCommand.js'; import { getPipelineFormatter } from '../formatters/index.js'; import Fuse from 'fuse.js'; import { logger } from '../services/logger.js'; import { Progress } from '../ui/progress.js'; export class ListPipelines extends BaseCommand { BATCH_SIZE = 50; // Reasonable batch size for API calls DEFAULT_LIMIT = 50; // Default number of pipelines to show constructor(options) { super(options); } async execute(options) { await this.ensureInitialized(); try { // Need to get organization info if not provided const org = options.org; if (!org) { try { const orgs = await this.client.getViewerOrganizationSlugs(); await this.listPipelines(orgs, options); } catch (error) { logger.error(error, 'Failed to determine your organizations'); throw new Error('Failed to determine your organizations', { cause: error }); } } else { await this.listPipelines([org], options); } // Success is implicit - data display confirms retrieval return 0; // Success } catch (error) { this.handleError(error, options.debug); return 1; // Error } } async listPipelines(organizations, options) { let allPipelines = []; let totalBeforeFilter = 0; let hasMorePipelines = false; // Track if there are more pipelines available beyond what we fetched // Use progress bar for multiple orgs, spinner for single org const format = options.format || 'plain'; const useProgressBar = organizations.length > 1 && format === 'plain'; const orgProgress = useProgressBar ? Progress.bar({ total: organizations.length, label: 'Processing organizations', format: format }) : null; for (let orgIndex = 0; orgIndex < organizations.length; orgIndex++) { const org = organizations[orgIndex]; // Use different progress indicators based on context let spinner = null; const pageProgress = useProgressBar ? Progress.spinner(`Loading pipelines from ${org}...`, { format }) : null; if (!useProgressBar) { // For single org, use spinner (existing behavior) spinner = Progress.spinner(`Fetching pipelines from ${org}…`, { format }); } try { const batchSize = this.BATCH_SIZE; let hasNextPage = true; let cursor = null; // Use default limit if no count specified const resultLimit = options.count !== undefined ? parseInt(options.count, 10) : this.DEFAULT_LIMIT; // Update org progress if using progress bar if (orgProgress) { orgProgress.update(orgIndex, `Organization: ${org}`); } let pageCount = 0; let orgPipelineCount = 0; while (hasNextPage && allPipelines.length < resultLimit) { pageCount++; if (pageProgress) { pageProgress.update(pageCount, `Loading ${org} (page ${pageCount})...`); } if (options.debug) { logger.debug(`Fetching batch of pipelines from org ${org}, cursor: ${cursor || 'initial'}`); } const data = await this.client.getPipelines(org, batchSize, cursor || undefined); if (data?.organization?.pipelines?.edges) { // Add org information to each pipeline for display const pipelines = data.organization.pipelines.edges .filter(edge => edge !== null && edge.node !== null) .map(edge => { const node = edge.node; return { uuid: node.uuid || '', id: node.id || '', name: node.name || '', slug: node.slug || '', description: node.description, url: node.url || '', repository: node.repository, organization: org }; }); orgPipelineCount += pipelines.length; allPipelines = allPipelines.concat(pipelines); } // Check if we need to fetch more pages hasNextPage = data?.organization?.pipelines?.pageInfo?.hasNextPage || false; cursor = data?.organization?.pipelines?.pageInfo?.endCursor || null; if (options.debug) { logger.debug(`Fetched batch of ${data?.organization?.pipelines?.edges?.length || 0} pipelines from org ${org}`); if (hasNextPage) { logger.debug(`More pages available, cursor: ${cursor}`); } } // Stop after getting enough results if (allPipelines.length >= resultLimit) { // If we hit the limit and there are more pages, remember that if (hasNextPage) { hasMorePipelines = true; } break; } } // Stop the appropriate progress indicator if (pageProgress) { pageProgress.stop(); if (options.debug) { logger.debug(`Loaded ${orgPipelineCount} pipelines from ${org} in ${pageCount} pages`); } } else if (spinner) { spinner.stop(); } } catch (error) { // Clean up any active progress indicators if (spinner) { spinner.stop(); } if (pageProgress) { pageProgress.stop(); } throw new Error(`Error fetching pipelines for organization ${org}`, { cause: error }); } } // Complete the org progress bar if used if (orgProgress) { orgProgress.complete(`Loaded ${allPipelines.length} pipelines from ${organizations.length} organizations`); } // Apply limit and track truncation const requestedLimit = options.count ? parseInt(options.count, 10) : this.DEFAULT_LIMIT; const truncated = allPipelines.length > requestedLimit; if (allPipelines.length > requestedLimit) { allPipelines = allPipelines.slice(0, requestedLimit); } // Track total before filter for context totalBeforeFilter = allPipelines.length; if (options.filter && allPipelines.length > 0) { if (options.debug) { logger.debug(`Applying fuzzy filter '${options.filter}' to ${allPipelines.length} pipelines`); } const fuse = new Fuse(allPipelines, { keys: ['name', 'slug', 'description'], threshold: 0.4, includeScore: true, shouldSort: true }); const searchResults = fuse.search(options.filter); allPipelines = searchResults.map(result => result.item); if (options.debug) { logger.debug(`Filtered to ${allPipelines.length} pipelines matching '${options.filter}'`); } } // Prepare formatter options with context const formatterOptions = { debug: options.debug, filterActive: !!options.filter, filterText: options.filter, truncated: truncated || hasMorePipelines, // Either truncated locally or more available on server hasMoreAvailable: hasMorePipelines, totalBeforeFilter: totalBeforeFilter, requestedLimit: requestedLimit, organizationsCount: organizations.length, orgSpecified: !!options.org }; const formatter = getPipelineFormatter(format); const output = formatter.formatPipelines(allPipelines, organizations, formatterOptions); logger.console(output); } } //# sourceMappingURL=ListPipelines.js.map