Snap-in developmentReferences

Snap-in manifest

The following section is for version 2 of the manifest specification. For the previous version, see Manifest V1.

The snap-in manifest is what the developers write to define a snap-in. The manifest has the following sections:

Version

The version specifies the manifest version. The following documentation is for version 2 of the manifest. In the manifest, specify the following:

1version: 2

Keyrings

Keyrings are secret tokens used to make calls to external systems. They can be categorized either as organization scoped or user scoped. Keyrings are specified in the manifest with the following syntax:

1keyrings:
2 organization:
3 - name: <The name of the keyring that should be used for the snap-in.>
4 description: <A description of the functions of this keyring.>
5 display_name: <The name shown to the user.>
6 types: <List of all keyring types that can be selected by the end-user.>
7
8 - name: <The name of the keyring that should be used for the snap-in.>
9 description: <A description of the functions of this keyring.>
10 display_name: <The name shown to the user.>
11 types: <List of all keyring types that can be selected by the end-user.>
12 user:
13 - name: <The name of the keyring that should be used for the snap-in.>
14 description: <A description of the functions of this keyring.>
15 display_name: <The name shown to the user.>
16 types: <List of all keyring types that can be selected by the end-user.>
17
18 - name: <The name of the keyring that should be used for the snap-in.>
19 description: <A description of the functions of this keyring.>
20 display_name: <The name shown to the user.>
21 types: <List of all keyring types that can be selected by the end-user.>

For example:

1keyrings:
2 organization:
3 - name: my-org-secret-token
4 description: The secret tokens stores the keys to the kingdom
5 types:
6 - snap_in_secret
7 display_name: Organization secret token
8 user:
9 - name: my-secret-token
10 description: The secret tokens stores the keys to the kingdom
11 types:
12 - snap_in_secret
13 display_name: Your secret token

Keyrings defined in the manifest can be provided in the snap-in configuration screens and are made available to the function. The keyring type is used to determine the type of the keyring and restricts selection on the configuration screen to valid types.

Organization keyrings are common to the organization, while user keyrings are set per user. User keyrings are optional, so the developer must correctly handle cases where the keyring isn’t found.

To view the supported connection types, see Keyrings.

Developer keyrings

Developer keyrings are provided by the snap-in version developer. They’re available across all installations and hidden from the installer. Only the secret string type can be used as developer keyrings.

1developer_keyrings:
2 - name: <The name of the keyring that should be used for the snap-in.>
3 description: <A description of the functions of this keyring.>
4 display_name: <The name shown to the developer.>
5
6 - name: <The name of the keyring that should be used for the snap-in.>
7 description: <A description of the functions of this keyring.>
8 display_name: <The name shown to the developer.>

For example:

1developer_keyrings:
2 - name: mongodb
3 description: Store usage statistics
4 display_name: MongoDB PAT
5
6 - name: discord
7 description: Access additional discord's API
8 display_name: Discord PAT

Select the developer connection while creating snap_in_version. The DevRev CLI automatically detects such keyrings in the manifest and asks for them:

$devrev snap_in_version create-one --manifest manifest.yaml
>Please provide mapping for the developer keyrings:
>Use the arrow keys to navigate: ↓ ↑ → ←
>? mongodb:
> ▸ mongodb
> discord

Developer keyrings can only be created in the UI. They’re of the Snap-in Secret type.

Event sources

Event sources can be categorized as “organization” level and “user” level. Event sources are specified in the manifest with the following syntax:

1 event_sources:
2 organization:
3 - name: <The name of the event-source that should be used for the snap-in.>
4 description: <A description of the functions of this event-source.>
5 display_name: <The name shown to the user.>
6 type: <An enum specifying the type of source to create.>
7 setup_instructions: <Instructions shown to the end user as an option.>
8 config:
9 <An object containing event source configuration.>
10
11 - name: <The name of the event-source that should be used for the snap-in.>
12 description: <A description of the functions of this event-source.>
13 display_name: <The name shown to the user.>
14 type: <An enum specifying the type of source to create.>
15 user:
16 - name: <The name of the event-source that should be used for the snap-in.>
17 description: <A description of the functions of this event-source.>
18 display_name: <The name shown to the user.>
19 type: <An enum specifying the type of source to create.>
20 setup_instructions: <Instructions shown to the end user as an option.>
21 config:
22 <An object containing event source configuration.>
23
24 - name: <The name of the event-source that should be used for the snap-in.>
25 description: <A description of the functions of this event-source.>
26 display_name: <The name shown to the user.>
27 type: <An enum specifying the type of source to create.>

