From 58b5396c306e88e34c6e0f2b8fe8f6c78f2e6502 Mon Sep 17 00:00:00 2001 From: Junyi Date: Mon, 10 Mar 2025 16:01:35 +0800 Subject: [PATCH 1/2] refactor(plugin-workflow-action-trigger): support to use end node to determine status (#6399) --- .../src/server/ActionTrigger.ts | 58 ++++++++++++++- .../src/server/__tests__/trigger.test.ts | 70 ++++++++++++++++++- 2 files changed, 124 insertions(+), 4 deletions(-) diff --git a/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts b/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts index f880ac32d7..5c29330cc6 100644 --- a/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts +++ b/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts @@ -12,12 +12,28 @@ import { BelongsTo, HasOne } from 'sequelize'; import { Model, modelAssociationByKey } from '@nocobase/database'; import Application, { DefaultContext } from '@nocobase/server'; import { Context as ActionContext, Next } from '@nocobase/actions'; +import PluginErrorHandler from '@nocobase/plugin-error-handler'; -import WorkflowPlugin, { EventOptions, Trigger, WorkflowModel, toJSON } from '@nocobase/plugin-workflow'; +import WorkflowPlugin, { + EXECUTION_STATUS, + EventOptions, + Trigger, + WorkflowModel, + toJSON, +} from '@nocobase/plugin-workflow'; import { joinCollectionName, parseCollectionName } from '@nocobase/data-source-manager'; interface Context extends ActionContext, DefaultContext {} +class RequestOnActionTriggerError extends Error { + status = 400; + messages: any[] = []; + constructor(message) { + super(message); + this.name = 'RequestOnActionTriggerError'; + } +} + export default class extends Trigger { static TYPE = 'action'; @@ -43,6 +59,16 @@ export default class extends Trigger { } workflow.app.dataSourceManager.use(triggerWorkflowActionMiddleware); + + workflow.app.pm.get(PluginErrorHandler).errorHandler.register( + (err) => err instanceof RequestOnActionTriggerError || err.name === 'RequestOnActionTriggerError', + async (err, ctx) => { + ctx.body = { + errors: err.messages, + }; + ctx.status = err.status; + }, + ); } /** @@ -177,7 +203,35 @@ export default class extends Trigger { } for (const event of syncGroup) { - await this.workflow.trigger(event[0], event[1]); + const processor = await this.workflow.trigger(event[0], event[1], { httpContext: context }); + + // NOTE: workflow trigger failed + if (!processor) { + return context.throw(500); + } + + const { lastSavedJob, nodesMap } = processor; + const lastNode = nodesMap.get(lastSavedJob?.nodeId); + // NOTE: passthrough + if (processor.execution.status === EXECUTION_STATUS.RESOLVED) { + if (lastNode?.type === 'end') { + return; + } + continue; + } + // NOTE: intercept + if (processor.execution.status < EXECUTION_STATUS.STARTED) { + if (lastNode?.type !== 'end') { + return context.throw(500, 'Workflow on your action failed, please contact the administrator'); + } + + const err = new RequestOnActionTriggerError('Request failed'); + err.status = 400; + err.messages = context.state.messages; + return context.throw(err.status, err); + } + // NOTE: should not be pending + return context.throw(500, 'Workflow on your action hangs, please contact the administrator'); } for (const event of asyncGroup) { diff --git a/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/__tests__/trigger.test.ts b/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/__tests__/trigger.test.ts index d45959ad98..c7e76af1bb 100644 --- a/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/__tests__/trigger.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/__tests__/trigger.test.ts @@ -9,7 +9,7 @@ import { omit } from 'lodash'; import Database from '@nocobase/database'; -import { EXECUTION_STATUS } from '@nocobase/plugin-workflow'; +import { EXECUTION_STATUS, JOB_STATUS } from '@nocobase/plugin-workflow'; import { getApp, sleep } from '@nocobase/plugin-workflow-test'; import { MockServer } from '@nocobase/test'; @@ -30,7 +30,7 @@ describe('workflow > action-trigger', () => { beforeEach(async () => { app = await getApp({ - plugins: ['users', 'auth', 'acl', 'data-source-manager', 'system-settings', Plugin], + plugins: ['users', 'auth', 'acl', 'data-source-manager', 'system-settings', 'error-handler', Plugin], }); await app.pm.get('auth').install(); agent = app.agent(); @@ -661,6 +661,72 @@ describe('workflow > action-trigger', () => { expect(e3s.length).toBe(1); expect(e3s[0].status).toBe(EXECUTION_STATUS.RESOLVED); }); + + it('execution failed on node error', async () => { + const workflow = await WorkflowModel.create({ + enabled: true, + type: 'action', + sync: true, + config: { + collection: 'posts', + }, + }); + + const n1 = await workflow.createNode({ + type: 'error', + }); + + const res1 = await userAgents[0].resource('posts').create({ + values: { title: 't1' }, + triggerWorkflows: `${workflow.key}`, + }); + expect(res1.status).toBe(500); + }); + + it('execution failed on end node success', async () => { + const workflow = await WorkflowModel.create({ + enabled: true, + type: 'action', + sync: true, + config: { + collection: 'posts', + }, + }); + + const n1 = await workflow.createNode({ + type: 'end', + }); + + const res1 = await userAgents[0].resource('posts').create({ + values: { title: 't1' }, + triggerWorkflows: `${workflow.key}`, + }); + expect(res1.status).toBe(200); + }); + + it('execution failed on end node success', async () => { + const workflow = await WorkflowModel.create({ + enabled: true, + type: 'action', + sync: true, + config: { + collection: 'posts', + }, + }); + + const n1 = await workflow.createNode({ + type: 'end', + config: { + endStatus: JOB_STATUS.FAILED, + }, + }); + + const res1 = await userAgents[0].resource('posts').create({ + values: { title: 't1' }, + triggerWorkflows: `${workflow.key}`, + }); + expect(res1.status).toBe(400); + }); }); describe('global workflow', () => { From eb25702d37479d27a7790192a7522d741e41134b Mon Sep 17 00:00:00 2001 From: xilesun <2013xile@gmail.com> Date: Tue, 11 Mar 2025 09:56:55 +0800 Subject: [PATCH 2/2] fix: merge ci --- .github/workflows/manual-merge.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/manual-merge.yml b/.github/workflows/manual-merge.yml index 061765def4..70bcbeaa5d 100644 --- a/.github/workflows/manual-merge.yml +++ b/.github/workflows/manual-merge.yml @@ -65,6 +65,10 @@ jobs: run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" env: GH_TOKEN: ${{ steps.app-token.outputs.token }} + - name: Set user + run: | + git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]' + git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>' - name: Checkout uses: actions/checkout@v4 with: