Skip to content

Commit

Permalink
Merge pull request #228 from johnseekins-pathccm/regex-fixes
Browse files Browse the repository at this point in the history
A few incident trigger tweaks
  • Loading branch information
stephenyeargin authored Oct 1, 2024
2 parents 46ca664 + 028978e commit 399082e
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 104 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hubot-pager-me",
"description": "PagerDuty integration for Hubot",
"version": "4.0.4",
"version": "4.1.0",
"author": "Josh Nichols <[email protected]>",
"license": "MIT",
"keywords": [
Expand Down
224 changes: 126 additions & 98 deletions src/scripts/pagerduty.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
// Commands:
// hubot pager me as <email> - remember your pager email is <email>
// 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 <schedule> - return the username of who's on call for any schedule matching <search>
// hubot pager trigger <user> <msg> - create a new incident with <msg> and assign it to <user>
// hubot pager default trigger <msg> - create a new incident with <msg> and assign it the user currently on call for our default schedule
// hubot pager trigger <schedule> <msg> - create a new incident with <msg> and assign it the user currently on call for <schedule>
// hubot pager incidents - return the current incidents
// hubot pager sup - return the current incidents
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 [email protected]\` 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);
}
);

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 [email protected]\` 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 ||
Expand Down
6 changes: 5 additions & 1 deletion test/pager-me-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
});
Expand Down

0 comments on commit 399082e

Please sign in to comment.