Refer to Event sources for a checklist of supported event sources and their corresponding event types.

Refer to the webhook event-request example for a list of supported webhooks:

1{
2 "account_created": {
3 "account": {
4 "created_by": {},
5 "created_date": "2023-01-01T12:00:00.000Z",
6 "display_id": "string",
7 "id": "string",
8 "modified_by": {},
9 "modified_date": "2023-01-01T12:00:00.000Z",
10 "display_name": "string",
11 "description": "string",
12 "domains": [
13 null
14 ],
15 "external_refs": [
16 null
17 ],
18 "owned_by": [
19 {}
20 ],
21 "tier": "string"
22 }
23 },
24 "account_deleted": {
25 "id": "ACC-12345"
26 },
27 "account_updated": {
28 "account": {
29 "created_by": {},
30 "created_date": "2023-01-01T12:00:00.000Z",
31 "display_id": "string",
32 "id": "string",
33 "modified_by": {},
34 "modified_date": "2023-01-01T12:00:00.000Z",
35 "display_name": "string",
36 "description": "string",
37 "domains": [
38 null
39 ],
40 "external_refs": [
41 null
42 ],
43 "owned_by": [
44 {}
45 ],
46 "tier": "string"
47 }
48 },
49 "conversation_created": {
50 "conversation": {
51 "created_by": {},
52 "created_date": "2023-01-01T12:00:00.000Z",
53 "display_id": "string",
54 "id": "string",
55 "modified_by": {},
56 "modified_date": "2023-01-01T12:00:00.000Z",
57 "description": "string",
58 "group": {},
59 "members": [
60 {}
61 ],
62 "messages": [
63 {}
64 ],
65 "metadata": {},
66 "owned_by": [
67 {}
68 ],
69 "stage": {},
70 "tags": [
71 {}
72 ],
73 "title": "string"
74 }
75 },
76 "conversation_deleted": {
77 "id": "string"
78 },
79 "conversation_updated": {
80 "conversation": {
81 "created_by": {},
82 "created_date": "2023-01-01T12:00:00.000Z",
83 "display_id": "string",
84 "id": "string",
85 "modified_by": {},
86 "modified_date": "2023-01-01T12:00:00.000Z",
87 "description": "string",
88 "group": {},
89 "members": [
90 {}
91 ],
92 "messages": [
93 {}
94 ],
95 "metadata": {},
96 "owned_by": [
97 {}
98 ],
99 "stage": {},
100 "tags": [
101 {}
102 ],
103 "title": "string"
104 }
105 },
106 "dev_user_created": {
107 "dev_user": {
108 "created_by": {},
109 "created_date": "2023-01-01T12:00:00.000Z",
110 "display_id": "string",
111 "id": "string",
112 "modified_by": {},
113 "modified_date": "2023-01-01T12:00:00.000Z",
114 "display_name": "string",
115 "display_picture": {},
116 "email": "string",
117 "full_name": "string",
118 "phone_numbers": [
119 null
120 ],
121 "state": "active",
122 "external_identities": [
123 {}
124 ]
125 }
126 },
127 "dev_user_deleted": {
128 "id": "string"
129 },
130 "dev_user_updated": {
131 "dev_user": {
132 "created_by": {},
133 "created_date": "2023-01-01T12:00:00.000Z",
134 "display_id": "string",
135 "id": "string",
136 "modified_by": {},
137 "modified_date": "2023-01-01T12:00:00.000Z",
138 "display_name": "string",
139 "display_picture": {},
140 "email": "string",
141 "full_name": "string",
142 "phone_numbers": [
143 null
144 ],
145 "state": "active",
146 "external_identities": [
147 {}
148 ]
149 }
150 },
151 "id": "string",
152 "part_created": {
153 "part": {
154 "created_by": {},
155 "created_date": "2023-01-01T12:00:00.000Z",
156 "display_id": "string",
157 "id": "string",
158 "modified_by": {},
159 "modified_date": "2023-01-01T12:00:00.000Z",
160 "artifacts": [
161 null
162 ],
163 "description": "string",
164 "name": "string",
165 "owned_by": [
166 {}
167 ],
168 "tags": [
169 {}
170 ]
171 }
172 },
173 "part_deleted": {
174 "id": "PROD-12345"
175 },
176 "part_updated": {
177 "part": {
178 "created_by": {},
179 "created_date": "2023-01-01T12:00:00.000Z",
180 "display_id": "string",
181 "id": "string",
182 "modified_by": {},
183 "modified_date": "2023-01-01T12:00:00.000Z",
184 "artifacts": [
185 null
186 ],
187 "description": "string",
188 "name": "string",
189 "owned_by": [
190 {}
191 ],
192 "tags": [
193 {}
194 ]
195 }
196 },
197 "rev_org_created": {
198 "rev_org": {
199 "created_by": {},
200 "created_date": "2023-01-01T12:00:00.000Z",
201 "display_id": "string",
202 "id": "string",
203 "modified_by": {},
204 "modified_date": "2023-01-01T12:00:00.000Z",
205 "display_name": "string",
206 "description": "string",
207 "domain": "string",
208 "external_ref": "string"
209 }
210 },
211 "rev_org_deleted": {
212 "id": "REV-AbCdEfGh"
213 },
214 "rev_org_updated": {
215 "rev_org": {
216 "created_by": {},
217 "created_date": "2023-01-01T12:00:00.000Z",
218 "display_id": "string",
219 "id": "string",
220 "modified_by": {},
221 "modified_date": "2023-01-01T12:00:00.000Z",
222 "display_name": "string",
223 "description": "string",
224 "domain": "string",
225 "external_ref": "string"
226 }
227 },
228 "rev_user_created": {
229 "rev_user": {
230 "created_by": {},
231 "created_date": "2023-01-01T12:00:00.000Z",
232 "display_id": "string",
233 "id": "string",
234 "modified_by": {},
235 "modified_date": "2023-01-01T12:00:00.000Z",
236 "display_name": "string",
237 "display_picture": {},
238 "email": "string",
239 "full_name": "string",
240 "phone_numbers": [
241 null
242 ],
243 "state": "active",
244 "description": "string",
245 "external_ref": "string",
246 "rev_org": {}
247 }
248 },
249 "rev_user_deleted": {
250 "id": "string"
251 },
252 "rev_user_updated": {
253 "rev_user": {
254 "created_by": {},
255 "created_date": "2023-01-01T12:00:00.000Z",
256 "display_id": "string",
257 "id": "string",
258 "modified_by": {},
259 "modified_date": "2023-01-01T12:00:00.000Z",
260 "display_name": "string",
261 "display_picture": {},
262 "email": "string",
263 "full_name": "string",
264 "phone_numbers": [
265 null
266 ],
267 "state": "active",
268 "description": "string",
269 "external_ref": "string",
270 "rev_org": {}
271 }
272 },
273 "sla_tracker_created": {
274 "sla_tracker": {
275 "created_by": {},
276 "created_date": "2023-01-01T12:00:00.000Z",
277 "display_id": "string",
278 "id": "string",
279 "modified_by": {},
280 "modified_date": "2023-01-01T12:00:00.000Z"
281 }
282 },
283 "sla_tracker_deleted": {
284 "id": "string"
285 },
286 "sla_tracker_updated": {
287 "sla_tracker": {
288 "created_by": {},
289 "created_date": "2023-01-01T12:00:00.000Z",
290 "display_id": "string",
291 "id": "string",
292 "modified_by": {},
293 "modified_date": "2023-01-01T12:00:00.000Z"
294 }
295 },
296 "tag_created": {
297 "tag": {
298 "created_by": {},
299 "created_date": "2023-01-01T12:00:00.000Z",
300 "display_id": "string",
301 "id": "string",
302 "modified_by": {},
303 "modified_date": "2023-01-01T12:00:00.000Z",
304 "allowed_values": [
305 null
306 ],
307 "description": "string",
308 "name": "string"
309 }
310 },
311 "tag_deleted": {
312 "id": "TAG-12345"
313 },
314 "tag_updated": {
315 "tag": {
316 "created_by": {},
317 "created_date": "2023-01-01T12:00:00.000Z",
318 "display_id": "string",
319 "id": "string",
320 "modified_by": {},
321 "modified_date": "2023-01-01T12:00:00.000Z",
322 "allowed_values": [
323 null
324 ],
325 "description": "string",
326 "name": "string"
327 }
328 },
329 "timeline_entry_created": {
330 "entry": {
331 "created_by": {},
332 "created_date": "2023-01-01T12:00:00.000Z",
333 "display_id": "string",
334 "id": "string",
335 "modified_by": {},
336 "modified_date": "2023-01-01T12:00:00.000Z",
337 "object": "string",
338 "object_display_id": "string",
339 "object_type": "capability",
340 "visibility": "external",
341 "artifacts": [
342 null
343 ],
344 "body": "string",
345 "body_type": "snap_kit",
346 "snap_kit_body": {
347 "body": {}
348 },
349 "snap_widget_body": [
350 {}
351 ]
352 }
353 },
354 "timeline_entry_deleted": {
355 "id": "don:core:<partition>:devo/<dev-org-id>:ticket/123:timeline_event/<timeline-event-id>"
356 },
357 "timeline_entry_updated": {
358 "entry": {
359 "created_by": {},
360 "created_date": "2023-01-01T12:00:00.000Z",
361 "display_id": "string",
362 "id": "string",
363 "modified_by": {},
364 "modified_date": "2023-01-01T12:00:00.000Z",
365 "object": "string",
366 "object_display_id": "string",
367 "object_type": "capability",
368 "visibility": "external",
369 "artifacts": [
370 null
371 ],
372 "body": "string",
373 "body_type": "snap_kit",
374 "snap_kit_body": {
375 "body": {}
376 },
377 "snap_widget_body": [
378 {}
379 ]
380 }
381 },
382 "timestamp": "2023-01-01T12:00:00.000Z",
383 "type": "account_created",
384 "verify": {
385 "challenge": "string"
386 },
387 "webhook_created": {
388 "webhook": {
389 "created_by": {},
390 "created_date": "2023-01-01T12:00:00.000Z",
391 "display_id": "string",
392 "id": "string",
393 "modified_by": {},
394 "modified_date": "2023-01-01T12:00:00.000Z",
395 "event_types": [
396 null
397 ],
398 "secret": "string",
399 "status": "active",
400 "url": "string"
401 }
402 },
403 "webhook_deleted": {
404 "id": "don:integration:<partition>:devo/<dev-org-id>:webhook/<webhook-id>"
405 },
406 "webhook_id": "don:integration:<partition>:devo/<dev-org-id>:webhook/<webhook-id>",
407 "webhook_updated": {
408 "webhook": {
409 "created_by": {},
410 "created_date": "2023-01-01T12:00:00.000Z",
411 "display_id": "string",
412 "id": "string",
413 "modified_by": {},
414 "modified_date": "2023-01-01T12:00:00.000Z",
415 "event_types": [
416 null
417 ],
418 "secret": "string",
419 "status": "active",
420 "url": "string"
421 }
422 },
423 "work_created": {
424 "work": {
425 "created_by": {},
426 "created_date": "2023-01-01T12:00:00.000Z",
427 "display_id": "string",
428 "id": "string",
429 "modified_by": {},
430 "modified_date": "2023-01-01T12:00:00.000Z",
431 "applies_to_part": {},
432 "artifacts": [
433 null
434 ],
435 "body": "string",
436 "owned_by": [
437 {}
438 ],
439 "reported_by": [
440 {}
441 ],
442 "stage": {},
443 "tags": [
444 {}
445 ],
446 "target_close_date": "2023-01-01T12:00:00.000Z",
447 "title": "string",
448 "developed_with": [
449 {}
450 ],
451 "priority": "p0"
452 }
453 },
454 "work_deleted": {
455 "id": "ISS-12345"
456 },
457 "work_updated": {
458 "work": {
459 "created_by": {},
460 "created_date": "2023-01-01T12:00:00.000Z",
461 "display_id": "string",
462 "id": "string",
463 "modified_by": {},
464 "modified_date": "2023-01-01T12:00:00.000Z",
465 "applies_to_part": {},
466 "artifacts": [
467 null
468 ],
469 "body": "string",
470 "owned_by": [
471 {}
472 ],
473 "reported_by": [
474 {}
475 ],
476 "stage": {},
477 "tags": [
478 {}
479 ],
480 "target_close_date": "2023-01-01T12:00:00.000Z",
481 "title": "string",
482 "developed_with": [
483 {}
484 ],
485 "priority": "p0"
486 }
487 }
488}

