UNPKG

@swell/cli

Version:

Swell's command line interface/utility

100 lines (97 loc) 4.11 kB
import { InspectResourceCommand, inspectResourceBaseArgs, inspectResourceBaseFlags, } from '../../inspect-resource-command.js'; import { buildAppSlugMap } from '../../lib/apps/resolve.js'; import { redactWorkflowPayload, resolveWorkflowOperationRef, workflowDisplayName, workflowListMeta, } from '../../lib/workflows/operations.js'; export default class Workflows extends InspectResourceCommand { static summary = 'Durable app workflows and runtime state.'; static description = `Lists workflow manifests across deployed apps with runtime state. Pass --app=<slug> or --app=. (current swell.json) to scope. Pass an identifier to view a workflow manifest, summary counts, and failed instance sample as JSON. Identifier forms: app.<app>.<name> - full paste-back key (list column 1) <name> - requires --app= scope <24-char id> - any scope `; static args = { ...inspectResourceBaseArgs }; static flags = { ...inspectResourceBaseFlags }; static examples = [ 'swell inspect workflows', 'swell inspect workflows --app=my-app', 'swell inspect workflows app.my-app.run-import', 'swell inspect workflows run-import --app=my-app', 'swell inspect workflows --live', ]; resourceLabel = 'Workflows'; resourceLabelSingular = 'workflow'; adminPath = '/data/:workflows'; commandName = 'workflows'; appSlugById = {}; skippedApps = []; detailRef; async run() { const { args, flags } = await this.parse(Workflows); await this.runInspect({ args, flags }); } keyFor(record, appSlugById) { const appId = record.app_id || ''; const appPart = appSlugById[appId] || appId; return `app.${appPart}.${workflowDisplayName(record)}`; } metaFor(record) { return workflowListMeta(record); } async getListResults(scope, _flags) { this.skippedApps = []; if (scope.appId) { return this.getWorkflowListForApp(scope.appId); } this.appSlugById = await buildAppSlugMap(this.api); const results = await Promise.all(Object.keys(this.appSlugById).map(async (appId) => { try { return await this.getWorkflowListForApp(appId); } catch { this.skippedApps.push(this.appSlugById[appId] || appId); return []; } })); return results.flat(); } async getAppSlugById(scope) { if (scope.appId) { return scope.appSlug ? { [scope.appId]: scope.appSlug } : {}; } return this.appSlugById; } afterList() { if (this.skippedApps.length > 0) { this.log(); this.log(`Skipped inaccessible apps: ${this.skippedApps.join(', ')}`); } } async showDetail(identifier, _scope, flags) { const ref = await resolveWorkflowOperationRef(this.api, identifier, flags); const workflowRef = ref.query.workflow_id || ref.query.workflow_name; const detail = await this.api.get({ adminPath: `/data/:workflows/${workflowRef}` }, { query: { app_id: ref.appId } }); const manifest = detail?.manifest || {}; const workflowName = workflowDisplayName(manifest); this.detailRef = { appPart: ref.appSlug || ref.appId, workflowName, }; this.emitDetail(redactWorkflowPayload(detail), flags); } hints() { if (!this.detailRef) { return []; } const { appPart, workflowName } = this.detailRef; return [ `swell inspect workflow-runs --workflow app.${appPart}.${workflowName} --status active`, `swell inspect workflow-runs --workflow app.${appPart}.${workflowName} --status failed`, `swell logs --type workflow --app ${appPart} -s ${workflowName}`, ]; } async getWorkflowListForApp(appId) { const response = await this.api.get({ adminPath: '/data/:workflows' }, { query: { app_id: appId } }); return response?.results || []; } }