Add basic client for the GitHub API

parent 7030eb32
module Github
class Client
attr_reader :connection
def initialize(token)
@connection = Faraday.new(url: 'https://api.github.com') do |faraday|
faraday.adapter :net_http_persistent
faraday.response :json, content_type: /\bjson$/
faraday.authorization 'token', token
faraday.response :logger
end
end
def get(url, query = {})
rate_limit = RateLimit.new(connection)
sleep rate_limit.reset_in if rate_limit.exceed?
Github::Response.new(connection.get(url, query))
end
end
end
module Github
class Collection
def initialize(url)
@url = url
end
def fetch(query = {})
return [] if @url.blank?
Enumerator.new do |yielder|
loop do
response = client.get(@url, query)
response.body.each { |item| yielder << item }
raise StopIteration unless response.rels.key?(:next)
@url = response.rels[:next]
end
end.lazy
end
private
def client
@client ||= Github::Client.new
end
end
end
module Github
class Issues
attr_reader :owner, :repo
def initialize(owner, repo)
@owner = owner
@repo = repo
end
def fetch
Collection.new(issues_url).fetch(state: :all, sort: :created, direction: :asc, per_page: 10)
end
private
def issues_url
"/repos/#{owner}/#{repo}/issues"
end
end
end
module Github
class Labels
attr_reader :owner, :repo
def initialize(owner, repo)
@owner = owner
@repo = repo
end
def fetch
Collection.new(labels_url).fetch
end
private
def labels_url
"/repos/#{owner}/#{repo}/labels"
end
end
end
module Github
class Milestones
attr_reader :owner, :repo
def initialize(owner, repo)
@owner = owner
@repo = repo
end
def fetch
Collection.new(milestones_url).fetch
end
private
def milestones_url
"/repos/#{owner}/#{repo}/milestones"
end
end
end
module Github
class PullRequests
attr_reader :owner, :repo
def initialize(owner, repo)
@owner = owner
@repo = repo
end
def fetch
Collection.new(pull_requests_url).fetch(state: :all, sort: :created, direction: :asc)
end
private
def pull_requests_url
"/repos/#{owner}/#{repo}/pulls"
end
end
end
module Github
class RateLimit
SAFE_REMAINING_REQUESTS = 100.freeze
SAFE_RESET_TIME = 500.freeze
attr_reader :connection
def initialize(connection)
@connection = connection
end
def exceed?
return false unless enabled?
remaining <= SAFE_REMAINING_REQUESTS
end
def remaining
@remaining ||= response.body.dig('rate', 'remaining').to_i
end
def reset_in
@reset ||= response.body.dig('rate', 'reset').to_i
end
private
def rate_limit_url
'/rate_limit'
end
def response
@response ||= connection.get(rate_limit_url)
end
# GitHub Rate Limit API returns 404 when the rate limit is disabled
def enabled?
response.status != 404
end
end
end
module Github
class Releases
attr_reader :owner, :repo
def initialize(owner, repo)
@owner = owner
@repo = repo
end
def fetch
Collection.new(releases_url).fetch
end
private
def releases_url
"/repos/#{owner}/#{repo}/releases"
end
end
end
module Github
class Repositories
def initialize(username)
@username = username
end
def fetch
Collection.new(repos_url).fetch
end
private
def repos_url
'/user/repos'
end
end
end
module Github
class Response
attr_reader :raw, :headers, :body, :status
def initialize(response)
@raw = response
@headers = response.headers
@body = response.body
@status = response.status
end
def rels
links = headers['Link'].to_s.split(', ').map do |link|
href, name = link.match(/<(.*?)>; rel="(\w+)"/).captures
[name.to_sym, href]
end
Hash[*links.flatten]
end
end
end
module Github
class User
attr_reader :username
def initialize(username)
@username = username
end
def get
client.get(user_url).body
end
private
def client
@client ||= Github::Client.new
end
def user_url
"/users/#{username}"
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment