lib/right_hook/subscriber.rb
require 'httparty'
require 'right_hook/event'
require 'right_hook/logger'
module RightHook
# Subscriber can subscribe and unsubscribe GitHub hooks to a hosted instance of a specified {RightHook::App}.
# See the README for sample usage.
class Subscriber
# The base URL for the binding (where your {RightHook::App} is hosted).
attr_accessor :base_url
#
# The full target URL for the binding when used with #subscribe_direct.
attr_accessor :url
# The OAuth token to use for authenticating with GitHub.
# The token must belong to an account that has the +repo+ scope and collaborator privilege on the given repository.
attr_accessor :oauth_token
# The owner of the named repository.
attr_accessor :owner
# The event type of the hook.
# See http://developer.github.com/v3/repos/hooks/ for a complete list of valid types.
attr_accessor :event_type
# The user agent value to send on the request to github
# See: http://developer.github.com/v3/#user-agent-required
attr_accessor :user_agent
# Initialize takes options which will be used as default values in other methods.
# The valid keys in the options are [+base_url+, +oauth_token+, +owner+, +event_type+, and +user_agent+].
# @param [Hash] opts Subscription options. Defaults to attr_reader methods when such methods exist.
# @option opts [String] :owner The owner of the repository
# @option opts [String] :event_type A constant under RightHook::Event representing an event type
# @option opts [String] :base_url The URL of where the {RightHook::App} is hosted
# @option opts [String] :url The URL to receive requests from GitHub when a hook is activated
# @option opts [String] :oauth_token The OAuth token to use to authenticate with GitHub when subscribing
# @option opts [String] :user_agent The value to send for the User-Agent header when talking with GitHub
def initialize(default_opts = {})
@base_url = default_opts[:base_url]
@url = default_opts[:url]
@oauth_token = default_opts[:oauth_token]
@owner = default_opts[:owner]
@event_type = default_opts[:event_type]
@user_agent = default_opts[:user_agent]
end
# Subscribe an instance of {RightHook::App} hosted at +base_url+ to a hook for +owner+/+repo_name+, authenticating with +oauth_token+.
# +repo_name+ and +secret+ are required options and they are intentionally not stored as defaults on the +Subscriber+ instance.
# @param [Hash] opts Subscription options. Defaults to attr_reader methods when such methods exist.
# @return [bool success] Whether the request was successful.
# @option opts [String] :owner The owner of the repository
# @option opts [String] :repo_name The name of the repository
# @option opts [String] :event_type A constant under RightHook::Event representing an event type
# @option opts [String] :base_url The URL of where the {RightHook::App} is hosted
# @option opts [String] :secret The secret to use to validate that a request came from GitHub. May be omitted
# @option opts [String] :oauth_token The OAuth token to use to authenticate with GitHub when subscribing
# @option opts [String] :user_agent The value to send for the User-Agent header when talking with GitHub
def subscribe(opts)
hub_request_with_mode('subscribe', opts)
end
# Unsubscribe an instance of {RightHook::App} hosted at +base_url+ to a hook for +owner+/+repo_name+, authenticating with +oauth_token+.
# +repo_name+ and +secret+ are required options and they are intentionally not stored as defaults on the +Subscriber+ instance.
# (NB: It's possible that GitHub's API *doesn't* require secret; I haven't checked.)
# @param [Hash] opts Subscription options. Defaults to attr_reader methods when such methods exist.
# @return [bool success] Whether the request was successful.
# @option opts [String] :owner The owner of the repository
# @option opts [String] :repo_name The name of the repository
# @option opts [String] :event_type A constant under RightHook::Event representing an event type
# @option opts [String] :base_url The URL of where the {RightHook::App} is hosted
# @option opts [String] :secret The secret to use to validate that a request came from GitHub. May be omitted
# @option opts [String] :oauth_token The OAuth token to use to authenticate with GitHub when subscribing
# @option opts [String] :user_agent The value to send for the User-Agent header when talking with GitHub
def unsubscribe(opts)
hub_request_with_mode('unsubscribe', opts)
end
# Subscribe directly to a fixed URL, rather than a calculated URL for an instance of {RightHook::App}.
# @return [bool success] Whether the request was successful.
# @param [Hash] opts Subscription options. Defaults to attr_reader methods when such methods exist.
# @option opts [String] :owner The owner of the repository
# @option opts [String] :repo_name The name of the repository
# @option opts [String] :event_type A constant under RightHook::Event representing an event type
# @option opts [String] :url The URL to receive requests from GitHub when a hook is activated
# @option opts [String] :secret The secret to use to validate that a request came from GitHub. May be omitted
# @option opts [String] :oauth_token The OAuth token to use to authenticate with GitHub when subscribing
# @option opts [String] :user_agent The value to send for the User-Agent header when talking with GitHub
def subscribe_direct(opts)
direct_hub_request_with_mode('subscribe', opts)
end
# Unsubscribe directly to a fixed URL, rather than a calculated URL for an instance of {RightHook::App}.
# @return [bool success] Whether the request was successful.
# @param [Hash] opts Subscription options. Defaults to attr_reader methods when such methods exist.
# @option opts [String] :owner The owner of the repository
# @option opts [String] :repo_name The name of the repository
# @option opts [String] :event_type A constant under RightHook::Event representing an event type
# @option opts [String] :url The URL to receive requests from GitHub when a hook is activated
# @option opts [String] :secret The secret to use to validate that a request came from GitHub. May be omitted
# @option opts [String] :oauth_token The OAuth token to use to authenticate with GitHub when subscribing
# @option opts [String] :user_agent The value to send for the User-Agent header when talking with GitHub
def unsubscribe_direct(opts)
direct_hub_request_with_mode('unsubscribe', opts)
end
private
def hub_request_with_mode(mode, opts)
repo_name = opts.fetch(:repo_name) # explicitly not defaulted
owner = opts.fetch(:owner) { self.owner }
base_url = opts.fetch(:base_url) { self.base_url }
event_type = opts.fetch(:event_type) { self.event_type }
url = "#{base_url}/hook/#{owner}/#{repo_name}/#{event_type}"
direct_hub_request_with_mode(mode, opts.merge(url: url))
end
def direct_hub_request_with_mode(mode, opts)
repo_name = opts.fetch(:repo_name) # explicitly not defaulted
url = opts.fetch(:url) # explicitly not defaulted
secret = opts.fetch(:secret, nil)
owner = opts.fetch(:owner) { self.owner }
oauth_token = opts.fetch(:oauth_token) { self.oauth_token }
event_type = opts.fetch(:event_type) { self.event_type }
user_agent = opts.fetch(:user_agent) { self.user_agent }
response = HTTParty.post('https://api.github.com/hub',
headers: {
# http://developer.github.com/v3/#authentication
'Authorization' => "token #{oauth_token}",
'User-Agent' => user_agent.to_s
},
body: {
'hub.mode' => mode,
'hub.topic' => "https://github.com/#{owner}/#{repo_name}/events/#{Event.github_name(event_type)}",
'hub.callback' => url,
'hub.secret' => secret,
},
)
raise "Failure modifying direct subscription: #{response.inspect}" unless response.success?
end
end
end