From 7a9fc53a0f63ffddfc87cf806c9974e5035c2269 Mon Sep 17 00:00:00 2001 From: Farhan Yahaya Date: Mon, 20 Oct 2025 10:14:18 +0000 Subject: [PATCH 1/7] feat: workflow merge compatibility --- packages/project/src/Workflow.ts | 10 +++++ packages/project/test/workflow.test.ts | 59 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/packages/project/src/Workflow.ts b/packages/project/src/Workflow.ts index 19a9b7574..06064bb50 100644 --- a/packages/project/src/Workflow.ts +++ b/packages/project/src/Workflow.ts @@ -20,6 +20,8 @@ class Workflow { id: string; openfn: OpenfnMeta; + history: string[] = []; + constructor(workflow: l.Workflow) { this.index = { steps: {}, // steps by id @@ -167,6 +169,14 @@ class Workflow { getVersionHash() { return generateHash(this); } + + // return true if the current workflow can be merged into the target workflow without losing any changes + canMergeInto(target: Workflow) { + if (!target.history.length) return true; + const targetHead = target.history[target.history.length - 1]; + if (this.history.indexOf(targetHead) > -1) return true; + return false; + } } export default Workflow; diff --git a/packages/project/test/workflow.test.ts b/packages/project/test/workflow.test.ts index 82e7b914a..c42853e2e 100644 --- a/packages/project/test/workflow.test.ts +++ b/packages/project/test/workflow.test.ts @@ -1,6 +1,7 @@ import { randomUUID } from 'node:crypto'; import test from 'ava'; import Workflow from '../src/Workflow'; +import { generateWorkflow } from '../src'; const simpleWorkflow = { id: 'my-workflow', @@ -205,3 +206,61 @@ test('map uuids to ids', (t) => { t.deepEqual(w.index.id[uuid_ac], 'a-c'); t.deepEqual(w.index.id[uuid_bc], 'b-c'); }); + +test('canMergeInto: empty histories', (t) => { + const sourceWf = generateWorkflow('trigger-x'); + const targetWf = generateWorkflow('trigger-y'); + t.deepEqual(sourceWf.history, []); + t.deepEqual(targetWf.history, []); + t.true(sourceWf.canMergeInto(targetWf)); // allowed +}); + +test('canMergeInto: empty target history', (t) => { + const sourceWf = generateWorkflow('trigger-x'); + const targetWf = generateWorkflow('trigger-y'); + sourceWf.history = ['history-1']; + t.is(sourceWf.history.length, 1); + t.deepEqual(targetWf.history, []); + t.true(sourceWf.canMergeInto(targetWf)); // allowed +}); + +test('canMergeInto: empty source history', (t) => { + const sourceWf = generateWorkflow('trigger-x'); + const targetWf = generateWorkflow('trigger-y'); + targetWf.history = ['history-1']; + t.is(targetWf.history.length, 1); + t.deepEqual(sourceWf.history, []); + t.false(sourceWf.canMergeInto(targetWf)); // not allowed +}); + +test('canMergeInto: target head in source', (t) => { + const sourceWf = generateWorkflow('trigger-x'); + const targetWf = generateWorkflow('trigger-y'); + targetWf.history = ['history-1', 'history-3', 'history-5']; + sourceWf.history = ['history-2', 'history-5', 'history-6']; + t.true(sourceWf.canMergeInto(targetWf)); // allowed +}); + +test('canMergeInto: target head not in source', (t) => { + const sourceWf = generateWorkflow('trigger-x'); + const targetWf = generateWorkflow('trigger-y'); + targetWf.history = ['history-1', 'history-3', 'history-5']; + sourceWf.history = ['history-2', 'history-4', 'history-6']; + t.false(sourceWf.canMergeInto(targetWf)); // not allowed +}); + +test('canMergeInto: source head in target', (t) => { + const sourceWf = generateWorkflow('trigger-x'); + const targetWf = generateWorkflow('trigger-y'); + targetWf.history = ['history-1', 'history-3', 'history-6', 'history-5']; + sourceWf.history = ['history-2', 'history-4', 'history-6']; + t.false(sourceWf.canMergeInto(targetWf)); // not allowed +}); + +test('canMergeInto: same heads', (t) => { + const sourceWf = generateWorkflow('trigger-x'); + const targetWf = generateWorkflow('trigger-y'); + targetWf.history = ['history-1', 'history-3', 'history-6']; + sourceWf.history = ['history-2', 'history-4', 'history-6']; + t.true(sourceWf.canMergeInto(targetWf)); // allowed +}); From d33ce0512fe9ac67799b9d8baac8d9f893186c76 Mon Sep 17 00:00:00 2001 From: Farhan Yahaya Date: Mon, 20 Oct 2025 12:29:55 +0000 Subject: [PATCH 2/7] feat: push version history --- packages/project/src/Workflow.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/project/src/Workflow.ts b/packages/project/src/Workflow.ts index 06064bb50..77fff338f 100644 --- a/packages/project/src/Workflow.ts +++ b/packages/project/src/Workflow.ts @@ -170,6 +170,10 @@ class Workflow { return generateHash(this); } + pushHistory(versionHash: string) { + this.history.push(versionHash); + } + // return true if the current workflow can be merged into the target workflow without losing any changes canMergeInto(target: Workflow) { if (!target.history.length) return true; From 0c2cc48ae70d8c09babef22f8ac047bd48292811 Mon Sep 17 00:00:00 2001 From: Farhan Yahaya Date: Mon, 20 Oct 2025 12:49:56 +0000 Subject: [PATCH 3/7] fix: log level when calling checkout from merge --- packages/cli/src/merge/handler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/merge/handler.ts b/packages/cli/src/merge/handler.ts index eed5f527e..4c767df83 100644 --- a/packages/cli/src/merge/handler.ts +++ b/packages/cli/src/merge/handler.ts @@ -65,6 +65,7 @@ const mergeHandler = async (options: MergeOptions, logger: Logger) => { command: 'checkout', projectPath: commandPath, projectName: final.name || '', + log: options.log, }, logger ); From 664dfbeab755ba66b494f3892f3685f53792a85c Mon Sep 17 00:00:00 2001 From: Farhan Yahaya Date: Mon, 20 Oct 2025 15:37:29 +0000 Subject: [PATCH 4/7] feat: add history to workflow property --- packages/lexicon/core.d.ts | 3 ++ packages/project/src/Workflow.ts | 14 ++++---- packages/project/test/gen/fixtures.ts | 1 + packages/project/test/gen/generator.test.ts | 7 ++++ .../project/test/parse/from-app-state.test.ts | 1 + packages/project/test/workflow.test.ts | 33 ++++++++++--------- 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/packages/lexicon/core.d.ts b/packages/lexicon/core.d.ts index 8d0ae075f..267acf6bb 100644 --- a/packages/lexicon/core.d.ts +++ b/packages/lexicon/core.d.ts @@ -83,6 +83,9 @@ export type Workflow = { globals?: string; openfn?: OpenFnMetadata; + + // holds history information of a workflow + history?: string[] }; export type StepId = string; diff --git a/packages/project/src/Workflow.ts b/packages/project/src/Workflow.ts index 77fff338f..cf787519a 100644 --- a/packages/project/src/Workflow.ts +++ b/packages/project/src/Workflow.ts @@ -20,8 +20,6 @@ class Workflow { id: string; openfn: OpenfnMeta; - history: string[] = []; - constructor(workflow: l.Workflow) { this.index = { steps: {}, // steps by id @@ -32,6 +30,9 @@ class Workflow { this.workflow = clone(workflow); + // history needs to be on workflow object. + this.workflow.history = workflow.history?.length ? workflow.history : []; + const { id, name, openfn, steps, ...options } = workflow; if (!(id || name)) { throw new Error('A Workflow MUST have a name or id'); @@ -171,14 +172,15 @@ class Workflow { } pushHistory(versionHash: string) { - this.history.push(versionHash); + this.workflow.history?.push(versionHash); } // return true if the current workflow can be merged into the target workflow without losing any changes canMergeInto(target: Workflow) { - if (!target.history.length) return true; - const targetHead = target.history[target.history.length - 1]; - if (this.history.indexOf(targetHead) > -1) return true; + if (!target.workflow.history.length) return true; + const targetHead = + target.workflow.history[target.workflow.history.length - 1]; + if (this.workflow.history.indexOf(targetHead) > -1) return true; return false; } } diff --git a/packages/project/test/gen/fixtures.ts b/packages/project/test/gen/fixtures.ts index e75597307..a33dd9725 100644 --- a/packages/project/test/gen/fixtures.ts +++ b/packages/project/test/gen/fixtures.ts @@ -4,6 +4,7 @@ export const ab = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'a', diff --git a/packages/project/test/gen/generator.test.ts b/packages/project/test/gen/generator.test.ts index 794a0c59b..0c2ab6863 100644 --- a/packages/project/test/gen/generator.test.ts +++ b/packages/project/test/gen/generator.test.ts @@ -120,6 +120,7 @@ test('it should generate a simple workflow with any letter', (t) => { const expected = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'x', @@ -152,6 +153,7 @@ test('it should generate a simple workflow with words, numbers and underscores', const expected = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'node_1', @@ -184,6 +186,7 @@ test('it should generate two node pairs', (t) => { const expected = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'a', @@ -231,6 +234,7 @@ test('it should generate two node pairs from one parent', (t) => { const expected = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'a', @@ -276,6 +280,7 @@ test('it should generate several node pairs', (t) => { const expected = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'a', @@ -439,6 +444,7 @@ test('it should generate a simple workflow with mapped uuids', (t) => { const expected = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'a', @@ -481,6 +487,7 @@ test('it should generate a project with uuids', (t) => { const expected = { id: 'workflow', name: 'Workflow', + history: [], steps: [ { id: 'a', diff --git a/packages/project/test/parse/from-app-state.test.ts b/packages/project/test/parse/from-app-state.test.ts index 16fda2237..86c3ef6ed 100644 --- a/packages/project/test/parse/from-app-state.test.ts +++ b/packages/project/test/parse/from-app-state.test.ts @@ -114,6 +114,7 @@ test('should create a Project from prov state with a workflow', (t) => { t.deepEqual(project.workflows[0].toJSON(), { id: 'my-workflow', name: 'My Workflow', + history: [], steps: [ { id: 'trigger', diff --git a/packages/project/test/workflow.test.ts b/packages/project/test/workflow.test.ts index c42853e2e..b2ce3bdaa 100644 --- a/packages/project/test/workflow.test.ts +++ b/packages/project/test/workflow.test.ts @@ -5,6 +5,7 @@ import { generateWorkflow } from '../src'; const simpleWorkflow = { id: 'my-workflow', + history: [], name: 'My Workflow', steps: [ { @@ -210,57 +211,57 @@ test('map uuids to ids', (t) => { test('canMergeInto: empty histories', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - t.deepEqual(sourceWf.history, []); - t.deepEqual(targetWf.history, []); + t.deepEqual(sourceWf.workflow.history, []); + t.deepEqual(targetWf.workflow.history, []); t.true(sourceWf.canMergeInto(targetWf)); // allowed }); test('canMergeInto: empty target history', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - sourceWf.history = ['history-1']; - t.is(sourceWf.history.length, 1); - t.deepEqual(targetWf.history, []); + sourceWf.workflow.history = ['history-1']; + t.is(sourceWf.workflow.history.length, 1); + t.deepEqual(targetWf.workflow.history, []); t.true(sourceWf.canMergeInto(targetWf)); // allowed }); test('canMergeInto: empty source history', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - targetWf.history = ['history-1']; - t.is(targetWf.history.length, 1); - t.deepEqual(sourceWf.history, []); + targetWf.workflow.history = ['history-1']; + t.is(targetWf.workflow.history.length, 1); + t.deepEqual(sourceWf.workflow.history, []); t.false(sourceWf.canMergeInto(targetWf)); // not allowed }); test('canMergeInto: target head in source', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - targetWf.history = ['history-1', 'history-3', 'history-5']; - sourceWf.history = ['history-2', 'history-5', 'history-6']; + targetWf.workflow.history = ['history-1', 'history-3', 'history-5']; + sourceWf.workflow.history = ['history-2', 'history-5', 'history-6']; t.true(sourceWf.canMergeInto(targetWf)); // allowed }); test('canMergeInto: target head not in source', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - targetWf.history = ['history-1', 'history-3', 'history-5']; - sourceWf.history = ['history-2', 'history-4', 'history-6']; + targetWf.workflow.history = ['history-1', 'history-3', 'history-5']; + sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; t.false(sourceWf.canMergeInto(targetWf)); // not allowed }); test('canMergeInto: source head in target', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - targetWf.history = ['history-1', 'history-3', 'history-6', 'history-5']; - sourceWf.history = ['history-2', 'history-4', 'history-6']; + targetWf.workflow.history = ['history-1', 'history-3', 'history-6', 'history-5']; + sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; t.false(sourceWf.canMergeInto(targetWf)); // not allowed }); test('canMergeInto: same heads', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - targetWf.history = ['history-1', 'history-3', 'history-6']; - sourceWf.history = ['history-2', 'history-4', 'history-6']; + targetWf.workflow.history = ['history-1', 'history-3', 'history-6']; + sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; t.true(sourceWf.canMergeInto(targetWf)); // allowed }); From b5f667acfe2e53dc1186a238a2ecdc39dcd6569a Mon Sep 17 00:00:00 2001 From: Farhan Yahaya Date: Tue, 21 Oct 2025 07:25:51 +0000 Subject: [PATCH 5/7] tests: update wording --- packages/project/test/workflow.test.ts | 31 +++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/project/test/workflow.test.ts b/packages/project/test/workflow.test.ts index b2ce3bdaa..1c5cedfee 100644 --- a/packages/project/test/workflow.test.ts +++ b/packages/project/test/workflow.test.ts @@ -208,60 +208,75 @@ test('map uuids to ids', (t) => { t.deepEqual(w.index.id[uuid_bc], 'b-c'); }); -test('canMergeInto: empty histories', (t) => { +test('canMergeInto: can merge empty histories', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); + t.deepEqual(sourceWf.workflow.history, []); t.deepEqual(targetWf.workflow.history, []); + t.true(sourceWf.canMergeInto(targetWf)); // allowed }); -test('canMergeInto: empty target history', (t) => { +test('canMergeInto: can merge empty target history', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); sourceWf.workflow.history = ['history-1']; + t.is(sourceWf.workflow.history.length, 1); t.deepEqual(targetWf.workflow.history, []); + t.true(sourceWf.canMergeInto(targetWf)); // allowed }); -test('canMergeInto: empty source history', (t) => { +test('canMergeInto: cannot merge empty source history', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); targetWf.workflow.history = ['history-1']; + t.is(targetWf.workflow.history.length, 1); t.deepEqual(sourceWf.workflow.history, []); + t.false(sourceWf.canMergeInto(targetWf)); // not allowed }); -test('canMergeInto: target head in source', (t) => { +test('canMergeInto: can merge target head in source', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); targetWf.workflow.history = ['history-1', 'history-3', 'history-5']; sourceWf.workflow.history = ['history-2', 'history-5', 'history-6']; + t.true(sourceWf.canMergeInto(targetWf)); // allowed }); -test('canMergeInto: target head not in source', (t) => { +test('canMergeInto: cannot merge target head not in source', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); targetWf.workflow.history = ['history-1', 'history-3', 'history-5']; sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; + t.false(sourceWf.canMergeInto(targetWf)); // not allowed }); -test('canMergeInto: source head in target', (t) => { +test('canMergeInto: cannot merge source head in target', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); - targetWf.workflow.history = ['history-1', 'history-3', 'history-6', 'history-5']; + targetWf.workflow.history = [ + 'history-1', + 'history-3', + 'history-6', + 'history-5', + ]; sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; + t.false(sourceWf.canMergeInto(targetWf)); // not allowed }); -test('canMergeInto: same heads', (t) => { +test('canMergeInto: can merge same heads', (t) => { const sourceWf = generateWorkflow('trigger-x'); const targetWf = generateWorkflow('trigger-y'); targetWf.workflow.history = ['history-1', 'history-3', 'history-6']; sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; + t.true(sourceWf.canMergeInto(targetWf)); // allowed }); From 5bb14553a2cbca842d8239d46b9d610401169d96 Mon Sep 17 00:00:00 2001 From: Farhan Yahaya Date: Fri, 24 Oct 2025 07:44:51 +0000 Subject: [PATCH 6/7] feat: update history checking logic --- packages/project/src/Workflow.ts | 11 +- packages/project/test/workflow.test.ts | 137 +++++++++++++++---------- 2 files changed, 89 insertions(+), 59 deletions(-) diff --git a/packages/project/src/Workflow.ts b/packages/project/src/Workflow.ts index cf787519a..721e51e43 100644 --- a/packages/project/src/Workflow.ts +++ b/packages/project/src/Workflow.ts @@ -177,10 +177,13 @@ class Workflow { // return true if the current workflow can be merged into the target workflow without losing any changes canMergeInto(target: Workflow) { - if (!target.workflow.history.length) return true; - const targetHead = - target.workflow.history[target.workflow.history.length - 1]; - if (this.workflow.history.indexOf(targetHead) > -1) return true; + const thisHistory = this.workflow.history?.concat(this.getVersionHash()); + const targetHistory = target.workflow.history?.concat( + target.getVersionHash() + ); + + const targetHead = targetHistory[targetHistory.length - 1]; + if (thisHistory.indexOf(targetHead) > -1) return true; return false; } } diff --git a/packages/project/test/workflow.test.ts b/packages/project/test/workflow.test.ts index 1c5cedfee..c9171c9c1 100644 --- a/packages/project/test/workflow.test.ts +++ b/packages/project/test/workflow.test.ts @@ -51,6 +51,11 @@ const simpleWorkflow = { }, }; +// should workflow.toJSON actually do this? +function realJson(v: any) { + return JSON.parse(JSON.stringify(v)); +} + test('create a Workflow from json', (t) => { const w = new Workflow(simpleWorkflow); @@ -208,75 +213,97 @@ test('map uuids to ids', (t) => { t.deepEqual(w.index.id[uuid_bc], 'b-c'); }); -test('canMergeInto: can merge empty histories', (t) => { - const sourceWf = generateWorkflow('trigger-x'); - const targetWf = generateWorkflow('trigger-y'); - - t.deepEqual(sourceWf.workflow.history, []); - t.deepEqual(targetWf.workflow.history, []); +test.only('canMergeInto: should merge same content source & target', (t) => { + const main = generateWorkflow('trigger-x'); + const sbox = generateWorkflow('trigger-x'); - t.true(sourceWf.canMergeInto(targetWf)); // allowed + t.true(sbox.canMergeInto(main)); // allowed }); -test('canMergeInto: can merge empty target history', (t) => { - const sourceWf = generateWorkflow('trigger-x'); - const targetWf = generateWorkflow('trigger-y'); - sourceWf.workflow.history = ['history-1']; +test.only("canMergeInto: shouldn't merge different content source & target", (t) => { + const main = generateWorkflow('trigger-x'); + const sbox = generateWorkflow('trigger-y'); - t.is(sourceWf.workflow.history.length, 1); - t.deepEqual(targetWf.workflow.history, []); - - t.true(sourceWf.canMergeInto(targetWf)); // allowed + t.false(sbox.canMergeInto(main)); // allowed }); -test('canMergeInto: cannot merge empty source history', (t) => { - const sourceWf = generateWorkflow('trigger-x'); - const targetWf = generateWorkflow('trigger-y'); - targetWf.workflow.history = ['history-1']; - - t.is(targetWf.workflow.history.length, 1); - t.deepEqual(sourceWf.workflow.history, []); +test.only('canMergeInto: source is target + changes', (t) => { + // initial main code + const main = generateWorkflow('trigger-x'); + main.pushHistory(main.getVersionHash()); + // main code updated + main.workflow.steps = generateWorkflow('trigger-x x-y').steps; + main.pushHistory(main.getVersionHash()); + + // clone main for sbox + const sbox = new Workflow(realJson(main.toJSON())); + // do code changes to sbox + sbox.workflow.steps = generateWorkflow('trigger-x x-y y-z').steps; + t.true(sbox.canMergeInto(main)); +}); - t.false(sourceWf.canMergeInto(targetWf)); // not allowed +test.only("canMergeInto: source isn't from target", (t) => { + // initial main code + const main = generateWorkflow('trigger-x'); + main.pushHistory(main.getVersionHash()); + // main code updated + main.workflow.steps = generateWorkflow('trigger-x x-y').steps; + main.pushHistory(main.getVersionHash()); + + // clone main for sbox + const sbox = generateWorkflow('trigger-y'); + sbox.pushHistory(sbox.getVersionHash()); + t.false(sbox.canMergeInto(main)); }); -test('canMergeInto: can merge target head in source', (t) => { - const sourceWf = generateWorkflow('trigger-x'); - const targetWf = generateWorkflow('trigger-y'); - targetWf.workflow.history = ['history-1', 'history-3', 'history-5']; - sourceWf.workflow.history = ['history-2', 'history-5', 'history-6']; +test.only("canMergeInto: source isn't from target but ended with same code", (t) => { + // initial main code + const main = generateWorkflow('trigger-x'); + main.pushHistory(main.getVersionHash()); + // main code updated + main.workflow.steps = generateWorkflow('trigger-x x-y').steps; + main.pushHistory(main.getVersionHash()); - t.true(sourceWf.canMergeInto(targetWf)); // allowed + const sbox = generateWorkflow('trigger-x x-y'); + t.true(sbox.canMergeInto(main)); }); -test('canMergeInto: cannot merge target head not in source', (t) => { - const sourceWf = generateWorkflow('trigger-x'); - const targetWf = generateWorkflow('trigger-y'); - targetWf.workflow.history = ['history-1', 'history-3', 'history-5']; - sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; +test.only('canMergeInto: source is from target but target has changes', (t) => { + // initial main code + const main = generateWorkflow('trigger-x'); + main.pushHistory(main.getVersionHash()); + // main code updated + main.workflow.steps = generateWorkflow('trigger-x x-y').steps; + main.pushHistory(main.getVersionHash()); - t.false(sourceWf.canMergeInto(targetWf)); // not allowed -}); + // clone main for sbox + const sbox = new Workflow(realJson(main.toJSON())); + + // changes to main after cloning + main.workflow.steps = generateWorkflow('trigger-x x-y x-z').steps; + main.pushHistory(main.getVersionHash()); -test('canMergeInto: cannot merge source head in target', (t) => { - const sourceWf = generateWorkflow('trigger-x'); - const targetWf = generateWorkflow('trigger-y'); - targetWf.workflow.history = [ - 'history-1', - 'history-3', - 'history-6', - 'history-5', - ]; - sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; - - t.false(sourceWf.canMergeInto(targetWf)); // not allowed + // merging sbox to main + t.false(sbox.canMergeInto(main)); }); -test('canMergeInto: can merge same heads', (t) => { - const sourceWf = generateWorkflow('trigger-x'); - const targetWf = generateWorkflow('trigger-y'); - targetWf.workflow.history = ['history-1', 'history-3', 'history-6']; - sourceWf.workflow.history = ['history-2', 'history-4', 'history-6']; - - t.true(sourceWf.canMergeInto(targetWf)); // allowed +test.only('canMergeInto: source is from target but target & source have changes', (t) => { + // initial main code + const main = generateWorkflow('trigger-x'); + main.pushHistory(main.getVersionHash()); + // main code updated + main.workflow.steps = generateWorkflow('trigger-x x-y').steps; + main.pushHistory(main.getVersionHash()); + + // clone main for sbox + const sbox = new Workflow(realJson(main.toJSON())); + // changes to sbox + sbox.workflow.steps = generateWorkflow('trigger-x x-y y-g').steps; + + // changes to main after cloning + main.workflow.steps = generateWorkflow('trigger-x x-y x-z').steps; + main.pushHistory(main.getVersionHash()); + + // merging sbox to main + t.false(sbox.canMergeInto(main)); }); From ec480cd1bb131e92cdd9c6a27177392c86195845 Mon Sep 17 00:00:00 2001 From: Farhan Yahaya Date: Fri, 24 Oct 2025 14:12:29 +0000 Subject: [PATCH 7/7] tests: update tests --- packages/project/test/workflow.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/project/test/workflow.test.ts b/packages/project/test/workflow.test.ts index c9171c9c1..008db9f94 100644 --- a/packages/project/test/workflow.test.ts +++ b/packages/project/test/workflow.test.ts @@ -213,21 +213,21 @@ test('map uuids to ids', (t) => { t.deepEqual(w.index.id[uuid_bc], 'b-c'); }); -test.only('canMergeInto: should merge same content source & target', (t) => { +test('canMergeInto: should merge same content source & target', (t) => { const main = generateWorkflow('trigger-x'); const sbox = generateWorkflow('trigger-x'); - t.true(sbox.canMergeInto(main)); // allowed + t.true(sbox.canMergeInto(main)); }); -test.only("canMergeInto: shouldn't merge different content source & target", (t) => { +test("canMergeInto: shouldn't merge different content source & target", (t) => { const main = generateWorkflow('trigger-x'); const sbox = generateWorkflow('trigger-y'); - t.false(sbox.canMergeInto(main)); // allowed + t.false(sbox.canMergeInto(main)); }); -test.only('canMergeInto: source is target + changes', (t) => { +test('canMergeInto: source is target + changes', (t) => { // initial main code const main = generateWorkflow('trigger-x'); main.pushHistory(main.getVersionHash()); @@ -242,7 +242,7 @@ test.only('canMergeInto: source is target + changes', (t) => { t.true(sbox.canMergeInto(main)); }); -test.only("canMergeInto: source isn't from target", (t) => { +test("canMergeInto: source isn't from target", (t) => { // initial main code const main = generateWorkflow('trigger-x'); main.pushHistory(main.getVersionHash()); @@ -256,7 +256,7 @@ test.only("canMergeInto: source isn't from target", (t) => { t.false(sbox.canMergeInto(main)); }); -test.only("canMergeInto: source isn't from target but ended with same code", (t) => { +test("canMergeInto: source isn't from target but ended with same code", (t) => { // initial main code const main = generateWorkflow('trigger-x'); main.pushHistory(main.getVersionHash()); @@ -268,7 +268,7 @@ test.only("canMergeInto: source isn't from target but ended with same code", (t) t.true(sbox.canMergeInto(main)); }); -test.only('canMergeInto: source is from target but target has changes', (t) => { +test('canMergeInto: source is from target but target has changes', (t) => { // initial main code const main = generateWorkflow('trigger-x'); main.pushHistory(main.getVersionHash()); @@ -287,7 +287,7 @@ test.only('canMergeInto: source is from target but target has changes', (t) => { t.false(sbox.canMergeInto(main)); }); -test.only('canMergeInto: source is from target but target & source have changes', (t) => { +test('canMergeInto: source is from target but target & source have changes', (t) => { // initial main code const main = generateWorkflow('trigger-x'); main.pushHistory(main.getVersionHash());