From 4a33f7aca6f8ae80c76657ce64cd0eba4e0526ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kor=C3=A1l?= Date: Mon, 21 Dec 2015 18:36:37 +0100 Subject: [PATCH 01/17] implement: who's next oncall AND/OR who was oncall --- src/scripts/pagerduty.coffee | 126 +++++++++++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 5 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index bf5f206e..509df695 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -599,17 +599,29 @@ module.exports = (robot) -> else msg.send 'No schedules found!' + + # who was on call? + robot.respond /who was (on call|oncall)/i, (msg) -> + withTimeBasedOncall -72, msg, (usernames) -> + msg.send "*Previous shift*: #{usernames[0]} were on call.\n_Current shift: #{usernames[1]} are on call now._" + + # who is next on call? + robot.respond /who(?:’s|'s|s| is|se)? ((next (on call|oncall))|((on call|oncall) next))/i, (msg) -> + withTimeBasedOncall 72, msg, (usernames) -> + msg.send "*Upcoming shift*: #{usernames[1]} are next on call.\n_Current shift: #{usernames[0]} are on call now._" + + # who is on call? robot.respond /who(?:’s|'s|s| is|se)? (?:on call|oncall|on-call)(?:\?)?(?: (?:for )?((["'])([^]*?)\2|(.*?))(?:\?|$))?$/i, (msg) -> if pagerduty.missingEnvironmentForApi(msg) return + messages = [] + scheduleName = msg.match[3] or msg.match[4] - messages = [] - allowed_schedules = [] - if pagerDutySchedules? - allowed_schedules = pagerDutySchedules.split(",") + if scheduleName?.trim() is 'next' + return renderSchedule = (s, cb) -> withCurrentOncall msg, s, (username, schedule) -> @@ -618,7 +630,7 @@ module.exports = (robot) -> robot.logger.debug "Schedule #{schedule.id} (#{schedule.name}) not in HUBOT_PAGERDUTY_SCHEDULES" return cb null - # Ignore schedule if no user assigned to it + # Ignore schedule if no user assigned to it if (username) messages.push("* #{username} is on call for #{schedule.name} - #{schedule.html_url}") else @@ -732,6 +744,110 @@ module.exports = (robot) -> else cb() + withCurrentOncall = (msg, schedule, cb) -> + withCurrentOncallUser 1, msg, schedule, (user, s) -> + if (user) + cb(user.name, s) + else + cb(null, s) + + withCurrentOncallId = (msg, schedule, cb) -> + withCurrentOncallUser 1, msg, schedule, (user, s) -> + cb(user.id, user.name, s) + + withCurrentOncallUser = (addedHours = 1, msg, schedule, cb) -> + if typeof schedule is 'function' + cb = schedule + schedule = msg + msg = addedHours + addedHours = 1 + + if addedHours > 0 + timeSince = moment().format() + timeUntil = moment().add(addedHours, 'hours').format() + else + timeSince = moment().subtract(-addedHours, 'hours').format() + timeUntil = moment().format() + + scheduleId = schedule.id + if (schedule instanceof Array && schedule[0]) + scheduleId = schedule[0].id + unless scheduleId + msg.send "Unable to retrieve the schedule. Use 'pager schedules' to list all schedules." + return + + query = { + since: timeSince + until: timeUntil + overflow: 'true' + } + + pagerduty.get "/schedules/#{scheduleId}/users", query, (err, json) -> + if err? + robot.emit 'error', err, msg + return + if json.entries and json.entries.length > 0 + if addedHours isnt 1 # custom hours [who (next|was) oncall] + if addedHours > 0 + users = [ + json.entries[0].user + json.entries[1].user + ] + else if addedHours < 0 + last = json.entries.pop() + prev = json.entries.pop() or last + users = [ + prev.user + last.user + ] + return cb(users, schedule) + cb(json.entries[0].user, schedule) + + + withTimeBasedOncall = (addedHours = 1, msg, cb) -> + renderSchedule = (s, cb) -> + withCurrentOncallUser addedHours, msg, s, (users, schedule = {}) -> + cb(null, + users.map((user) -> + "#{schedule.name} - #{user.name}" + ) + ) + + pagerduty.getSchedules (err, schedules = []) -> + if err? + robot.emit 'error', err, msg + return + + schedules = schedules.filter((schedule) -> + !!schedule.name.match(/^(user support on\-call|1st level platform on\-call|2nd level platform on\-call)/i) + ) + + if schedules.length > 0 + async.map schedules, renderSchedule, (err, results = []) -> + if err? + robot.emit 'error', err, msg + return + rows = [] + + # Mix these arrays: + # ['platform userA', 'platform userX'] + # ['user-support userC', 'user-support userT'] + # into: + # [ + # 'platform userA and user-support userC' + # 'platform userX and user-support userT' + # ] + + for userIndex in [0..(results[0]?.length - 1)] by 1 + messageRow = [] + for historyIndex in [0..(results.length - 1)] by 1 + messageRow.push(results[historyIndex][userIndex]) + rows.push(messageRow.join(' and ')) + cb(rows) + else + msg.send 'No schedules found!' + + pagerDutyIntegrationAPI = (msg, cmd, description, cb) -> unless pagerDutyServiceApiKey? msg.send "PagerDuty API service key is missing." From c8bdc9d87e0dcfe04ca94dbcb74d9db17bdfeda7 Mon Sep 17 00:00:00 2001 From: nadade Date: Wed, 30 Dec 2015 12:07:18 +0100 Subject: [PATCH 02/17] whos oncall working even if a schedule has no entries --- src/scripts/pagerduty.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 509df695..2d9e3270 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -746,10 +746,7 @@ module.exports = (robot) -> withCurrentOncall = (msg, schedule, cb) -> withCurrentOncallUser 1, msg, schedule, (user, s) -> - if (user) - cb(user.name, s) - else - cb(null, s) + cb(user?.name or 'Nobody', s) withCurrentOncallId = (msg, schedule, cb) -> withCurrentOncallUser 1, msg, schedule, (user, s) -> @@ -802,6 +799,8 @@ module.exports = (robot) -> ] return cb(users, schedule) cb(json.entries[0].user, schedule) + else + cb(null, schedule) withTimeBasedOncall = (addedHours = 1, msg, cb) -> From 996c84aaa69d3c716dab0be6e14e002b689900ae Mon Sep 17 00:00:00 2001 From: nadade Date: Tue, 26 Jan 2016 13:57:47 +0100 Subject: [PATCH 03/17] who ('s/next/was) oncall - consistent formatting; fixed output after schedule rename --- src/scripts/pagerduty.coffee | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 2d9e3270..2dfe6917 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -603,12 +603,12 @@ module.exports = (robot) -> # who was on call? robot.respond /who was (on call|oncall)/i, (msg) -> withTimeBasedOncall -72, msg, (usernames) -> - msg.send "*Previous shift*: #{usernames[0]} were on call.\n_Current shift: #{usernames[1]} are on call now._" + msg.send "> *Previous shift*:\n> #{usernames[0].join("\n> ")}" # who is next on call? robot.respond /who(?:’s|'s|s| is|se)? ((next (on call|oncall))|((on call|oncall) next))/i, (msg) -> withTimeBasedOncall 72, msg, (usernames) -> - msg.send "*Upcoming shift*: #{usernames[1]} are next on call.\n_Current shift: #{usernames[0]} are on call now._" + msg.send "> *Upcoming shift*: \n> #{usernames[1].join("\n> ")}" # who is on call? @@ -632,7 +632,7 @@ module.exports = (robot) -> # Ignore schedule if no user assigned to it if (username) - messages.push("* #{username} is on call for #{schedule.name} - #{schedule.html_url}") + messages.push("> #{schedule.name} - *#{username}*") else robot.logger.debug "No user for schedule #{schedule.name}" @@ -786,9 +786,11 @@ module.exports = (robot) -> if json.entries and json.entries.length > 0 if addedHours isnt 1 # custom hours [who (next|was) oncall] if addedHours > 0 + first = json.entries[0] + next = json.entries[1] or first users = [ - json.entries[0].user - json.entries[1].user + first.user + next.user ] else if addedHours < 0 last = json.entries.pop() @@ -808,7 +810,7 @@ module.exports = (robot) -> withCurrentOncallUser addedHours, msg, s, (users, schedule = {}) -> cb(null, users.map((user) -> - "#{schedule.name} - #{user.name}" + "#{schedule.name} - *#{user.name}*" ) ) @@ -817,10 +819,6 @@ module.exports = (robot) -> robot.emit 'error', err, msg return - schedules = schedules.filter((schedule) -> - !!schedule.name.match(/^(user support on\-call|1st level platform on\-call|2nd level platform on\-call)/i) - ) - if schedules.length > 0 async.map schedules, renderSchedule, (err, results = []) -> if err? @@ -841,7 +839,7 @@ module.exports = (robot) -> messageRow = [] for historyIndex in [0..(results.length - 1)] by 1 messageRow.push(results[historyIndex][userIndex]) - rows.push(messageRow.join(' and ')) + rows.push(messageRow) cb(rows) else msg.send 'No schedules found!' From 3bbef03eba270cd7186ed502609be6132ad02a1b Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Wed, 25 Jul 2018 14:48:08 +0200 Subject: [PATCH 04/17] Added Team filtering by team_ids for /incidents endpoint --- README.md | 2 +- src/pagerduty.coffee | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 75b9594d..83836eee 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Then add **hubot-pager-me** to your `external-scripts.json`: | `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_TEAMS` | No | Provide a comma separated list of teams identifiers (e.g. `PFGPBFY,AFBCGH`) to restrict queries to only those teams. You need teams function on | `*` - May be required for certain actions. diff --git a/src/pagerduty.coffee b/src/pagerduty.coffee index ae031b72..bd39c3bb 100644 --- a/src/pagerduty.coffee +++ b/src/pagerduty.coffee @@ -4,6 +4,7 @@ pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_API_KEY pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN pagerDutyBaseUrl = 'https://api.pagerduty.com' pagerDutyServices = process.env.HUBOT_PAGERDUTY_SERVICES +pagerDutyTeams = process.env.HUBOT_PAGERDUTY_TEAMS pagerDutyFromEmail = process.env.HUBOT_PAGERDUTY_FROM_EMAIL pagerNoop = process.env.HUBOT_PAGERDUTY_NOOP pagerNoop = false if pagerNoop is 'false' or pagerNoop is 'off' @@ -33,8 +34,11 @@ module.exports = cb = query query = {} + if pagerDutyTeams? && url.match /\/incidents/ + query['teams_ids[]'] = pagerDutyTeams.split(',') + if pagerDutyServices? && url.match /\/incidents/ - query['service_id'] = pagerDutyServices + query['service_ids[]'] = pagerDutyServices.split(',') @http(url) .query(query) From 74ba0f5d6377b0ebebb6b4049506b090f45ec913 Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Wed, 25 Jul 2018 15:10:54 +0200 Subject: [PATCH 05/17] feat: switch from /schedules to /oncalls --- README.md | 1 + src/pagerduty.coffee | 17 +++++++++++++++++ src/scripts/pagerduty.coffee | 34 +++++++++++++--------------------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 83836eee..552223f8 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Then add **hubot-pager-me** to your `external-scripts.json`: | `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_TEAMS` | No | Provide a comma separated list of teams identifiers (e.g. `PFGPBFY,AFBCGH`) to restrict queries to only those teams. You need teams function on | +| `HUBOT_PAGERDUTY_SCHEDULES` | No | Provide a comma separated list of schedules identifiers (e.g. `PFGPBFY,AFBCGH`) to restrict queries to only those schedules. | `*` - May be required for certain actions. diff --git a/src/pagerduty.coffee b/src/pagerduty.coffee index bd39c3bb..4d1cf6fe 100644 --- a/src/pagerduty.coffee +++ b/src/pagerduty.coffee @@ -5,6 +5,7 @@ pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN pagerDutyBaseUrl = 'https://api.pagerduty.com' pagerDutyServices = process.env.HUBOT_PAGERDUTY_SERVICES pagerDutyTeams = process.env.HUBOT_PAGERDUTY_TEAMS +pagerDutySchedules = process.env.HUBOT_PAGERDUTY_SCHEDULES pagerDutyFromEmail = process.env.HUBOT_PAGERDUTY_FROM_EMAIL pagerNoop = process.env.HUBOT_PAGERDUTY_NOOP pagerNoop = false if pagerNoop is 'false' or pagerNoop is 'off' @@ -138,6 +139,22 @@ module.exports = return cb(null, json.incidents) + getOncalls: (query, cb) -> + if typeof(query) is 'function' + cb = query + query = {} + + if pagerDutySchedules? + query['schedule_ids[]'] = pagerDutySchedules.split(',') + + + @get "/oncalls", query, (err, json) -> + if err? + cb(err) + return + + cb(null, json.oncalls) + getSchedules: (query, cb) -> if typeof(query) is 'function' cb = query diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 2dfe6917..fe475a69 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -618,47 +618,39 @@ module.exports = (robot) -> messages = [] - scheduleName = msg.match[3] or msg.match[4] + oncallName = msg.match[3] or msg.match[4] - if scheduleName?.trim() is 'next' + if oncallName?.trim() is 'next' return - renderSchedule = (s, cb) -> - withCurrentOncall msg, s, (username, schedule) -> - # If there is an allowed schedules array, skip returned schedule not in it - if allowed_schedules.length and schedule.id not in allowed_schedules - robot.logger.debug "Schedule #{schedule.id} (#{schedule.name}) not in HUBOT_PAGERDUTY_SCHEDULES" - return cb null - - # Ignore schedule if no user assigned to it + renderOncall = (s, cb) -> + withCurrentOncall msg, s, (username, oncall) -> if (username) - messages.push("> #{schedule.name} - *#{username}*") + messages.push("> #{oncall.name} - *#{username}*") else - robot.logger.debug "No user for schedule #{schedule.name}" - - # Return callback + robot.logger.debug "No user for oncall #{oncall.name}" cb null - if scheduleName? - SchedulesMatching msg, scheduleName, (s) -> - async.map s, renderSchedule, (err) -> + if oncallName? + withScheduleMatching msg, oncallName, (s) -> + renderOncall s, (err) -> if err? robot.emit 'error', err, msg return msg.send messages.join("\n") else - pagerduty.getSchedules (err, schedules) -> + pagerduty.getOncalls (err, oncalls) -> if err? robot.emit 'error', err, msg return - if schedules.length > 0 - async.map schedules, renderSchedule, (err) -> + if oncalls.length > 0 + async.map oncalls, renderOncall, (err) -> if err? robot.emit 'error', err, msg return msg.send messages.join("\n") else - msg.send 'No schedules found!' + msg.send 'No oncall found!' robot.respond /(pager|major)( me)? services$/i, (msg) -> if pagerduty.missingEnvironmentForApi(msg) From a5b975dd9904bc44cded301cc450967a20dd67a9 Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Wed, 25 Jul 2018 15:20:10 +0200 Subject: [PATCH 06/17] fix: add oncallmatching --- src/scripts/pagerduty.coffee | 85 +++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index fe475a69..7ee11c2e 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -632,7 +632,7 @@ module.exports = (robot) -> cb null if oncallName? - withScheduleMatching msg, oncallName, (s) -> + withOncallMatching msg, oncallName, (s) -> renderOncall s, (err) -> if err? robot.emit 'error', err, msg @@ -705,6 +705,89 @@ module.exports = (robot) -> match.split(/[ ,]+/).map (incidentNumber) -> parseInt(incidentNumber) + userEmail = (user) -> + user.pagerdutyEmail || user.email_address || user.profile?.email || process.env.HUBOT_PAGERDUTY_TEST_EMAIL + + campfireUserToPagerDutyUser = (msg, user, required, cb) -> + if typeof required is 'function' + cb = required + required = true + + ## Determine the email based on the adapter type (v4.0.0+ of the Slack adapter stores it in `profile.email`) + email = userEmail(user) + speakerEmail = userEmail(msg.message.user) + + if not email + if not required + cb null + return + else + possessive = if email is speakerEmail + "your" + else + "#{user.name}'s" + addressee = if email is speakerEmail + "you" + else + "#{user.name}" + + msg.send "Sorry, I can't figure out #{possessive} email address :( Can #{addressee} tell me with `#{robot.name} pager me as you@yourdomain.com`?" + return + + pagerduty.get "/users", {query: email}, (err, json) -> + if err? + robot.emit 'error', err, msg + return + + if json.users.length isnt 1 + if json.users.length is 0 and not required + cb null + return + else + msg.send "Sorry, I expected to get 1 user back for #{email}, but got #{json.users.length} :sweat:. If your PagerDuty email is not #{email} use `/pager me as #{email}`" + return + + cb(json.users[0]) + + SchedulesMatching = (msg, q, cb) -> + query = { + query: q + } + pagerduty.getSchedules query, (err, schedules) -> + if err? + robot.emit 'error', err, msg + return + + cb(schedules) + + + OncallsMatching = (msg, q, cb) -> + query = { + query: q + } + pagerduty.getOncalls query, (err, oncalls) -> + if err? + robot.emit 'error', err, msg + return + + cb(oncalls) + + withScheduleMatching = (msg, q, cb) -> + SchedulesMatching msg, q, (schedules) -> + if schedules?.length < 1 + msg.send "I couldn't find any schedules matching #{q}" + else + cb(schedule) for schedule in schedules + return + + withOncallMatching = (msg, q, cb) -> + OncallsMatching msg, q, (oncalls) -> + if oncalls?.length < 1 + msg.send "I couldn't find any oncalls matching #{q}" + else + cb(oncall) for oncall in oncalls + return + reassignmentParametersForUserOrScheduleOrEscalationPolicy = (msg, string, cb) -> if campfireUser = robot.brain.userForName(string) campfireUserToPagerDutyUser msg, campfireUser, (user) -> From f2f797e1fafa9739cbb1ef8be810898d54482628 Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Thu, 26 Jul 2018 16:56:27 +0200 Subject: [PATCH 07/17] fix: add lodash for filtering escalation level --- src/pagerduty.coffee | 15 ++++++++-- src/scripts/pagerduty.coffee | 58 ++++++++++++++---------------------- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/pagerduty.coffee b/src/pagerduty.coffee index 4d1cf6fe..bc7f291d 100644 --- a/src/pagerduty.coffee +++ b/src/pagerduty.coffee @@ -1,4 +1,5 @@ HttpClient = require 'scoped-http-client' +_ = require('lodash') pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_API_KEY pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN @@ -147,13 +148,23 @@ module.exports = if pagerDutySchedules? query['schedule_ids[]'] = pagerDutySchedules.split(',') + if pagerDutyEscalationsPolicies? + query['escalation_policy_ids[]'] = pagerDutyEscalationsPolicies.split(',') + + console.error query @get "/oncalls", query, (err, json) -> if err? cb(err) return - - cb(null, json.oncalls) + console.error json.oncalls.length + # escalation_level filtering + oncalls = _.map json.oncalls, (o) -> + if o.escalation_level is 1 then return o + + filterdOncalls = _.without(oncalls, undefined) + console.error filterdOncalls.length + cb(null, filterdOncalls) getSchedules: (query, cb) -> if typeof(query) is 'function' diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 7ee11c2e..9211126c 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -41,6 +41,7 @@ pagerduty = require('../pagerduty') async = require('async') inspect = require('util').inspect moment = require('moment-timezone') +_ = require('lodash') pagerDutyUserId = process.env.HUBOT_PAGERDUTY_USER_ID pagerDutyServiceApiKey = process.env.HUBOT_PAGERDUTY_SERVICE_API_KEY @@ -623,34 +624,31 @@ module.exports = (robot) -> if oncallName?.trim() is 'next' return - renderOncall = (s, cb) -> - withCurrentOncall msg, s, (username, oncall) -> - if (username) - messages.push("> #{oncall.name} - *#{username}*") - else - robot.logger.debug "No user for oncall #{oncall.name}" - cb null + renderOncall = (oncall, cb) -> + if (oncall.user.summary) + messages.push("> #{oncall.schedule.summary} - *#{oncall.user.summary}*") + else + robot.logger.debug "No user for oncall #{oncall.schedule.summary}" + cb null + + query = { + since: moment().format(), + until: moment().add(1, 'minute').format(), + earliest: true + } - if oncallName? - withOncallMatching msg, oncallName, (s) -> - renderOncall s, (err) -> + pagerduty.getOncalls query, (err, oncalls) -> + if err? + robot.emit 'error', err, msg + return + if oncalls.length > 0 + async.map oncalls, renderOncall, (err) -> if err? robot.emit 'error', err, msg return - msg.send messages.join("\n") - else - pagerduty.getOncalls (err, oncalls) -> - if err? - robot.emit 'error', err, msg - return - if oncalls.length > 0 - async.map oncalls, renderOncall, (err) -> - if err? - robot.emit 'error', err, msg - return - msg.send messages.join("\n") - else - msg.send 'No oncall found!' + msg.send _.uniq(messages).sort().join("\n") + else + msg.send 'No oncall found!' robot.respond /(pager|major)( me)? services$/i, (msg) -> if pagerduty.missingEnvironmentForApi(msg) @@ -760,18 +758,6 @@ module.exports = (robot) -> cb(schedules) - - OncallsMatching = (msg, q, cb) -> - query = { - query: q - } - pagerduty.getOncalls query, (err, oncalls) -> - if err? - robot.emit 'error', err, msg - return - - cb(oncalls) - withScheduleMatching = (msg, q, cb) -> SchedulesMatching msg, q, (schedules) -> if schedules?.length < 1 From b0dea8ac72a72784ead0453b1f5c943f2a45dc74 Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Thu, 2 Aug 2018 16:42:08 +0200 Subject: [PATCH 08/17] refactor: who was/is oncall (next)? --- src/pagerduty.coffee | 14 ++++-- src/scripts/pagerduty.coffee | 98 +++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 44 deletions(-) diff --git a/src/pagerduty.coffee b/src/pagerduty.coffee index bc7f291d..7e9ad316 100644 --- a/src/pagerduty.coffee +++ b/src/pagerduty.coffee @@ -157,14 +157,20 @@ module.exports = if err? cb(err) return - console.error json.oncalls.length # escalation_level filtering oncalls = _.map json.oncalls, (o) -> if o.escalation_level is 1 then return o - filterdOncalls = _.without(oncalls, undefined) - console.error filterdOncalls.length - cb(null, filterdOncalls) + + oncallsBySchedules = _.transform(filterdOncalls, (result, value, key) -> + message = "#{value.user.summary} - #{value.start} - #{value.end}" + unless result[value.schedule.summary] + (result[value.schedule.summary] || (result[value.schedule.summary] = [])).push(message); + if result[value.schedule.summary].indexOf(message) == -1 + (result[value.schedule.summary] || (result[value.schedule.summary] = [])).push(message); + , {}) + + cb(null, oncallsBySchedules) getSchedules: (query, cb) -> if typeof(query) is 'function' diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 9211126c..f2374741 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -603,52 +603,15 @@ module.exports = (robot) -> # who was on call? robot.respond /who was (on call|oncall)/i, (msg) -> - withTimeBasedOncall -72, msg, (usernames) -> - msg.send "> *Previous shift*:\n> #{usernames[0].join("\n> ")}" + getOncalls msg, -72 # who is next on call? robot.respond /who(?:’s|'s|s| is|se)? ((next (on call|oncall))|((on call|oncall) next))/i, (msg) -> - withTimeBasedOncall 72, msg, (usernames) -> - msg.send "> *Upcoming shift*: \n> #{usernames[1].join("\n> ")}" - + getOncalls msg, 72 # who is on call? robot.respond /who(?:’s|'s|s| is|se)? (?:on call|oncall|on-call)(?:\?)?(?: (?:for )?((["'])([^]*?)\2|(.*?))(?:\?|$))?$/i, (msg) -> - if pagerduty.missingEnvironmentForApi(msg) - return - - messages = [] - - oncallName = msg.match[3] or msg.match[4] - - if oncallName?.trim() is 'next' - return - - renderOncall = (oncall, cb) -> - if (oncall.user.summary) - messages.push("> #{oncall.schedule.summary} - *#{oncall.user.summary}*") - else - robot.logger.debug "No user for oncall #{oncall.schedule.summary}" - cb null - - query = { - since: moment().format(), - until: moment().add(1, 'minute').format(), - earliest: true - } - - pagerduty.getOncalls query, (err, oncalls) -> - if err? - robot.emit 'error', err, msg - return - if oncalls.length > 0 - async.map oncalls, renderOncall, (err) -> - if err? - robot.emit 'error', err, msg - return - msg.send _.uniq(messages).sort().join("\n") - else - msg.send 'No oncall found!' + getOncalls msg robot.respond /(pager|major)( me)? services$/i, (msg) -> if pagerduty.missingEnvironmentForApi(msg) @@ -699,6 +662,61 @@ module.exports = (robot) -> else msg.send "That didn't work. Check Hubot's logs for an error!" + + getOncalls = (msg, hoursSpan) -> + if pagerduty.missingEnvironmentForApi(msg) + return + + messages = [] + + oncallName = msg.match[3] or msg.match[4] + + if oncallName?.trim() is 'next' + return + + query = { + since: moment().format(), + until: moment().add(1, 'minute').format(), + earliest: true + } + + if hoursSpan + if hoursSpan > 0 + query.since = moment().format() + query.until = moment().add(hoursSpan, 'hours').format() + else + query.since = moment().subtract(-hoursSpan, 'hours').format() + query.until = moment().format() + + pagerduty.getOncalls query, (err, oncalls) -> + if err? + robot.emit 'error', err, msg + return + if Object.keys(oncalls).length > 0 + filteredOncalls = oncalls + _.forEach filteredOncalls, (value, key) -> + if hoursSpan < 0 + values = value[value.length - 1] + else if hoursSpan > 0 + if value.length > 1 + values = value[1] + else + values = value[0] + else + values = value.join(", ") + + messages.push("> #{key} - *#{values}*") + msg.send _.uniq(messages).sort().join('\n') + else + msg.send 'No oncall found!' + + getFirstOncalls = (oncalls) -> + return oncalls + + getLatestOncalls = (oncalls) -> + return oncalls + + parseIncidentNumbers = (match) -> match.split(/[ ,]+/).map (incidentNumber) -> parseInt(incidentNumber) From 9cc717a5450a4162f4de4e816c88940d3d8de149 Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Fri, 3 Aug 2018 11:05:54 +0200 Subject: [PATCH 09/17] chore: adjust formating --- src/pagerduty.coffee | 4 +++- src/scripts/pagerduty.coffee | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pagerduty.coffee b/src/pagerduty.coffee index 7e9ad316..e8d7afa2 100644 --- a/src/pagerduty.coffee +++ b/src/pagerduty.coffee @@ -1,5 +1,7 @@ HttpClient = require 'scoped-http-client' _ = require('lodash') +moment = require('moment-timezone') +timezone = 'UTC' pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_API_KEY pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN @@ -163,7 +165,7 @@ module.exports = filterdOncalls = _.without(oncalls, undefined) oncallsBySchedules = _.transform(filterdOncalls, (result, value, key) -> - message = "#{value.user.summary} - #{value.start} - #{value.end}" + message = "(#{moment(value.start).tz(timezone).format('MMM Do, h:mm a')} - #{moment(value.end).tz(timezone).format('MMM Do, h:mm a')}) - *#{value.user.summary}*" unless result[value.schedule.summary] (result[value.schedule.summary] || (result[value.schedule.summary] = [])).push(message); if result[value.schedule.summary].indexOf(message) == -1 diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index f2374741..2347d200 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -705,7 +705,7 @@ module.exports = (robot) -> else values = value.join(", ") - messages.push("> #{key} - *#{values}*") + messages.push("> #{key} #{values}") msg.send _.uniq(messages).sort().join('\n') else msg.send 'No oncall found!' From 588547fc7dd8e50790bfc84816925e53518cf639 Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Fri, 3 Aug 2018 11:48:28 +0200 Subject: [PATCH 10/17] chore: add support for timezone --- src/pagerduty.coffee | 9 +++++---- src/scripts/pagerduty.coffee | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pagerduty.coffee b/src/pagerduty.coffee index e8d7afa2..6aa34bbd 100644 --- a/src/pagerduty.coffee +++ b/src/pagerduty.coffee @@ -1,7 +1,6 @@ HttpClient = require 'scoped-http-client' _ = require('lodash') moment = require('moment-timezone') -timezone = 'UTC' pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_API_KEY pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN @@ -142,7 +141,7 @@ module.exports = return cb(null, json.incidents) - getOncalls: (query, cb) -> + getOncalls: (query, tz, cb) -> if typeof(query) is 'function' cb = query query = {} @@ -163,9 +162,11 @@ module.exports = oncalls = _.map json.oncalls, (o) -> if o.escalation_level is 1 then return o filterdOncalls = _.without(oncalls, undefined) - + timezone = tz oncallsBySchedules = _.transform(filterdOncalls, (result, value, key) -> - message = "(#{moment(value.start).tz(timezone).format('MMM Do, h:mm a')} - #{moment(value.end).tz(timezone).format('MMM Do, h:mm a')}) - *#{value.user.summary}*" + message = "(#{moment(value.start).tz(timezone).format('MMM Do, h:mm a')} " + message += "- #{moment(value.end).tz(timezone).format('MMM Do, h:mm a')}) " + message += "- *#{value.user.summary}*" unless result[value.schedule.summary] (result[value.schedule.summary] || (result[value.schedule.summary] = [])).push(message); if result[value.schedule.summary].indexOf(message) == -1 diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 2347d200..8239b283 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -688,7 +688,7 @@ module.exports = (robot) -> query.since = moment().subtract(-hoursSpan, 'hours').format() query.until = moment().format() - pagerduty.getOncalls query, (err, oncalls) -> + pagerduty.getOncalls query, msg.message.user.slack.slack.tz or 'UTC', (err, oncalls) -> if err? robot.emit 'error', err, msg return From aa5cb941a4c71fb27f4d2816412b216a91084a01 Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Mon, 14 Sep 2020 09:31:36 +0200 Subject: [PATCH 11/17] fix: newer lodash --- package-lock.json | 19 ++++++++++++------- package.json | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8335e08c..21345fe8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2754,10 +2754,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", - "dev": true + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash.find": { "version": "4.6.0", @@ -3084,9 +3083,9 @@ } }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", "dev": true }, "normalize-path": { @@ -3859,6 +3858,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index 41c2dfdb..5a1e862a 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "async": "^3.2.0", + "lodash": "^4.17.20", "moment-timezone": "^0.5.31", "scoped-http-client": "^0.11.0" }, From c9d3ce9a711777e62006c3c254555fabd60c864e Mon Sep 17 00:00:00 2001 From: Ladislav Prskavec Date: Mon, 5 Oct 2020 17:48:32 +0200 Subject: [PATCH 12/17] Revert "chore: add support for timezone" This reverts commit 588547fc7dd8e50790bfc84816925e53518cf639. --- src/pagerduty.coffee | 9 ++++----- src/scripts/pagerduty.coffee | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pagerduty.coffee b/src/pagerduty.coffee index 6aa34bbd..e8d7afa2 100644 --- a/src/pagerduty.coffee +++ b/src/pagerduty.coffee @@ -1,6 +1,7 @@ HttpClient = require 'scoped-http-client' _ = require('lodash') moment = require('moment-timezone') +timezone = 'UTC' pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_API_KEY pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN @@ -141,7 +142,7 @@ module.exports = return cb(null, json.incidents) - getOncalls: (query, tz, cb) -> + getOncalls: (query, cb) -> if typeof(query) is 'function' cb = query query = {} @@ -162,11 +163,9 @@ module.exports = oncalls = _.map json.oncalls, (o) -> if o.escalation_level is 1 then return o filterdOncalls = _.without(oncalls, undefined) - timezone = tz + oncallsBySchedules = _.transform(filterdOncalls, (result, value, key) -> - message = "(#{moment(value.start).tz(timezone).format('MMM Do, h:mm a')} " - message += "- #{moment(value.end).tz(timezone).format('MMM Do, h:mm a')}) " - message += "- *#{value.user.summary}*" + message = "(#{moment(value.start).tz(timezone).format('MMM Do, h:mm a')} - #{moment(value.end).tz(timezone).format('MMM Do, h:mm a')}) - *#{value.user.summary}*" unless result[value.schedule.summary] (result[value.schedule.summary] || (result[value.schedule.summary] = [])).push(message); if result[value.schedule.summary].indexOf(message) == -1 diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 8239b283..2347d200 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -688,7 +688,7 @@ module.exports = (robot) -> query.since = moment().subtract(-hoursSpan, 'hours').format() query.until = moment().format() - pagerduty.getOncalls query, msg.message.user.slack.slack.tz or 'UTC', (err, oncalls) -> + pagerduty.getOncalls query, (err, oncalls) -> if err? robot.emit 'error', err, msg return From bd496ff0595419f692159abea3097687dcff47c2 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 26 Nov 2020 10:42:07 +0100 Subject: [PATCH 13/17] feat: add custom response with correct dates --- src/scripts/pagerduty-custom.coffee | 74 +++++++++++++++++++++++++++++ src/scripts/pagerduty.coffee | 11 +++-- 2 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 src/scripts/pagerduty-custom.coffee diff --git a/src/scripts/pagerduty-custom.coffee b/src/scripts/pagerduty-custom.coffee new file mode 100644 index 00000000..b616876b --- /dev/null +++ b/src/scripts/pagerduty-custom.coffee @@ -0,0 +1,74 @@ +pagerduty = require('../pagerduty') + +getCustomOncalls = (timeFrame, msg) -> + if not msg? + console.log('no msg sent') + return + + timeNow = Date.now() + past = new Date(timeNow - (72 * 3600000)).toISOString() + future = new Date(timeNow + (72 * 3600000)).toISOString() + plusMinute = new Date(timeNow + 60000).toISOString() + since = null + untilParam = null + + # , 'PGWSC3H', 'PGFERYM' + if timeFrame is 'now' + since = new Date(timeNow).toISOString() + untilParam = plusMinute + msg.send('it\'s now or never') + + if timeFrame is 'was' + since = past + untilParam = new Date(timeNow).toISOString() + msg.send('let the past rest in peace') + + if timeFrame is 'next' + since = new Date(timeNow).toISOString() + untilParam = future + msg.send('what\'s next?') + + query = { + limit: 50 + time_zone: 'UTC' + "schedule_ids[]": ['PDHLWLB' , 'PGWSC3H', 'PGFERYM'], + since: since + until: untilParam + } + + pagerduty.get('/oncalls', query, (err, json) -> + if err + msg.send(err) + + userSupports = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PDHLWLB') + escallations = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PGFERYM') + platformOncalls = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PGWSC3H') + + findOncall = (oncalls, timeFrame) -> + if timeFrame is 'was' + return oncalls.find((oncall) -> + Date.parse(oncall.start) < timeNow - (24 * 3600000) < Date.parse(oncall.end) + ) + if timeFrame is 'next' + return oncalls.find((oncall) -> + Date.parse(oncall.start) > timeNow + ) + return oncalls.find((oncall) -> + Date.parse(oncall.start) < timeNow < Date.parse(oncall.end) + ) + + formatTime = (date) -> + dateTime = new Date(date).toString() + return "#{dateTime.substring(0, 10)} #{dateTime.substring(16, 21)} pm" + + userSupport = findOncall(userSupports, timeFrame) + escallation = findOncall(escallations, timeFrame) + platformOncall = findOncall(platformOncalls, timeFrame) + + message = "#{userSupport.schedule.summary} - (#{formatTime(userSupport.start)} - #{formatTime(userSupport.end)}) - *#{userSupport.user.summary}*\n" + message += "#{platformOncall.schedule.summary} - #{formatTime(platformOncall.start)} - #{formatTime(platformOncall.end)} - *#{platformOncall.user.summary}*\n" + message += "#{escallation.schedule.summary} - #{formatTime(escallation.start)} - #{formatTime(escallation.end)} - *#{escallation.user.summary}*\n" + + msg.send(message) + ) +module.exports = getCustomOncalls \ No newline at end of file diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 8239b283..8077146e 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -42,6 +42,7 @@ async = require('async') inspect = require('util').inspect moment = require('moment-timezone') _ = require('lodash') +getCustomOncalls = require('./pagerduty-custom.coffee') pagerDutyUserId = process.env.HUBOT_PAGERDUTY_USER_ID pagerDutyServiceApiKey = process.env.HUBOT_PAGERDUTY_SERVICE_API_KEY @@ -602,16 +603,16 @@ module.exports = (robot) -> # who was on call? - robot.respond /who was (on call|oncall)/i, (msg) -> - getOncalls msg, -72 + robot.respond /who was (on call|oncall|on-call)/i, (msg) -> + getCustomOncalls 'was', msg # who is next on call? - robot.respond /who(?:’s|'s|s| is|se)? ((next (on call|oncall))|((on call|oncall) next))/i, (msg) -> - getOncalls msg, 72 + robot.respond /who(?:’s|'s|s| is|se)? ((next (on call|oncall|on-call))|((on call|oncall|on-call) next))/i, (msg) -> + getCustomOncalls 'next', msg # who is on call? robot.respond /who(?:’s|'s|s| is|se)? (?:on call|oncall|on-call)(?:\?)?(?: (?:for )?((["'])([^]*?)\2|(.*?))(?:\?|$))?$/i, (msg) -> - getOncalls msg + getCustomOncalls 'now', msg robot.respond /(pager|major)( me)? services$/i, (msg) -> if pagerduty.missingEnvironmentForApi(msg) From 907b499a14ca86a05dd38857a49d2951f875af68 Mon Sep 17 00:00:00 2001 From: Natalie Date: Wed, 2 Dec 2020 11:32:12 +0100 Subject: [PATCH 14/17] refactor: simplify for testing --- src/scripts/pagerduty-custom.coffee | 83 ++++++++++++++--------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/src/scripts/pagerduty-custom.coffee b/src/scripts/pagerduty-custom.coffee index b616876b..5f1dc15d 100644 --- a/src/scripts/pagerduty-custom.coffee +++ b/src/scripts/pagerduty-custom.coffee @@ -1,39 +1,52 @@ pagerduty = require('../pagerduty') -getCustomOncalls = (timeFrame, msg) -> - if not msg? - console.log('no msg sent') - return +# selects the right oncall based on current time +findOncall = (oncalls, timeFrame, timeNow) -> + if timeFrame is 'was' + return oncalls.find((oncall) -> + Date.parse(oncall.start) < timeNow - (24 * 3600000) < Date.parse(oncall.end) + ) + if timeFrame is 'next' + return oncalls.find((oncall) -> + Date.parse(oncall.start) > timeNow + ) + return oncalls.find((oncall) -> + Date.parse(oncall.start) < timeNow < Date.parse(oncall.end) + ) - timeNow = Date.now() +# formats time to show the name of the day, month, day and time +formatTime = (date) -> + dateTime = new Date(date).toString() + return "#{dateTime.substring(0, 10)} #{dateTime.substring(16, 21)}" + +# according to requesed time (on call, now, on call next, was on call) prepares time query +# pagerduty limits the amount of returned data, so more precise time settings +setTimeQuery = (timeFrame, timeNow) -> past = new Date(timeNow - (72 * 3600000)).toISOString() future = new Date(timeNow + (72 * 3600000)).toISOString() plusMinute = new Date(timeNow + 60000).toISOString() - since = null - untilParam = null - - # , 'PGWSC3H', 'PGFERYM' - if timeFrame is 'now' - since = new Date(timeNow).toISOString() - untilParam = plusMinute - msg.send('it\'s now or never') - + if timeFrame is 'was' - since = past - untilParam = new Date(timeNow).toISOString() - msg.send('let the past rest in peace') + return { since: past, untilParam: new Date(timeNow).toISOString() } if timeFrame is 'next' - since = new Date(timeNow).toISOString() - untilParam = future - msg.send('what\'s next?') + return { since: new Date(timeNow).toISOString(), untilParam: future } + return { since: new Date(timeNow).toISOString(), untilParam: plusMinute } + +getCustomOncalls = (timeFrame, msg) -> + if not msg? + console.log('no msg sent') + return + + timeNow = Date.now() + timeQuery = setTimeQuery(timeFrame, timeNow) query = { limit: 50 time_zone: 'UTC' "schedule_ids[]": ['PDHLWLB' , 'PGWSC3H', 'PGFERYM'], - since: since - until: untilParam + since: timeQuery.since + until: timeQuery.untilParam } pagerduty.get('/oncalls', query, (err, json) -> @@ -44,26 +57,9 @@ getCustomOncalls = (timeFrame, msg) -> escallations = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PGFERYM') platformOncalls = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PGWSC3H') - findOncall = (oncalls, timeFrame) -> - if timeFrame is 'was' - return oncalls.find((oncall) -> - Date.parse(oncall.start) < timeNow - (24 * 3600000) < Date.parse(oncall.end) - ) - if timeFrame is 'next' - return oncalls.find((oncall) -> - Date.parse(oncall.start) > timeNow - ) - return oncalls.find((oncall) -> - Date.parse(oncall.start) < timeNow < Date.parse(oncall.end) - ) - - formatTime = (date) -> - dateTime = new Date(date).toString() - return "#{dateTime.substring(0, 10)} #{dateTime.substring(16, 21)} pm" - - userSupport = findOncall(userSupports, timeFrame) - escallation = findOncall(escallations, timeFrame) - platformOncall = findOncall(platformOncalls, timeFrame) + userSupport = findOncall(userSupports, timeFrame, timeNow) + escallation = findOncall(escallations, timeFrame, timeNow) + platformOncall = findOncall(platformOncalls, timeFrame, timeNow) message = "#{userSupport.schedule.summary} - (#{formatTime(userSupport.start)} - #{formatTime(userSupport.end)}) - *#{userSupport.user.summary}*\n" message += "#{platformOncall.schedule.summary} - #{formatTime(platformOncall.start)} - #{formatTime(platformOncall.end)} - *#{platformOncall.user.summary}*\n" @@ -71,4 +67,5 @@ getCustomOncalls = (timeFrame, msg) -> msg.send(message) ) -module.exports = getCustomOncalls \ No newline at end of file +module.exports = getCustomOncalls +module.exports = { findOncall, formatTime, setTimeQuery } \ No newline at end of file From 36c3586e7d1aa4242ebda26304c37240466d95b3 Mon Sep 17 00:00:00 2001 From: Natalie Date: Wed, 2 Dec 2020 11:32:47 +0100 Subject: [PATCH 15/17] test: add unit tests --- test/pagerduty-custom-unit.coffee | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 test/pagerduty-custom-unit.coffee diff --git a/test/pagerduty-custom-unit.coffee b/test/pagerduty-custom-unit.coffee new file mode 100644 index 00000000..942a7985 --- /dev/null +++ b/test/pagerduty-custom-unit.coffee @@ -0,0 +1,36 @@ +# module.exports = { findOncall, formatTime } +chai = require 'chai' +formatTime = require('../src/scripts/pagerduty-custom.coffee').formatTime +findOncall = require('../src/scripts/pagerduty-custom.coffee').findOncall +setTimeQuery = require('../src/scripts/pagerduty-custom.coffee').setTimeQuery + +expect = chai.expect + +oncalls = [ + {name: 'yesterday', start: "2020-11-27T17:00:00.000Z", end: "2020-11-29T17:00:00.000Z"}, + {name: 'today',start: "2020-11-29T17:00:00.000Z", end: "2020-11-30T17:00:00.000Z"}, + {name: 'tomorrow',start: "2020-11-30T17:00:00.000Z", end: "2020-12-01T17:00:00.000Z"}, +] + +timeNow = Date.parse("2020-11-30T13:00:00.000Z") + +describe 'custom on call - findOncall', -> + it 'should return today for `now` timeFrame', -> + expect(findOncall(oncalls, 'now', timeNow).name).to.equal('today') + + it 'should return yesterday for `was` timeFrame', -> + expect(findOncall(oncalls, 'was', timeNow).name).to.equal('yesterday') + + it 'should return yesterday for `next` timeFrame', -> + expect(findOncall(oncalls, 'next', timeNow).name).to.equal('tomorrow') + +describe 'custom on call - formatTime', -> + it 'should format time correctly', -> + expect(formatTime(oncalls[1].start)).to.equal('Sun Nov 29 18:00') + expect(formatTime(oncalls[0].end)).to.equal('Sun Nov 29 18:00') + expect(formatTime(oncalls[2].end)).to.equal('Tue Dec 01 18:00') + +describe 'custom on call - setTimeQuery', -> + it 'should return time query according to requested time', -> + expect(setTimeQuery('now', timeNow).since).to.equal('2020-11-30T13:00:00.000Z') + expect(setTimeQuery('now', timeNow).untilParam).to.equal('2020-11-30T13:01:00.000Z') \ No newline at end of file From e252aa688fa0acd1b58fec21d2df75140b018da6 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 3 Dec 2020 23:56:57 +0100 Subject: [PATCH 16/17] refactor: use env variables --- src/scripts/pagerduty-custom.coffee | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/scripts/pagerduty-custom.coffee b/src/scripts/pagerduty-custom.coffee index 5f1dc15d..c1a9eeb0 100644 --- a/src/scripts/pagerduty-custom.coffee +++ b/src/scripts/pagerduty-custom.coffee @@ -1,4 +1,7 @@ pagerduty = require('../pagerduty') +userSupportId = process.env.HUBOT_PAGERDUTY_SCHEDULE_USERSUP_ID +platformId = process.env.HUBOT_PAGERDUTY_SCHEDULE_PLATFORM_ID +escalationId = process.env.HUBOT_PAGERDUTY_SCHEDULE_ESCALATION_ID # selects the right oncall based on current time findOncall = (oncalls, timeFrame, timeNow) -> @@ -44,7 +47,7 @@ getCustomOncalls = (timeFrame, msg) -> query = { limit: 50 time_zone: 'UTC' - "schedule_ids[]": ['PDHLWLB' , 'PGWSC3H', 'PGFERYM'], + "schedule_ids[]": [userSupportId, platformId, escalationId], since: timeQuery.since until: timeQuery.untilParam } @@ -53,9 +56,9 @@ getCustomOncalls = (timeFrame, msg) -> if err msg.send(err) - userSupports = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PDHLWLB') - escallations = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PGFERYM') - platformOncalls = json.oncalls.filter((oncall) -> oncall.schedule.id is 'PGWSC3H') + userSupports = json.oncalls.filter((oncall) -> oncall.schedule.id is userSupportId) + escallations = json.oncalls.filter((oncall) -> oncall.schedule.id is escalationId) + platformOncalls = json.oncalls.filter((oncall) -> oncall.schedule.id is platformId) userSupport = findOncall(userSupports, timeFrame, timeNow) escallation = findOncall(escallations, timeFrame, timeNow) From 5a7f6dea2e1392bbd1b72da90dfd0407e4813564 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 3 Dec 2020 23:57:42 +0100 Subject: [PATCH 17/17] fix: correct exporting --- src/scripts/pagerduty-custom.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/scripts/pagerduty-custom.coffee b/src/scripts/pagerduty-custom.coffee index c1a9eeb0..070b131c 100644 --- a/src/scripts/pagerduty-custom.coffee +++ b/src/scripts/pagerduty-custom.coffee @@ -70,5 +70,8 @@ getCustomOncalls = (timeFrame, msg) -> msg.send(message) ) -module.exports = getCustomOncalls -module.exports = { findOncall, formatTime, setTimeQuery } \ No newline at end of file +getCustomOncalls.findOncall = findOncall +getCustomOncalls.formatTime = formatTime +getCustomOncalls.setTimeQuery = setTimeQuery + +module.exports = getCustomOncalls \ No newline at end of file