hubot-github-event-announcer
Version:
Announces GitHub webhook events
157 lines (129 loc) • 5.21 kB
text/coffeescript
util = require 'util'
# The list of all GitHub events.
#
# See: https://developer.github.com/v3/activity/events/types/
ALL_EVENTS = ['*']
# Public: Manages GitHub event hooks.
class HookManager
# Public: Constructs a new `HookManager`.
#
# * `robot` Robot used to interact with the outside world.
# * `message` Message to use to reply back to the user.
constructor: (@robot, @message) ->
# Public: Adds a hook to the repository at the given GitHub `user` and `repo`.
#
# * `user` {String} containing the GitHub user name.
# * `repo` {String} containing the GitHub repository name.
# * `options` {Object} containing the following options:
# * `room` Room name {String} to send events to for this hook.
addHook: (user, repo, options = {}) ->
try
url = @buildHookUrl(user, repo, options)
data =
name: 'web'
active: true
config:
content_type: 'json'
secret: process.env.HUBOT_GITHUB_EVENT_SECRET
url: url
events: ALL_EVENTS
@buildClient(user, repo)
.post(JSON.stringify(data)) (error, response, body) =>
throw error if error
throw response unless @isSuccessful(response)
@robot.logger.info util.inspect(body)
@message.reply 'I was able to successfully add the GitHub events hook'
catch e
@handleError(e, "adding the GitHub event hook to #{user}/#{repo}")
# Public: List the web hooks installed on the GitHub repository identified by the `user` and
# `repo` names.
#
# * `user` {String} containing the GitHub user name.
# * `repo` {String} containing the GitHub repository name.
listHooks: (user, repo) ->
try
@buildClient(user, repo)
.get() (error, response, body) =>
throw error if error
throw response unless @isSuccessful(response)
@robot.logger.info util.inspect(body)
hooks = JSON.parse(body)
@message.reply "#{user}/#{repo} has the following hooks:\n\n#{@formatHooksList(hooks)}"
catch e
@handleError(e, "listing the GitHub event hooks on #{user}/#{repo}")
# Private: Builds the URL to use for querying the web hook API.
#
# * `user` {String} containing the GitHub user name.
# * `repo` {String} containing the GitHub repository name.
#
# Returns a {String} containing the API URL.
buildApiUrl: (user, repo) ->
"https://api.github.com/repos/#{user}/#{repo}/hooks"
# Private: Builds the client object to use to perform API requests.
#
# * `user` {String} containing the GitHub user name.
# * `repo` {String} containing the GitHub repository name.
#
# Returns an HTTP client {Object}.
buildClient: (user, repo) ->
token = @getToken()
@robot.http(@buildApiUrl(user, repo))
.header('Accept', 'application/json')
.header('Authorization', "token #{token}")
.header('User-Agent', 'lee-dohm')
# Private: Builds the URL to use for receiving the web hooks.
#
# * `user` {String} containing the GitHub user name.
# * `repo` {String} containing the GitHub repository name.
# * `options` {Object} containing the following options:
# * `room` Room name {String} to send events to for this hook.
#
# Returns a {String} containing the URL.
buildHookUrl: (user, repo, options = {}) ->
host = process.env.HEROKU_URL ? process.env.HUBOT_GITHUB_EVENT_BASE_URL
unless host
throw new Error('Neither HEROKU_URL nor HUBOT_GITHUB_EVENT_BASE_URL are set, cannot add hook')
url = "#{host}/hubot/github-events"
url += "?room=#{options.room}" if options.room
url
# Private: Gets the security token to use for authorization to access web hooks.
#
# Returns a {String} containing the token text.
getToken: ->
token = process.env.HUBOT_GITHUB_EVENT_HOOK_TOKEN
throw new Error('HUBOT_GITHUB_EVENT_HOOK_TOKEN is not set, cannot add hook') unless token
token
# Private: Formats the list of hooks for display.
#
# * `hooks` {Array} of hooks for the repository.
#
# Returns a {String} containing the list of hooks for display.
formatHooksList: (hooks) ->
output = []
for hook in hooks
switch hook.name
when 'web' then output.push "#{hook.id}: #{hook.name} -- #{hook.config.url}"
else output.push "#{hook.id}: #{hook.name}"
output.join("\n")
# Private: Handles the error by reporting it with the given message.
#
# * `error` {Object} describing the error.
# * `message` {String} describing what was being done when the error occurred.
handleError: (error, message) ->
@robot.logger.error util.inspect(error)
if error.statusCode
@message.reply "Server returned: #{error.statusCode} #{error.statusMessage}"
else
@message.reply """
I encountered an error while #{message}
#{error.message}
#{error.stack}
"""
# Private: Determine if the HTTP response indicates the request was successful.
#
# * `response` {Object} containing the HTTP response.
#
# Returns a {Boolean} flag indicating whether the request was successful.
isSuccessful: (response) ->
200 <= response.statusCode < 300
module.exports = HookManager