Skip to content

Commit 205c964

Browse files
committed
feat: implement hash generation
1 parent a1fa351 commit 205c964

2 files changed

Lines changed: 45 additions & 14 deletions

File tree

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1+
import { Workflow } from '@openfn/lexicon';
12
import crypto from 'node:crypto';
23

34
const SHORT_HASH_LENGTH = 12;
45

56
export const project = () => {};
67

7-
export const workflow = (workflow: l.Workflow, source = 'cli') => {
8+
function isDefined(v: any) {
9+
return v !== undefined && v !== null;
10+
}
11+
12+
export const workflow = (workflow: Workflow, source = 'cli') => {
813
const parts = [];
914

1015
// These are the keys we hash against
11-
const wfkeys = ['name', 'credentials'].sort();
16+
const wfKeys = ['name', 'credentials'].sort();
1217
const stepKeys = [
1318
'name',
1419
'adaptors',
@@ -24,22 +29,48 @@ export const workflow = (workflow: l.Workflow, source = 'cli') => {
2429
'disabled', // This feels more like an option - should be excluded?
2530
].sort();
2631

27-
for (const step of workflow.steps) {
32+
wfKeys.forEach((key) => {
33+
if (isDefined(workflow[key])) {
34+
parts.push(key, serializeValue(workflow[key]));
35+
}
36+
});
37+
38+
const steps = (workflow.steps || []).slice().sort((a, b) => {
39+
const aName = a.name ?? '';
40+
const bName = b.name ?? '';
41+
return aName.localeCompare(bName);
42+
});
43+
for (const step of steps) {
2844
stepKeys.forEach((key) => {
29-
if (typeof step[key] === 'string') {
30-
parts.push(key, step[key]);
45+
if (isDefined(step[key])) {
46+
parts.push(key, serializeValue(step[key]));
3147
}
3248
});
3349

34-
// if (step.next) {
35-
// for (const edge of step.next) {
36-
// // TODO I don't think we can handle this well right now
37-
// }
38-
// }
50+
if (step.next && Array.isArray(step.next)) {
51+
const edges = step.next.slice().sort((a, b) => {
52+
const aLabel = a.label || '';
53+
const bLabel = b.label || '';
54+
return aLabel.localeCompare(bLabel);
55+
});
56+
for (const edge of edges) {
57+
edgeKeys.forEach((key) => {
58+
if (isDefined(edge[key])) {
59+
parts.push(key, serializeValue(edge[key]));
60+
}
61+
});
62+
}
63+
}
3964
}
4065

4166
const str = parts.join('');
42-
const hash = crypto.hash('sha256', str);
43-
44-
return `${source}:${hash.substr(0, 12)}`;
67+
const hash = crypto.createHash('sha256').update(str).digest('hex');
68+
return `${source}:${hash.substring(0, SHORT_HASH_LENGTH)}`;
4569
};
70+
71+
function serializeValue(val) {
72+
if (typeof val === 'object') {
73+
return JSON.stringify(val);
74+
}
75+
return String(val);
76+
}

packages/project/test/util/version-workflow.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ test('generate an 12 character version hash for a basic workflow', (t) => {
4949

5050
const hash = workflow(wf);
5151
t.log(hash);
52-
t.is(hash, 'cli:625fcedf07d4');
52+
t.is(hash, 'cli:fd18866bcb34');
5353
});
5454

5555
/**

0 commit comments

Comments
 (0)