Skip to content

Commit 757f009

Browse files
Next CLI Release (#1413)
* deploy: support webhook_response in triggers * update portability spec * add canonical v2 test * project: support extra state keys * duplicate types * add support for new keys in v2 * update version hash * revert job code * webhook_response -> webhook_response_config * fix tests * fix step complete * update deploy test * changesets * enable type checking on project tests and fix a bunch of types * fix more typings * Support channels in provisioner (#1412) * feat(deploy): support channels in project state Add ChannelSpec/ChannelState types, merge channels in mergeSpecIntoState and mergeProjectPayloadIntoState, include them in toProjectPayload (drop when empty), read them in getStateFromProjectPayload, and accept null channels in the YAML validator. * feat(project,lexicon): propagate channels through parse, serialize, merge Add Provisioner.Channel type and channels field on Provisioner.Project_v1 in lexicon. Carry channels through Project, from-app-state, to-app-state, to-project, and merge-project (REPLACE mode prefers source, falls back to target; baseMerge treats channels as opaque like collections). * add collections to portability projectspec * style(deploy): format stateTransform with prettier * move channel typedef into portability layer * add extra tests * tweak typings * changesets * types --------- Co-authored-by: Joe Clark <jclark@openfn.org> * versions --------- Co-authored-by: Frank Midigo <midigofrank@gmail.com> Co-authored-by: Midigo Frank <39288959+midigofrank@users.noreply.github.com>
1 parent b0eb0bc commit 757f009

43 files changed

Lines changed: 1239 additions & 189 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/dull-meals-stare.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@openfn/lexicon': minor
3+
'@openfn/project': minor
4+
'@openfn/deploy': minor
5+
'@openfn/cli': minor
6+
---
7+
8+
Add support for channels

.changeset/frank-canyons-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openfn/deploy': minor
3+
---
4+
5+
Add support for webhook_response_config

.changeset/salty-areas-juggle.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openfn/lexicon': minor
3+
---
4+
5+
Support `cron_cursor_job_id`, `webhook_reply` and `webhook_response_config` in Provisioner types

.changeset/shy-needles-attack.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openfn/cli': minor
3+
---
4+
5+
Support webhook responses in sync & deploy

.changeset/wide-seals-tease.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openfn/project': patch
3+
---
4+
5+
Support more trigger keys

packages/deploy/src/stateTransform.ts

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ function mergeTriggers(
164164
if (specTrigger.type === 'webhook' && specTrigger.webhook_reply) {
165165
trigger.webhook_reply = specTrigger.webhook_reply;
166166
}
167+
if (
168+
specTrigger.type === 'webhook' &&
169+
specTrigger.webhook_response_config
170+
) {
171+
trigger.webhook_response_config =
172+
specTrigger.webhook_response_config;
173+
}
167174

168175
if (specTrigger.type === 'cron') {
169176
trigger.cron_expression = specTrigger.cron_expression;
@@ -202,6 +209,13 @@ function mergeTriggers(
202209
if (specTrigger!.type === 'webhook' && specTrigger!.webhook_reply) {
203210
trigger.webhook_reply = specTrigger!.webhook_reply;
204211
}
212+
if (
213+
specTrigger!.type === 'webhook' &&
214+
specTrigger!.webhook_response_config
215+
) {
216+
trigger.webhook_response_config =
217+
specTrigger!.webhook_response_config;
218+
}
205219

206220
if (specTrigger!.type === 'cron') {
207221
trigger.cron_expression = specTrigger!.cron_expression;
@@ -360,6 +374,58 @@ export function mergeSpecIntoState(
360374
}
361375
)
362376
);
377+
const nextChannels = Object.fromEntries(
378+
splitZip(oldState.channels || {}, spec.channels || {}).map(
379+
([channelKey, stateChannel, specChannel]) => {
380+
if (specChannel && !stateChannel) {
381+
return [
382+
channelKey,
383+
{
384+
id: crypto.randomUUID(),
385+
name: specChannel.name,
386+
destination_url: specChannel.destination_url,
387+
enabled: specChannel.enabled,
388+
destination_credential_id:
389+
specChannel.destination_credential &&
390+
getStateJobCredential(
391+
specChannel.destination_credential,
392+
nextCredentials
393+
),
394+
},
395+
];
396+
}
397+
398+
if (specChannel && stateChannel) {
399+
return [
400+
channelKey,
401+
{
402+
id: stateChannel.id,
403+
name: specChannel.name,
404+
destination_url: specChannel.destination_url,
405+
enabled: specChannel.enabled,
406+
destination_credential_id:
407+
specChannel.destination_credential &&
408+
getStateJobCredential(
409+
specChannel.destination_credential,
410+
nextCredentials
411+
),
412+
},
413+
];
414+
}
415+
416+
if (!specChannel && stateChannel) {
417+
return [channelKey, { id: stateChannel.id, delete: true }];
418+
}
419+
420+
throw new DeployError(
421+
`Invalid channel spec or corrupted state for channel: ${
422+
stateChannel?.name || specChannel?.name
423+
}`,
424+
'VALIDATION_ERROR'
425+
);
426+
}
427+
)
428+
);
363429

364430
const nextWorkflows = Object.fromEntries(
365431
splitZip(oldState.workflows, spec.workflows).map(
@@ -428,6 +494,7 @@ export function mergeSpecIntoState(
428494
workflows: nextWorkflows,
429495
project_credentials: nextCredentials,
430496
collections: nextCollections,
497+
channels: nextChannels,
431498
};
432499

433500
if (spec.description) projectState.description = spec.description;
@@ -476,9 +543,12 @@ export function getStateFromProjectPayload(
476543

477544
const collections = reduceByKey('name', project.collections || []);
478545

546+
const channels = reduceByKey('name', project.channels || []);
547+
479548
return {
480549
...project,
481550
collections,
551+
channels,
482552
project_credentials,
483553
workflows,
484554
};
@@ -547,9 +617,18 @@ export function mergeProjectPayloadIntoState(
547617
)
548618
);
549619

620+
const nextChannels = Object.fromEntries(
621+
idKeyPairs(project.channels || [], state.channels || {}).map(
622+
([key, nextChannel, _state]) => {
623+
return [key, nextChannel];
624+
}
625+
)
626+
);
627+
550628
return {
551629
...project,
552630
collections: nextCollections,
631+
channels: nextChannels,
553632
project_credentials: nextCredentials,
554633
workflows: nextWorkflows,
555634
};
@@ -595,12 +674,17 @@ export function toProjectPayload(state: ProjectState): ProjectPayload {
595674
state.collections
596675
);
597676

598-
const { collections: _, ...stateWithoutCollections } = state;
677+
const channels: ProjectPayload['channels'] = Object.values(
678+
state.channels || {}
679+
);
680+
681+
const { collections: _, channels: __, ...stateWithoutOptionals } = state;
599682

600683
return {
601-
...stateWithoutCollections,
684+
...stateWithoutOptionals,
602685
project_credentials,
603686
workflows,
604687
...(collections.length > 0 && { collections }),
688+
...(channels.length > 0 && { channels }),
605689
};
606690
}

packages/deploy/src/types.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,19 @@ export type SpecKafkaConfiguration = {
3838
connect_timeout: number;
3939
};
4040

41+
export type WebhookResponseConfig = {
42+
error_code: number | null;
43+
success_code: number | null;
44+
};
45+
4146
export type WebhookReply = 'before_start' | 'after_completion';
4247

4348
export type SpecTrigger = {
4449
type: string;
4550
cron_expression?: string;
4651
cron_cursor_job?: string;
4752
webhook_reply?: WebhookReply;
53+
webhook_response_config?: WebhookResponseConfig | null;
4854
enabled?: boolean;
4955
kafka_configuration?: SpecKafkaConfiguration;
5056
};
@@ -55,6 +61,7 @@ export type StateTrigger = {
5561
cron_expression?: string;
5662
cron_cursor_job_id?: string | null;
5763
webhook_reply?: WebhookReply;
64+
webhook_response_config?: WebhookResponseConfig | null;
5865
delete?: boolean;
5966
enabled?: boolean;
6067
kafka_configuration?: StateKafkaConfiguration;
@@ -110,12 +117,29 @@ export type CollectionState = {
110117
delete?: boolean;
111118
};
112119

120+
export type ChannelSpec = {
121+
name: string;
122+
destination_url: string;
123+
enabled: boolean;
124+
destination_credential: string | null;
125+
};
126+
127+
export type ChannelState = {
128+
id: string;
129+
name: string;
130+
destination_url: string;
131+
enabled: boolean;
132+
destination_credential_id: string | null;
133+
delete?: boolean;
134+
};
135+
113136
export interface ProjectSpec {
114137
name: string;
115138
description: string;
116139
workflows: Record<string | symbol, WorkflowSpec>;
117140
credentials: Record<string | symbol, CredentialSpec>;
118141
collections: Record<string | symbol, CollectionSpec>;
142+
channels: Record<string | symbol, ChannelSpec>;
119143
}
120144

121145
export interface WorkflowState {
@@ -139,13 +163,15 @@ export interface ProjectState {
139163
workflows: Record<string | symbol, WorkflowState>;
140164
project_credentials: Record<string | symbol, CredentialState>;
141165
collections: Record<string | symbol, CollectionState>;
166+
channels: Record<string | symbol, ChannelState>;
142167
}
143168

144169
export interface ProjectPayload {
145170
id: string;
146171
name: string;
147172
description: string;
148173
collections?: Concrete<CollectionState>[];
174+
channels?: Concrete<ChannelState>[];
149175
project_credentials: Concrete<CredentialState>[];
150176
workflows: {
151177
id: string;

packages/deploy/src/validator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ export async function parseAndValidate(
129129
}
130130
}
131131

132+
if (pair.key && pair.key.value === 'channels') {
133+
if (pair.value.value === null) {
134+
return doc.createPair('channels', {});
135+
}
136+
}
137+
132138
if (pair.key && pair.key.value === 'jobs') {
133139
if (pair.value.value === null) {
134140
errors.push({

packages/deploy/test/fixtures.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export function fullExampleSpec() {
55
name: 'my project',
66
description: 'some helpful description',
77
collections: {},
8+
channels: {},
89
credentials: {},
910
workflows: {
1011
'workflow-one': {
@@ -58,6 +59,7 @@ export function fullExampleState() {
5859
name: 'my project',
5960
description: 'some helpful description',
6061
collections: {},
62+
channels: {},
6163
project_credentials: {},
6264
workflows: {
6365
'workflow-one': {
@@ -254,6 +256,7 @@ export const lightningProjectState = {
254256
name: 'collection-one',
255257
},
256258
},
259+
channels: {},
257260
project_credentials: {
258261
'email@test.com-Basic-Auth': {
259262
id: '25f48989-d349-4eb8-99c3-923ebba5b116',

0 commit comments

Comments
 (0)