For example:

1event_sources:
2 organization:
3 - name: devrev-webhook
4 description: Events coming from GitHub
5 display_name: DevRev webhook
6 type: devrev-webhook
7 config:
8 event_types:
9 - work_created

Inputs

Inputs are implemented using per-object schemas, which is a customization technique to store custom schemas inline with the object. Each input’s schema maps to a FieldDescriptor. Inputs, like keyrings and event sources, are organization and user scoped. Organization-scoped inputs are set by the admins of the organization and are common across all users. User inputs are set individually.

Inputs are defined as:

1inputs:
2 organization:
3 - name: <The name of the input.>
4 description: <A description of the functions of this input.>
5 field_type: <The supported input types.>
6 id_type: <If the field type is id, so what are the supported object types whose ids this input can store?>
7 is_required: <Is this input required?>
8 default_value: <The default value for this input>
9 ui:
10 display_name: <Input field display name.>
11 user:
12 - name: <The name of the input.>
13 description: <A description of the functions of this input.>
14 field_type: <The supported input types.>
15 id_type: <If the field type is id, so what are the supported object types whose ids this input can store?>
16 is_required: <Is this input required?>
17 default_value: <The default value for this input>
18 ui:
19 display_name: <Input field display name.>

Inputs of type timestamp, date and array of booleans aren’t supported.

