diff --git a/packages/cli/src/WorkflowHelpers.ts b/packages/cli/src/WorkflowHelpers.ts index b7afe3c5c0..ad4bccd89a 100644 --- a/packages/cli/src/WorkflowHelpers.ts +++ b/packages/cli/src/WorkflowHelpers.ts @@ -26,11 +26,13 @@ import type { IWorkflowExecutionDataProcess, } from '@/Interfaces'; import { NodeTypes } from '@/NodeTypes'; +// eslint-disable-next-line import/no-cycle import { WorkflowRunner } from '@/WorkflowRunner'; import config from '@/config'; import type { WorkflowEntity } from '@db/entities/WorkflowEntity'; import type { User } from '@db/entities/User'; import omit from 'lodash/omit'; +// eslint-disable-next-line import/no-cycle import { PermissionChecker } from './UserManagement/PermissionChecker'; import { isWorkflowIdValid } from './utils'; import { UserService } from './user/user.service'; @@ -575,6 +577,18 @@ export function validateWorkflowCredentialUsage( return newWorkflowVersion; } +export function getExecutionStartNode(data: IWorkflowExecutionDataProcess, workflow: Workflow) { + let startNode; + if ( + data.startNodes?.length === 1 && + Object.keys(data.pinData ?? {}).includes(data.startNodes[0]) + ) { + startNode = workflow.getNode(data.startNodes[0]) ?? undefined; + } + + return startNode; +} + export async function getVariables(): Promise { const variables = await Container.get(VariablesService).getAllCached(); return Object.freeze( diff --git a/packages/cli/src/WorkflowRunner.ts b/packages/cli/src/WorkflowRunner.ts index 4eb966d1ce..b7e4b4eaac 100644 --- a/packages/cli/src/WorkflowRunner.ts +++ b/packages/cli/src/WorkflowRunner.ts @@ -37,9 +37,12 @@ import type { } from '@/Interfaces'; import { NodeTypes } from '@/NodeTypes'; import type { Job, JobData, JobQueue, JobResponse } from '@/Queue'; +// eslint-disable-next-line import/no-cycle import { Queue } from '@/Queue'; import * as WebhookHelpers from '@/WebhookHelpers'; +// eslint-disable-next-line import/no-cycle import * as WorkflowHelpers from '@/WorkflowHelpers'; +// eslint-disable-next-line import/no-cycle import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'; import { generateFailedExecutionFromError } from '@/WorkflowHelpers'; import { initErrorHandling } from '@/ErrorReporting'; @@ -345,13 +348,7 @@ export class WorkflowRunner { Logger.debug(`Execution ID ${executionId} will run executing all nodes.`, { executionId }); // Execute all nodes - let startNode; - if ( - data.startNodes?.length === 1 && - Object.keys(data.pinData ?? {}).includes(data.startNodes[0]) - ) { - startNode = workflow.getNode(data.startNodes[0]) ?? undefined; - } + const startNode = WorkflowHelpers.getExecutionStartNode(data, workflow); // Can execute without webhook so go on const workflowExecute = new WorkflowExecute(additionalData, data.executionMode); diff --git a/packages/cli/src/WorkflowRunnerProcess.ts b/packages/cli/src/WorkflowRunnerProcess.ts index e5566876c2..d1b009a77e 100644 --- a/packages/cli/src/WorkflowRunnerProcess.ts +++ b/packages/cli/src/WorkflowRunnerProcess.ts @@ -292,13 +292,7 @@ class WorkflowRunnerProcess { ) { // Execute all nodes - let startNode; - if ( - this.data.startNodes?.length === 1 && - Object.keys(this.data.pinData ?? {}).includes(this.data.startNodes[0]) - ) { - startNode = this.workflow.getNode(this.data.startNodes[0]) ?? undefined; - } + const startNode = WorkflowHelpers.getExecutionStartNode(this.data, this.workflow); // Can execute without webhook so go on this.workflowExecute = new WorkflowExecute(additionalData, this.data.executionMode); diff --git a/packages/cli/test/unit/WorkflowHelpers.test.ts b/packages/cli/test/unit/WorkflowHelpers.test.ts index 77cc85ec96..9735f1c015 100644 --- a/packages/cli/test/unit/WorkflowHelpers.test.ts +++ b/packages/cli/test/unit/WorkflowHelpers.test.ts @@ -1,9 +1,14 @@ import type { INode } from 'n8n-workflow'; -import { LoggerProxy } from 'n8n-workflow'; +import { LoggerProxy, type Workflow } from 'n8n-workflow'; import { WorkflowEntity } from '@db/entities/WorkflowEntity'; import { CredentialsEntity } from '@db/entities/CredentialsEntity'; -import { getNodesWithInaccessibleCreds, validateWorkflowCredentialUsage } from '@/WorkflowHelpers'; +import { + getExecutionStartNode, + getNodesWithInaccessibleCreds, + validateWorkflowCredentialUsage, +} from '@/WorkflowHelpers'; import { getLogger } from '@/Logger'; +import type { IWorkflowExecutionDataProcess } from '../../src/Interfaces'; const FIRST_CREDENTIAL_ID = '1'; const SECOND_CREDENTIAL_ID = '2'; @@ -145,6 +150,46 @@ describe('WorkflowHelpers', () => { }).toThrow(); }); }); + describe('getExecutionStartNode', () => { + it('Should return undefined', () => { + const data = { + pinData: {}, + startNodes: [], + } as unknown as IWorkflowExecutionDataProcess; + const workflow = { + getNode(nodeName: string) { + return { + name: nodeName, + }; + }, + } as unknown as Workflow; + const executionStartNode = getExecutionStartNode(data, workflow); + expect(executionStartNode).toBeUndefined(); + }); + it('Should return startNode', () => { + const data = { + pinData: { + node1: {}, + node2: {}, + }, + startNodes: ['node2'], + } as unknown as IWorkflowExecutionDataProcess; + const workflow = { + getNode(nodeName: string) { + if (nodeName === 'node2') { + return { + name: 'node2', + }; + } + return undefined; + }, + } as unknown as Workflow; + const executionStartNode = getExecutionStartNode(data, workflow); + expect(executionStartNode).toEqual({ + name: 'node2', + }); + }); + }); }); function generateCredentialEntity(credentialId: string) {