diff --git a/packages/cli/src/commands/update/workflow.ts b/packages/cli/src/commands/update/workflow.ts index 7c4dbd401dd1d..0a8f0314615c6 100644 --- a/packages/cli/src/commands/update/workflow.ts +++ b/packages/cli/src/commands/update/workflow.ts @@ -50,16 +50,22 @@ export class UpdateWorkflowCommand extends BaseCommand { } const newState = flags.active === 'true'; + const action = newState ? 'Activating' : 'Deactivating'; if (flags.id) { - this.logger.info(`Deactivating workflow with ID: ${flags.id}`); + this.logger.info(`${action} workflow with ID: ${flags.id}`); await Container.get(WorkflowRepository).updateActiveState(flags.id, newState); } else { - this.logger.info('Deactivating all workflows'); - await Container.get(WorkflowRepository).deactivateAll(); + this.logger.info(`${action} all workflows`); + if (newState) { + await Container.get(WorkflowRepository).activateAll(); + } else { + await Container.get(WorkflowRepository).deactivateAll(); + } } - this.logger.info('Done'); + this.logger.info('Activation or deactivation will not take effect if n8n is running.'); + this.logger.info('Please restart n8n for changes to take effect if n8n is currently running.'); } async catch(error: Error) { diff --git a/packages/cli/src/databases/repositories/workflow.repository.ts b/packages/cli/src/databases/repositories/workflow.repository.ts index 71559353ee85b..084238fc0b7f0 100644 --- a/packages/cli/src/databases/repositories/workflow.repository.ts +++ b/packages/cli/src/databases/repositories/workflow.repository.ts @@ -213,6 +213,10 @@ export class WorkflowRepository extends Repository { return await this.update({ active: true }, { active: false }); } + async activateAll() { + return await this.update({ active: false }, { active: true }); + } + async findByActiveState(activeState: boolean) { return await this.findBy({ active: activeState }); } diff --git a/packages/cli/test/integration/commands/update/workflow.test.ts b/packages/cli/test/integration/commands/update/workflow.test.ts new file mode 100644 index 0000000000000..922eaccb386ed --- /dev/null +++ b/packages/cli/test/integration/commands/update/workflow.test.ts @@ -0,0 +1,126 @@ +import { Config } from '@oclif/core'; +import { InternalHooks } from '@/InternalHooks'; +import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials'; +import { UpdateWorkflowCommand } from '@/commands/update/workflow'; + +import * as testDb from '../../shared/testDb'; +import { createWorkflowWithTrigger, getAllWorkflows } from '../../shared/db/workflows'; +import { mockInstance } from '../../../shared/mocking'; + +beforeAll(async () => { + mockInstance(InternalHooks); + mockInstance(LoadNodesAndCredentials); + await testDb.init(); +}); + +beforeEach(async () => { + await testDb.truncate(['Workflow']); +}); + +afterAll(async () => { + await testDb.terminate(); +}); + +test('update:workflow can activate all workflows', async () => { + // + // ARRANGE + // + const workflows = await Promise.all([ + createWorkflowWithTrigger({}), + createWorkflowWithTrigger({}), + ]); + expect(workflows).toMatchObject([{ active: false }, { active: false }]); + + // + // ACT + // + const config = new Config({ root: __dirname }); + const updater = new UpdateWorkflowCommand(['--all', '--active=true'], config); + await updater.init(); + await updater.run(); + + // + // ASSERT + // + const after = await getAllWorkflows(); + expect(after).toMatchObject([{ active: true }, { active: true }]); +}); + +test('update:workflow can deactivate all workflows', async () => { + // + // ARRANGE + // + const workflows = await Promise.all([ + createWorkflowWithTrigger({ active: true }), + createWorkflowWithTrigger({ active: true }), + ]); + expect(workflows).toMatchObject([{ active: true }, { active: true }]); + + // + // ACT + // + const config = new Config({ root: __dirname }); + const updater = new UpdateWorkflowCommand(['--all', '--active=false'], config); + await updater.init(); + await updater.run(); + + // + // ASSERT + // + const after = await getAllWorkflows(); + expect(after).toMatchObject([{ active: false }, { active: false }]); +}); + +test('update:workflow can activate a specific workflow', async () => { + // + // ARRANGE + // + const workflows = ( + await Promise.all([ + createWorkflowWithTrigger({ active: false }), + createWorkflowWithTrigger({ active: false }), + ]) + ).sort((wf1, wf2) => wf1.id.localeCompare(wf2.id)); + expect(workflows).toMatchObject([{ active: false }, { active: false }]); + + // + // ACT + // + const config = new Config({ root: __dirname }); + const updater = new UpdateWorkflowCommand([`--id=${workflows[0].id}`, '--active=true'], config); + await updater.init(); + await updater.run(); + + // + // ASSERT + // + const after = (await getAllWorkflows()).sort((wf1, wf2) => wf1.id.localeCompare(wf2.id)); + expect(after).toMatchObject([{ active: true }, { active: false }]); +}); + +test('update:workflow can deactivate a specific workflow', async () => { + // + // ARRANGE + // + const workflows = ( + await Promise.all([ + createWorkflowWithTrigger({ active: true }), + createWorkflowWithTrigger({ active: true }), + ]) + ).sort((wf1, wf2) => wf1.id.localeCompare(wf2.id)); + expect(workflows).toMatchObject([{ active: true }, { active: true }]); + + // + // ACT + // + const config = new Config({ root: __dirname }); + const updater = new UpdateWorkflowCommand([`--id=${workflows[0].id}`, '--active=false'], config); + await updater.init(); + await updater.run(); + + // + // ASSERT + // + const after = (await getAllWorkflows()).sort((wf1, wf2) => wf1.id.localeCompare(wf2.id)); + expect(after).toMatchObject([{ active: false }, { active: true }]); +}); diff --git a/packages/cli/test/integration/database/repositories/workflow.repository.test.ts b/packages/cli/test/integration/database/repositories/workflow.repository.test.ts new file mode 100644 index 0000000000000..d9e1ea22fd7f7 --- /dev/null +++ b/packages/cli/test/integration/database/repositories/workflow.repository.test.ts @@ -0,0 +1,70 @@ +import Container from 'typedi'; + +import { WorkflowRepository } from '@/databases/repositories/workflow.repository'; + +import * as testDb from '../../shared/testDb'; +import { createWorkflowWithTrigger, getAllWorkflows } from '../../shared/db/workflows'; + +describe('WorkflowRepository', () => { + beforeAll(async () => { + await testDb.init(); + }); + + beforeEach(async () => { + await testDb.truncate(['Workflow']); + }); + + afterAll(async () => { + await testDb.terminate(); + }); + + describe('activateAll', () => { + it('should activate all workflows', async () => { + // + // ARRANGE + // + const workflowRepository = Container.get(WorkflowRepository); + const workflows = await Promise.all([ + createWorkflowWithTrigger(), + createWorkflowWithTrigger(), + ]); + expect(workflows).toMatchObject([{ active: false }, { active: false }]); + + // + // ACT + // + await workflowRepository.activateAll(); + + // + // ASSERT + // + const after = await getAllWorkflows(); + expect(after).toMatchObject([{ active: true }, { active: true }]); + }); + }); + + describe('deactivateAll', () => { + it('should deactivate all workflows', async () => { + // + // ARRANGE + // + const workflowRepository = Container.get(WorkflowRepository); + const workflows = await Promise.all([ + createWorkflowWithTrigger({ active: true }), + createWorkflowWithTrigger({ active: true }), + ]); + expect(workflows).toMatchObject([{ active: true }, { active: true }]); + + // + // ACT + // + await workflowRepository.deactivateAll(); + + // + // ASSERT + // + const after = await getAllWorkflows(); + expect(after).toMatchObject([{ active: false }, { active: false }]); + }); + }); +});