Tags

In the manifest, pass the name and description of the tag.

For example:

1tags:
2 - name: github.branch.name
3 description: Tag storing github branch name.

Commands

In the manifest, you need to specify the command’s name, its namespace, and the surfaces where it can appear, such as comment discussions. It also specifies the UI description, usage hints, and the function to be triggered when the command is invoked.

1commands:
2 - name: summarize
3 namespace: turing
4 description: Summarizes the conversation
5 surfaces:
6 - surface: discussions
7 object_types:
8 - conversation
9 usage_hint: "number of tokens to generate"
10 function: generate_summary

For commands, the <name, namespace> pair should be unique across the Org in which it’s installed.

Functions

In the manifest, pass the name and description of the functions.

1functions:
2 - name: create_work
3 description: Function containing logic to create a DevRev work.
4
5 - name: post_message
6 description: Function containing logic to post a message on newly created work.

For functions, you also need to provide the actual JS/TS code behind this function. Refer to the README in the provided template.

Automations

Automation refers to linking events from the event sources to your functions.

Automations are defined as:

1automations:
2 - name: <The name of the automation.>
3 source: <Name of the event source specified in the manifest from which the events coming in could trigger this automation.>
4 event_types:
5 - <Event from the source on which you need to run the code.>
6 function: <Specifies which function should be run from the manifest.>

For custom event sources, whatever event key you emit from your policy, the event name will be custom:<your event key>.