diff --git a/README.md b/README.md index 5eb918e..5b8e157 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,9 @@ Then add **hubot-pager-me** to your `external-scripts.json`: | `HUBOT_PAGERDUTY_FROM_EMAIL` | Yes | The email of the default "actor" user for incident creation and modification. | | `HUBOT_PAGERDUTY_USER_ID` | No`*` | The user ID of a PagerDuty user for your bot. This is only required if you want chat users to be able to trigger incidents without their own PagerDuty user. | `HUBOT_PAGERDUTY_SERVICE_API_KEY` | No`*` | The [Incident Service Key](https://v2.developer.pagerduty.com/docs/incident-creation-api) to use when creating a new incident. This should be assigned to a dummy escalation policy that doesn't actually notify, as Hubot will trigger on this before reassigning it. -| `HUBOT_PAGERDUTY_SERVICES` | No | Provide a comma separated list of service identifiers (e.g. `PFGPBFY,AFBCGH`) to restrict queries to only those services. | -| `HUBOT_PAGERDUTY_SCHEDULES` | No | Provide a comma separated list of schedules identifiers (e.g. `PFGPBFY,AFBCGH`) to restrict queries to only those schedules. | +| `HUBOT_PAGERDUTY_SERVICES` | No | Provide a comma separated list of service identifiers (e.g. `PFGPBFY,AFBCGH`) to restrict queries to only those services. +| `HUBOT_PAGERDUTY_SCHEDULES` | No | Provide a comma separated list of schedules identifiers (e.g. `PFGPBFY,AFBCGH`) to restrict queries to only those schedules. +| `HUBOT_PAGERDUTY_DEFAULT_SCHEDULE` | No | A specific schedule that can be triggered using `pager default trigger` to reduce typing for users. `*` - May be required for certain actions. diff --git a/package-lock.json b/package-lock.json index a31122a..3a7ed6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "hubot-pager-me", - "version": "4.0.4", + "version": "4.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "hubot-pager-me", - "version": "4.0.4", + "version": "4.1.0", "license": "MIT", "dependencies": { "async": "^3.2.4", diff --git a/package.json b/package.json index 6048600..b9889de 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hubot-pager-me", "description": "PagerDuty integration for Hubot", - "version": "4.0.4", + "version": "4.1.0", "author": "Josh Nichols ", "license": "MIT", "keywords": [ diff --git a/src/scripts/pagerduty.js b/src/scripts/pagerduty.js index 2852a31..9232bec 100644 --- a/src/scripts/pagerduty.js +++ b/src/scripts/pagerduty.js @@ -4,10 +4,11 @@ // Commands: // hubot pager me as - remember your pager email is // hubot pager forget me - forget your pager email -// hubot Am I on call - return if I'm currently on call or not +// hubot am I on call - return if I'm currently on call or not // hubot who's on call - return a list of services and who is on call for them // hubot who's on call for - return the username of who's on call for any schedule matching // hubot pager trigger - create a new incident with and assign it to +// hubot pager default trigger - create a new incident with and assign it the user currently on call for our default schedule // hubot pager trigger - create a new incident with and assign it the user currently on call for // hubot pager incidents - return the current incidents // hubot pager sup - return the current incidents @@ -45,9 +46,12 @@ const moment = require('moment-timezone'); const pagerDutyUserId = process.env.HUBOT_PAGERDUTY_USER_ID; const pagerDutyServiceApiKey = process.env.HUBOT_PAGERDUTY_SERVICE_API_KEY; const pagerDutySchedules = process.env.HUBOT_PAGERDUTY_SCHEDULES; +const pagerDutyDefaultSchedule = process.env.HUBOT_PAGERDUTY_DEFAULT_SCHEDULE; + module.exports = function (robot) { let campfireUserToPagerDutyUser; + robot.respond(/pager( me)?$/i, function (msg) { if (pagerduty.missingEnvironmentForApi(msg)) { return; @@ -151,110 +155,42 @@ module.exports = function (robot) { robot.respond(/(pager|major)( me)? (?:trigger|page) ([\w\-]+)$/i, (msg) => msg.reply("Please include a user or schedule to page, like 'hubot pager infrastructure everything is on fire'.") ); + robot.respond( - /(pager|major)( me)? (?:trigger|page) ((["'])([^\4]*?)\4|“([^”]*?)”|‘([^’]*?)’|([\.\w\-]+)) (.+)$/i, + /(pager|major)( me)? default (?:trigger|page) ?(.+)?$/i, function (msg) { msg.finish(); if (pagerduty.missingEnvironmentForApi(msg)) { return; } - + if (!pagerDutyDefaultSchedule) { + msg.send("No default schedule configured! Cannot send a page! Please set HUBOT_PAGERDUTY_DEFAULT_SCHEDULE"); + return; + } const fromUserName = msg.message.user.name; - let query = msg.match[5] || msg.match[6] || msg.match[7] || msg.match[8]; - const reason = msg.match[9]; - const description = `${reason} - @${fromUserName}`; - - // Figure out who we are - campfireUserToPagerDutyUser(msg, msg.message.user, false, function (triggerdByPagerDutyUser) { - const triggerdByPagerDutyUserId = (() => { - if (triggerdByPagerDutyUser != null) { - return triggerdByPagerDutyUser.id; - } else if (pagerDutyUserId) { - return pagerDutyUserId; - } - })(); - if (!triggerdByPagerDutyUserId) { - msg.send( - `Sorry, I can't figure your PagerDuty account, and I don't have my own :( Can you tell me your PagerDuty email with \`${robot.name} pager me as you@yourdomain.com\` or make sure you've set the HUBOT_PAGERDUTY_USER_ID environment variable?` - ); - return; - } - - // Figure out what we're trying to page - reassignmentParametersForUserOrScheduleOrEscalationPolicy(msg, query, function (results) { - if (!(results.assigned_to_user || results.escalation_policy)) { - msg.reply(`Couldn't find a user or unique schedule or escalation policy matching ${query} :/`); - return; - } - - return pagerDutyIntegrationAPI(msg, 'trigger', description, function (json) { - query = { incident_key: json.incident_key }; - - msg.reply(':pager: triggered! now assigning it to the right user...'); - - return setTimeout( - () => - pagerduty.get('/incidents', query, function (err, json) { - if (err != null) { - robot.emit('error', err, msg); - return; - } - - if ((json != null ? json.incidents.length : undefined) === 0) { - msg.reply("Couldn't find the incident we just created to reassign. Please try again :/"); - } else { - } - - let data = null; - if (results.escalation_policy) { - data = { - incidents: json.incidents.map((incident) => ({ - id: incident.id, - type: 'incident_reference', + query = pagerDutyDefaultSchedule; + reason = msg.match[4] || "We Need Help!" + description = `${reason} - @${fromUserName}`; + robot.logger.debug(`Triggering a default page to ${pagerDutyDefaultSchedule} saying ${description}!`); + incidentTrigger(msg, query, description); + } + ); - escalation_policy: { - id: results.escalation_policy, - type: 'escalation_policy_reference', - }, - })), - }; - } else { - data = { - incidents: json.incidents.map((incident) => ({ - id: incident.id, - type: 'incident_reference', - - assignments: [ - { - assignee: { - id: results.assigned_to_user, - type: 'user_reference', - }, - }, - ], - })), - }; - } + robot.respond( + /(pager|major)( me)? (?:trigger|page) ((["'])([^\4]*?)\4|“([^”]*?)”|‘([^’]*?)’|([\.\w\-]+)) ?(.+)?$/i, + function (msg) { + msg.finish(); - return pagerduty.put('/incidents', data, function (err, json) { - if (err != null) { - robot.emit('error', err, msg); - return; - } - - if ((json != null ? json.incidents.length : undefined) === 1) { - return msg.reply(`:pager: assigned to ${results.name}!`); - } else { - return msg.reply('Problem reassigning the incident :/'); - } - }); - }), - 10000 - ); - }); - }); - }); + if (pagerduty.missingEnvironmentForApi(msg)) { + return; + } + const fromUserName = msg.message.user.name; + const query = msg.match[5] || msg.match[6] || msg.match[7] || msg.match[8]; + const reason = msg.match[9] || "We Need Help!"; + const description = `${reason} - @${fromUserName}`; + robot.logger.debug(`Triggering a page to ${query} saying ${description}!`); + incidentTrigger(msg, query, description); } ); @@ -722,14 +658,14 @@ module.exports = function (robot) { ); return; } - - withScheduleMatching(msg, msg.match[2], function (matchingSchedule) { + const schedule = msg.match[2].replace(/(^"|"$)/mg, ''); + const minutes = parseInt(msg.match[3]); + withScheduleMatching(msg, schedule, function (matchingSchedule) { if (!matchingSchedule.id) { return; } let start = moment().format(); - const minutes = parseInt(msg.match[3]); let end = moment().add(minutes, 'minutes').format(); const override = { start, @@ -1182,6 +1118,98 @@ module.exports = function (robot) { } }); + var incidentTrigger = (msg, query, description) => + // Figure out who we are + campfireUserToPagerDutyUser(msg, msg.message.user, false, function (triggerdByPagerDutyUser) { + const triggerdByPagerDutyUserId = (() => { + if (triggerdByPagerDutyUser != null) { + return triggerdByPagerDutyUser.id; + } else if (pagerDutyUserId) { + return pagerDutyUserId; + } + })(); + if (!triggerdByPagerDutyUserId) { + msg.send( + `Sorry, I can't figure your PagerDuty account, and I don't have my own :( Can you tell me your PagerDuty email with \`${robot.name} pager me as you@yourdomain.com\` or make sure you've set the HUBOT_PAGERDUTY_USER_ID environment variable?` + ); + return; + } + + // Figure out what we're trying to page + reassignmentParametersForUserOrScheduleOrEscalationPolicy(msg, query, function (results) { + if (!(results.assigned_to_user || results.escalation_policy)) { + msg.reply(`Couldn't find a user or unique schedule or escalation policy matching ${query} :/`); + return; + } + + return pagerDutyIntegrationAPI(msg, 'trigger', description, function (json) { + query = { incident_key: json.incident_key }; + + msg.reply(':pager: triggered! now assigning it to the right user...'); + + return setTimeout( + () => + pagerduty.get('/incidents', query, function (err, json) { + if (err != null) { + robot.emit('error', err, msg); + return; + } + + if ((json != null ? json.incidents.length : undefined) === 0) { + msg.reply("Couldn't find the incident we just created to reassign. Please try again :/"); + } else { + } + + let data = null; + if (results.escalation_policy) { + data = { + incidents: json.incidents.map((incident) => ({ + id: incident.id, + type: 'incident_reference', + + escalation_policy: { + id: results.escalation_policy, + type: 'escalation_policy_reference', + }, + })), + }; + } else { + data = { + incidents: json.incidents.map((incident) => ({ + id: incident.id, + type: 'incident_reference', + + assignments: [ + { + assignee: { + id: results.assigned_to_user, + type: 'user_reference', + }, + }, + ], + })), + }; + } + + return pagerduty.put('/incidents', data, function (err, json) { + if (err != null) { + robot.emit('error', err, msg); + return; + } + + if ((json != null ? json.incidents.length : undefined) === 1) { + return msg.reply(`:pager: assigned to ${results.name}!`); + } else { + return msg.reply('Problem reassigning the incident :/'); + } + }); + }), + 10000 + ); + }); + }); + }); + const userEmail = (user) => user.pagerdutyEmail || user.email_address || diff --git a/test/pager-me-test.js b/test/pager-me-test.js index 5812039..b2d3514 100644 --- a/test/pager-me-test.js +++ b/test/pager-me-test.js @@ -7,7 +7,7 @@ const { expect } = chai; describe('pagerduty', function () { before(function () { this.triggerRegex = - /(pager|major)( me)? (?:trigger|page) ((["'])([^\4]*?)\4|“([^”]*?)”|‘([^’]*?)’|([\.\w\-]+)) (.+)$/i; + /(pager|major)( me)? (?:trigger|page) ((["'])([^\4]*?)\4|“([^”]*?)”|‘([^’]*?)’|([\.\w\-]+)) ?(.+)?$/i; this.schedulesRegex = /(pager|major)( me)? schedules( ((["'])([^]*?)\5|(.+)))?$/i; this.whosOnCallRegex = /who(?:’s|'s|s| is|se)? (?:on call|oncall|on-call)(?:\?)?(?: (?:for )?((["'])([^]*?)\2|(.*?))(?:\?|$))?$/i; @@ -46,6 +46,10 @@ describe('pagerduty', function () { expect(this.robot.respond).to.have.been.calledWith(/(pager|major)( me)? (?:trigger|page) ([\w\-]+)$/i); }); + it('registers a pager default trigger with message listener', function () { + expect(this.robot.respond).to.have.been.calledWith(/(pager|major)( me)? default (?:trigger|page) ?(.+)?$/i); + }); + it('registers a pager trigger with message listener', function () { expect(this.robot.respond).to.have.been.calledWith(this.triggerRegex); });