Skip to content

Commit 084fe7e

Browse files
CLI Deploy: support collections (#860)
* CLI: support collections * fix failing tests * support deletion * add release changeset * version: [email protected] --------- Co-authored-by: Joe Clark <[email protected]>
1 parent 0337621 commit 084fe7e

File tree

10 files changed

+170
-364
lines changed

10 files changed

+170
-364
lines changed

packages/cli/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# @openfn/cli
22

3+
## 1.10.3
4+
5+
### Patch Changes
6+
7+
- Updated dependencies [6363e4a]
8+
- @openfn/deploy@0.9.0
9+
310
## 1.10.2
411

512
### Patch Changes

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openfn/cli",
3-
"version": "1.10.2",
3+
"version": "1.10.3",
44
"description": "CLI devtools for the openfn toolchain.",
55
"engines": {
66
"node": ">=18",

packages/deploy/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @openfn/deploy
22

3+
## 0.9.0
4+
5+
### Minor Changes
6+
7+
- 6363e4a: Support collections in deploy package
8+
39
## 0.8.2
410

511
### Patch Changes

packages/deploy/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openfn/deploy",
3-
"version": "0.8.2",
3+
"version": "0.9.0",
44
"description": "Deploy projects to Lightning instances",
55
"type": "module",
66
"exports": {

packages/deploy/src/stateTransform.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,43 @@ export function mergeSpecIntoState(
287287
)
288288
);
289289

290+
const nextCollections = Object.fromEntries(
291+
splitZip(oldState.collections || {}, spec.collections || {}).map(
292+
([collectionKey, stateCollection, specCollection]) => {
293+
if (specCollection && !stateCollection) {
294+
return [
295+
collectionKey,
296+
{
297+
id: crypto.randomUUID(),
298+
name: specCollection.name,
299+
},
300+
];
301+
}
302+
303+
if (specCollection && stateCollection) {
304+
return [
305+
collectionKey,
306+
{
307+
id: stateCollection.id,
308+
name: specCollection.name,
309+
},
310+
];
311+
}
312+
313+
if (!specCollection && stateCollection) {
314+
return [collectionKey, { id: stateCollection.id, delete: true }];
315+
}
316+
317+
throw new DeployError(
318+
`Invalid collection spec or corrupted state for collection: ${
319+
stateCollection?.name || specCollection?.name
320+
}`,
321+
'VALIDATION_ERROR'
322+
);
323+
}
324+
)
325+
);
326+
290327
const nextWorkflows = Object.fromEntries(
291328
splitZip(oldState.workflows, spec.workflows).map(
292329
([workflowKey, stateWorkflow, specWorkflow]) => {
@@ -352,6 +389,7 @@ export function mergeSpecIntoState(
352389
name: spec.name,
353390
workflows: nextWorkflows,
354391
project_credentials: nextCredentials,
392+
collections: nextCollections,
355393
};
356394

357395
if (spec.description) projectState.description = spec.description;
@@ -398,8 +436,11 @@ export function getStateFromProjectPayload(
398436
{} as Record<string, CredentialState>
399437
);
400438

439+
const collections = reduceByKey('name', project.collections || []);
440+
401441
return {
402442
...project,
443+
collections,
403444
project_credentials,
404445
workflows,
405446
};
@@ -460,8 +501,17 @@ export function mergeProjectPayloadIntoState(
460501
})
461502
);
462503

504+
const nextCollections = Object.fromEntries(
505+
idKeyPairs(project.collections || {}, state.collections || {}).map(
506+
([key, nextCollection, _state]) => {
507+
return [key, nextCollection];
508+
}
509+
)
510+
);
511+
463512
return {
464513
...project,
514+
collections: nextCollections,
465515
project_credentials: nextCredentials,
466516
workflows: nextWorkflows,
467517
};
@@ -503,8 +553,13 @@ export function toProjectPayload(state: ProjectState): ProjectPayload {
503553
const project_credentials: ProjectPayload['project_credentials'] =
504554
Object.values(state.project_credentials);
505555

556+
const collections: ProjectPayload['collections'] = Object.values(
557+
state.collections
558+
);
559+
506560
return {
507561
...state,
562+
collections,
508563
project_credentials,
509564
workflows,
510565
};

packages/deploy/src/types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,22 @@ export type CredentialState = {
9494
owner: string;
9595
};
9696

97+
export type CollectionSpec = {
98+
name: string;
99+
};
100+
101+
export type CollectionState = {
102+
id: string;
103+
name: string;
104+
delete?: boolean;
105+
};
106+
97107
export interface ProjectSpec {
98108
name: string;
99109
description: string;
100110
workflows: Record<string | symbol, WorkflowSpec>;
101111
credentials: Record<string | symbol, CredentialSpec>;
112+
collections: Record<string | symbol, CollectionSpec>;
102113
}
103114

104115
export interface WorkflowState {
@@ -121,12 +132,14 @@ export interface ProjectState {
121132
description: string;
122133
workflows: Record<string | symbol, WorkflowState>;
123134
project_credentials: Record<string | symbol, CredentialState>;
135+
collections: Record<string | symbol, CollectionState>;
124136
}
125137

126138
export interface ProjectPayload {
127139
id: string;
128140
name: string;
129141
description: string;
142+
collections: Concrete<CollectionState>[];
130143
project_credentials: Concrete<CredentialState>[];
131144
workflows: {
132145
id: string;

packages/deploy/src/validator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ export async function parseAndValidate(
123123
}
124124
}
125125

126+
if (pair.key && pair.key.value === 'collections') {
127+
if (pair.value.value === null) {
128+
return doc.createPair('collections', {});
129+
}
130+
}
131+
126132
if (pair.key && pair.key.value === 'jobs') {
127133
if (pair.value.value === null) {
128134
errors.push({

packages/deploy/test/fixtures.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export function fullExampleSpec() {
44
return {
55
name: 'my project',
66
description: 'some helpful description',
7+
collections: {},
78
credentials: {},
89
workflows: {
910
'workflow-one': {
@@ -56,6 +57,7 @@ export function fullExampleState() {
5657
id: 'be156ab1-8426-4151-9a18-4045142f9ec0',
5758
name: 'my project',
5859
description: 'some helpful description',
60+
collections: {},
5961
project_credentials: {},
6062
workflows: {
6163
'workflow-one': {
@@ -116,6 +118,12 @@ export const lightningProjectPayload = {
116118
updated_at: '2023-08-25T08:57:31',
117119
scheduled_deletion: null,
118120
requires_mfa: false,
121+
collections: [
122+
{
123+
id: 'f8e1c1e1-5c5a-4d9b-8e9f-4b2f6b1c2f4e',
124+
name: 'collection-one',
125+
},
126+
],
119127
project_credentials: [
120128
{
121129
id: '25f48989-d349-4eb8-99c3-923ebba5b116',
@@ -240,6 +248,12 @@ export const lightningProjectState = {
240248
updated_at: '2023-08-25T08:57:31',
241249
scheduled_deletion: null,
242250
requires_mfa: false,
251+
collections: {
252+
'collection-one': {
253+
id: 'f8e1c1e1-5c5a-4d9b-8e9f-4b2f6b1c2f4e',
254+
name: 'collection-one',
255+
},
256+
},
243257
project_credentials: {
244258
245259
id: '25f48989-d349-4eb8-99c3-923ebba5b116',

packages/deploy/test/stateTransform.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,46 @@ test('toNextState adding a job', (t) => {
9090
name: 'project-name',
9191
description: 'my test project',
9292
project_credentials: {},
93+
collections: {},
94+
});
95+
});
96+
97+
test('toNextState deleting a credential', (t) => {
98+
const spec = {
99+
name: 'project-name',
100+
description: 'my test project',
101+
collections: {},
102+
workflows: {},
103+
};
104+
105+
const state = {
106+
workflows: {},
107+
project_credentials: {},
108+
collections: {
109+
'test-collection': {
110+
id: 'f8e1c1e1-5c5a-4d9b-8e9f-4b2f6b1c2f4e',
111+
name: 'test-collection',
112+
},
113+
},
114+
id: 'ecb683d1-5e5a-4c4f-9165-e143e2eeeb48',
115+
name: 'project-name',
116+
description: 'my test project',
117+
};
118+
119+
let result = mergeSpecIntoState(state, spec);
120+
121+
t.deepEqual(result, {
122+
workflows: {},
123+
id: 'ecb683d1-5e5a-4c4f-9165-e143e2eeeb48',
124+
name: 'project-name',
125+
description: 'my test project',
126+
project_credentials: {},
127+
collections: {
128+
'test-collection': {
129+
id: 'f8e1c1e1-5c5a-4d9b-8e9f-4b2f6b1c2f4e',
130+
delete: true,
131+
},
132+
},
93133
});
94134
});
95135

@@ -117,6 +157,7 @@ test('toNextState with empty state', (t) => {
117157
name: 'my project',
118158
description: 'some helpful description',
119159
project_credentials: {},
160+
collections: {},
120161
workflows: {
121162
'workflow-one': {
122163
id: jp.query(result, '$..workflows["workflow-one"].id')[0],
@@ -176,6 +217,7 @@ test('toNextState with no changes', (t) => {
176217
name: 'my project',
177218
description: 'for the humans',
178219
project_credentials: {},
220+
collections: {},
179221
workflows: {
180222
'workflow-one': {
181223
id: '8124e88c-566f-472f-be38-363e588af55a',
@@ -291,6 +333,7 @@ test('toNextState with a new job', (t) => {
291333
name: 'my project',
292334
description: 'some other description',
293335
project_credentials: {},
336+
collections: {},
294337
workflows: {
295338
'workflow-one': {
296339
id: '8124e88c-566f-472f-be38-363e588af55a',
@@ -538,6 +581,7 @@ test('getStateFromProjectPayload with minimal project', (t) => {
538581
id: 'xyz',
539582
name: 'project',
540583
project_credentials: {},
584+
collections: {},
541585
workflows: {
542586
a: {
543587
id: 'wf-a',

0 commit comments

Comments
 (0)