{ "kind": "open-flow-workflow", "version": 1, "name": "Resolve PagerDuty and Jira from Mattermost", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_4381e4890f2f3a43": { "name": "Receive a Mattermost action", "kind": "webhook", "bodyFields": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "channel_id" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "context" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "user_id" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "user_name" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "channel_name" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "team_id" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "team_domain" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "team_name" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "post_id" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "trigger_id" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "type" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "data_source" } ], "method": "POST", "options": { "responseData": "{}", "responseHeaders": { "Content-Type": "application/json" }, "responseStatusCode": 200 } }, "n_8cb90e90e1d31b1b": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4381e4890f2f3a43", "output": "body" } ] }, "secret": { "kind": "unset" }, "from": { "kind": "value", "value": "YOUR_PAGERDUTY_EMAIL" }, "transitionId": { "kind": "value", "value": "YOUR_JIRA_TRANSITION_ID" }, "announcementChannel": { "kind": "value", "value": "YOUR_ANNOUNCEMENT_CHANNEL_ID" } }, "name": "Validate the action", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "secret" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "from" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "transitionId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "announcementChannel" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "nullable": false, "handle": "incidentId" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "A Mattermost object ID." }, "nullable": false, "handle": "channelId" }, { "jsonSchema": { "type": "string", "format": "email", "description": "Email address of the PagerDuty user resolving the incident. PagerDuty requires this header for write operations." }, "nullable": false, "handle": "from" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "A Mattermost object ID." }, "nullable": false, "handle": "announcementChannel" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "transitionId" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "endpoint" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "jiraBody" } ], "name": "Validate the action", "moduleId": "n_fd3b1d210e577065", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_9ffebb3a6b3f0ad0": { "inputs": { "incident_id": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8cb90e90e1d31b1b", "output": "incidentId" } ] }, "from": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8cb90e90e1d31b1b", "output": "from" } ] } }, "name": "Resolve the PagerDuty incident", "kind": "task", "task": { "inputs": [ { "description": "PagerDuty resource ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "nullable": false, "handle": "incident_id" }, { "description": "Email address of the PagerDuty user resolving the incident. PagerDuty requires this header for write operations.", "jsonSchema": { "type": "string", "format": "email", "description": "Email address of the PagerDuty user resolving the incident. PagerDuty requires this header for write operations." }, "nullable": false, "handle": "from" }, { "description": "Optional resolution note for the incident.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional resolution note for the incident." }, "nullable": true, "handle": "resolution", "value": null } ], "outputs": [ { "description": "PagerDuty incident record.", "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty incident object type." }, "summary": { "type": "string", "description": "Incident summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the incident." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the incident." }, "incident_number": { "type": "integer", "description": "PagerDuty incident number." }, "title": { "type": "string", "description": "Incident title." }, "description": { "type": "string", "description": "Incident description." }, "status": { "type": "string", "enum": [ "triggered", "acknowledged", "resolved" ], "description": "Incident status." }, "urgency": { "type": "string", "enum": [ "high", "low" ], "description": "Incident urgency." }, "created_at": { "type": "string", "description": "Timestamp in ISO 8601 format." }, "updated_at": { "type": "string", "description": "Timestamp in ISO 8601 format." }, "service": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty service reference type." }, "summary": { "type": "string", "description": "Service display summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the service." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the service." } }, "additionalProperties": true, "description": "PagerDuty service reference." }, "assignments": { "type": "array", "items": { "type": "object", "properties": { "at": { "type": "string", "description": "Timestamp in ISO 8601 format." }, "assignee": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty user reference type." }, "summary": { "type": "string", "description": "User display summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the user." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the user." } }, "additionalProperties": true, "description": "PagerDuty user reference." } }, "additionalProperties": true, "description": "PagerDuty incident assignment." }, "description": "Current incident assignments." }, "escalation_policy": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty escalation policy reference type." }, "summary": { "type": "string", "description": "Escalation policy display summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the escalation policy." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the escalation policy." } }, "additionalProperties": true, "description": "PagerDuty escalation policy reference." } }, "additionalProperties": true, "description": "PagerDuty incident record." }, "nullable": false, "handle": "incident" } ], "name": "Resolve the PagerDuty incident", "executor": { "kind": "connector", "action": "pagerduty.resolve_incident" } } }, "n_886c2b367abea6d3": { "inputs": { "incident": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9ffebb3a6b3f0ad0", "output": "incident" } ] }, "incidentId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8cb90e90e1d31b1b", "output": "incidentId" } ] } }, "name": "Confirm incident resolution", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty incident object type." }, "summary": { "type": "string", "description": "Incident summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the incident." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the incident." }, "incident_number": { "type": "integer", "description": "PagerDuty incident number." }, "title": { "type": "string", "description": "Incident title." }, "description": { "type": "string", "description": "Incident description." }, "status": { "type": "string", "enum": [ "triggered", "acknowledged", "resolved" ], "description": "Incident status." }, "urgency": { "type": "string", "enum": [ "high", "low" ], "description": "Incident urgency." }, "created_at": { "type": "string", "description": "Timestamp in ISO 8601 format." }, "updated_at": { "type": "string", "description": "Timestamp in ISO 8601 format." }, "service": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty service reference type." }, "summary": { "type": "string", "description": "Service display summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the service." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the service." } }, "additionalProperties": true, "description": "PagerDuty service reference." }, "assignments": { "type": "array", "items": { "type": "object", "properties": { "at": { "type": "string", "description": "Timestamp in ISO 8601 format." }, "assignee": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty user reference type." }, "summary": { "type": "string", "description": "User display summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the user." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the user." } }, "additionalProperties": true, "description": "PagerDuty user reference." } }, "additionalProperties": true, "description": "PagerDuty incident assignment." }, "description": "Current incident assignments." }, "escalation_policy": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "PagerDuty resource ID." }, "type": { "type": "string", "description": "PagerDuty escalation policy reference type." }, "summary": { "type": "string", "description": "Escalation policy display summary." }, "self": { "type": "string", "format": "uri", "description": "API URL for the escalation policy." }, "html_url": { "type": "string", "format": "uri", "description": "Web URL for the escalation policy." } }, "additionalProperties": true, "description": "PagerDuty escalation policy reference." } }, "additionalProperties": true, "description": "PagerDuty incident record." }, "nullable": false, "handle": "incident" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "incidentId" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "The Markdown message body to post." }, "nullable": false, "handle": "announcement" } ], "name": "Confirm incident resolution", "moduleId": "n_498236b8e1feb1df", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_14a8ec49ed869a10": { "inputs": { "endpoint": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8cb90e90e1d31b1b", "output": "endpoint" } ] }, "query": { "kind": "value", "value": {} }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8cb90e90e1d31b1b", "output": "jiraBody" } ] } }, "name": "Transition the Jira issue", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "endpoint" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": [ "string", "number", "boolean", "null" ] } }, "nullable": true, "handle": "query" }, { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" }, { "jsonSchema": { "const": "base64" }, "nullable": true, "handle": "bodyEncoding" } ], "name": "Transition the Jira issue", "executor": { "providerId": "jira", "method": "POST", "query": { "mode": "object", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "kind": "connector-proxy" } } }, "n_8475e7163bf88f41": { "inputs": { "statusCode": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_14a8ec49ed869a10", "output": "statusCode" } ] } }, "name": "Confirm Jira transition", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "The Markdown message body to post." }, "nullable": false, "handle": "message" } ], "name": "Confirm Jira transition", "moduleId": "n_5e0ced6a3567f1cb", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_3bef17ad294ea607": { "inputs": { "channelId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8cb90e90e1d31b1b", "output": "channelId" } ] }, "message": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8475e7163bf88f41", "output": "message" } ] } }, "name": "Confirm in the action channel", "kind": "task", "task": { "inputs": [ { "description": "A Mattermost object ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "A Mattermost object ID." }, "nullable": false, "handle": "channelId" }, { "description": "The Markdown message body to post.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The Markdown message body to post." }, "nullable": false, "handle": "message" }, { "description": "Optional root post ID for replying in a thread.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional root post ID for replying in a thread." }, "nullable": true, "handle": "rootId", "value": null }, { "description": "Optional Mattermost post props object.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Optional Mattermost post props object." }, "nullable": true, "handle": "props", "value": null } ], "outputs": [ { "description": "A Mattermost post object.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Mattermost post object." }, "nullable": false, "handle": "post" }, { "description": "The raw Mattermost API JSON response.", "jsonSchema": { "description": "The raw Mattermost API JSON response." }, "nullable": false, "handle": "raw" } ], "name": "Confirm in the action channel", "executor": { "kind": "connector", "action": "mattermost.create_post" } } }, "n_0bb5f4fa81528107": { "inputs": { "channelId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8cb90e90e1d31b1b", "output": "announcementChannel" } ] }, "message": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_886c2b367abea6d3", "output": "announcement" } ] } }, "name": "Announce the resolved incident", "kind": "task", "task": { "inputs": [ { "description": "A Mattermost object ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "A Mattermost object ID." }, "nullable": false, "handle": "channelId" }, { "description": "The Markdown message body to post.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The Markdown message body to post." }, "nullable": false, "handle": "message" }, { "description": "Optional root post ID for replying in a thread.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional root post ID for replying in a thread." }, "nullable": true, "handle": "rootId", "value": null }, { "description": "Optional Mattermost post props object.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Optional Mattermost post props object." }, "nullable": true, "handle": "props", "value": null } ], "outputs": [ { "description": "A Mattermost post object.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Mattermost post object." }, "nullable": false, "handle": "post" }, { "description": "The raw Mattermost API JSON response.", "jsonSchema": { "description": "The raw Mattermost API JSON response." }, "nullable": false, "handle": "raw" } ], "name": "Announce the resolved incident", "executor": { "kind": "connector", "action": "mattermost.create_post" } } } }, "edges": [ { "source": "n_4381e4890f2f3a43", "target": "n_8cb90e90e1d31b1b" }, { "source": "n_8cb90e90e1d31b1b", "target": "n_9ffebb3a6b3f0ad0" }, { "source": "n_9ffebb3a6b3f0ad0", "target": "n_886c2b367abea6d3" }, { "source": "n_886c2b367abea6d3", "target": "n_14a8ec49ed869a10" }, { "source": "n_14a8ec49ed869a10", "target": "n_8475e7163bf88f41" }, { "source": "n_8475e7163bf88f41", "target": "n_3bef17ad294ea607" }, { "source": "n_3bef17ad294ea607", "target": "n_0bb5f4fa81528107" } ] } }, "modules": { "n_fd3b1d210e577065": { "name": "Validate the action", "imports": [], "source": "export default function planResolution({body,secret,from,transitionId,announcementChannel}){\n if(typeof secret!=='string'||secret.length<24||secret==='YOUR_ACTION_SECRET')throw Error('Configure a strong action secret');if(typeof body?.context?.action_secret!=='string'||body.context.action_secret!==secret)throw Error('Invalid action secret');const incident=body?.context?.pagerduty_incident,channel=body?.channel_id,key=body?.context?.jira_key;if(typeof incident!=='string'||!incident.trim()||typeof channel!=='string'||!channel.trim()||typeof key!=='string'||!/^[A-Za-z][A-Za-z0-9_]*-[1-9][0-9]*$/.test(key))throw Error('Missing or invalid incident, channel or Jira key');if(typeof from!=='string'||!/^\\S+@\\S+\\.\\S+$/.test(from))throw Error('Configure PagerDuty user email');if(typeof transitionId!=='string'||!/^\\d+$/.test(transitionId))throw Error('Configure Jira transition ID');if(typeof announcementChannel!=='string'||!announcementChannel.trim()||announcementChannel==='YOUR_ANNOUNCEMENT_CHANNEL_ID')throw Error('Configure announcement channel');return{incidentId:incident,channelId:channel,from,announcementChannel,transitionId,endpoint:'/issue/'+encodeURIComponent(key)+'/transitions',jiraBody:{transition:{id:transitionId}}};\n}\n" }, "n_498236b8e1feb1df": { "name": "Confirm incident resolution", "imports": [], "source": "export default function confirmResolution({incident,incidentId}){if(!incident||incident.id!==incidentId||incident.status!=='resolved')throw Error('PagerDuty did not confirm resolution');const summary=typeof incident.summary==='string'&&incident.summary.trim()?incident.summary:incidentId;return{announcement:'🎉 The incident ('+summary+') was resolved by the lovely folks in the on-call team!'};}\n" }, "n_5e0ced6a3567f1cb": { "name": "Confirm Jira transition", "imports": [], "source": "export default function confirmJiraTransition({statusCode}){if(statusCode!==204)throw Error('Jira did not confirm transition; inspect the issue before retrying');return{message:'💪 This issue got closed in PagerDuty and Jira.'};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }