@swell/cli
Version:
Swell's command line interface/utility
100 lines (97 loc) • 4.11 kB
JavaScript
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 || [];
}
}