mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-15 17:14:05 -08:00
db1bbf0432
Also created a command that lists workflows so it can be used by other applications that wish to interact with n8n via CLI.
175 lines
4.9 KiB
TypeScript
175 lines
4.9 KiB
TypeScript
import * as fs from 'fs';
|
|
import { Command, flags } from '@oclif/command';
|
|
import {
|
|
UserSettings,
|
|
} from 'n8n-core';
|
|
import {
|
|
INode,
|
|
} from 'n8n-workflow';
|
|
|
|
import {
|
|
ActiveExecutions,
|
|
CredentialsOverwrites,
|
|
CredentialTypes,
|
|
Db,
|
|
ExternalHooks,
|
|
GenericHelpers,
|
|
IWorkflowBase,
|
|
IWorkflowExecutionDataProcess,
|
|
LoadNodesAndCredentials,
|
|
NodeTypes,
|
|
WorkflowCredentials,
|
|
WorkflowHelpers,
|
|
WorkflowRunner,
|
|
} from "../src";
|
|
|
|
import {
|
|
sep
|
|
} from 'path';
|
|
|
|
|
|
export class ExecuteAll extends Command {
|
|
static description = '\nExecutes all workflows once';
|
|
|
|
static examples = [
|
|
`$ n8n executeAll`,
|
|
`$ n8n executeAll --debug`,
|
|
`$ n8n executeAll --snapshot=/data/snapshots`,
|
|
];
|
|
|
|
static flags = {
|
|
help: flags.help({ char: 'h' }),
|
|
debug: flags.boolean({
|
|
description: 'Toggles on displaying all errors and debug messages.',
|
|
}),
|
|
snapshot: flags.string({
|
|
description: 'Enables snapshot saving. You must inform an existing folder to save snapshots via this param.',
|
|
}),
|
|
};
|
|
|
|
|
|
async run() {
|
|
const { flags } = this.parse(ExecuteAll);
|
|
|
|
const debug = flags.debug !== undefined;
|
|
|
|
if (flags.snapshot !== undefined) {
|
|
if (fs.existsSync(flags.snapshot)) {
|
|
if (!fs.lstatSync(flags.snapshot).isDirectory()) {
|
|
GenericHelpers.logOutput(`The paramenter --snapshot must be an existing directory`);
|
|
return;
|
|
}
|
|
} else {
|
|
GenericHelpers.logOutput(`The paramenter --snapshot must be an existing directory`);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Start directly with the init of the database to improve startup time
|
|
const startDbInitPromise = Db.init();
|
|
|
|
// Load all node and credential types
|
|
const loadNodesAndCredentials = LoadNodesAndCredentials();
|
|
const loadNodesAndCredentialsPromise = loadNodesAndCredentials.init();
|
|
|
|
// Wait till the database is ready
|
|
await startDbInitPromise;
|
|
|
|
const allWorkflows = await Db.collections!.Workflow!.find();
|
|
if (debug) {
|
|
this.log(`Found ${allWorkflows.length} workflows to execute.`);
|
|
}
|
|
|
|
// Make sure the settings exist
|
|
await UserSettings.prepareUserSettings();
|
|
|
|
// Wait till the n8n-packages have been read
|
|
await loadNodesAndCredentialsPromise;
|
|
|
|
// Load the credentials overwrites if any exist
|
|
const credentialsOverwrites = CredentialsOverwrites();
|
|
await credentialsOverwrites.init();
|
|
|
|
// Load all external hooks
|
|
const externalHooks = ExternalHooks();
|
|
await externalHooks.init();
|
|
|
|
// Add the found types to an instance other parts of the application can use
|
|
const nodeTypes = NodeTypes();
|
|
await nodeTypes.init(loadNodesAndCredentials.nodeTypes);
|
|
const credentialTypes = CredentialTypes();
|
|
await credentialTypes.init(loadNodesAndCredentials.credentialTypes);
|
|
|
|
// Check if the workflow contains the required "Start" node
|
|
// "requiredNodeTypes" are also defined in editor-ui/views/NodeView.vue
|
|
const requiredNodeTypes = ['n8n-nodes-base.start'];
|
|
for (let i = 0; i < allWorkflows.length; i++) {
|
|
const workflowData = allWorkflows[i];
|
|
|
|
if (debug) {
|
|
this.log(`Starting execution of workflow ID ${workflowData.id}.`);
|
|
}
|
|
|
|
let startNode: INode | undefined= undefined;
|
|
for (const node of workflowData!.nodes) {
|
|
if (requiredNodeTypes.includes(node.type)) {
|
|
startNode = node;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (startNode === undefined) {
|
|
// If the workflow does not contain a start-node we can not know what
|
|
// should be executed and with which data to start.
|
|
GenericHelpers.logOutput(`Workflow ID ${workflowData.id} cannot be started as it does not contain a "Start" node.`);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
const credentials = await WorkflowCredentials(workflowData!.nodes);
|
|
|
|
const runData: IWorkflowExecutionDataProcess = {
|
|
credentials,
|
|
executionMode: 'cli',
|
|
startNodes: [startNode.name],
|
|
workflowData: workflowData!,
|
|
};
|
|
|
|
const workflowRunner = new WorkflowRunner();
|
|
const executionId = await workflowRunner.run(runData);
|
|
|
|
const activeExecutions = ActiveExecutions.getInstance();
|
|
const data = await activeExecutions.getPostExecutePromise(executionId);
|
|
|
|
if (data === undefined) {
|
|
GenericHelpers.logOutput(`Workflow ${workflowData.id} did not return any data.`);
|
|
continue;
|
|
}
|
|
|
|
if (data.data.resultData.error) {
|
|
GenericHelpers.logOutput(`Workflow ${workflowData.id} failed.`);
|
|
if (debug) {
|
|
this.log(JSON.stringify(data, null, 2));
|
|
console.log(data.data.resultData.error);
|
|
}
|
|
continue;
|
|
}
|
|
GenericHelpers.logOutput(`Workflow ${workflowData.id} succeeded.`);
|
|
if (flags.snapshot !== undefined) {
|
|
const fileName = (flags.snapshot.endsWith(sep) ? flags.snapshot : flags.snapshot + sep) + `${workflowData.id}-snapshot.json`;
|
|
fs.writeFileSync(fileName,JSON.stringify(data, null, 2));
|
|
}
|
|
} catch (e) {
|
|
GenericHelpers.logOutput(`Workflow ${workflowData.id} failed.`);
|
|
if (debug) {
|
|
console.error(e.message);
|
|
console.error(e.stack);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
this.exit();
|
|
}
|
|
}
|