class GemsBond::Fetchers::Github

Fetches data from GitHub

Constants

REPOSITORY_REGEX

GitHub repository pattern, e.g.: “github.com/BigBigDoudou/gems_bond

Public Class Methods

new(url) click to toggle source

Initializes an instance @param url [String] URL of the GitHub repository @return [GemsBond::Fetchers::Github]

Calls superclass method GemsBond::Fetchers::Fetcher::new
# File lib/gems_bond/fetchers/github.rb, line 23
def initialize(url)
  super(url)
  @url = url
end
valid_url?(url) click to toggle source

Validates that `url` matches GitHub repository URL

# File lib/gems_bond/fetchers/github.rb, line 15
def valid_url?(url)
  url&.match?(REPOSITORY_REGEX)
end

Public Instance Methods

contributors_count() click to toggle source

Returns number of contributors @return [Integer] @note GitHub API does not provide this number out of the box

so we fetch all repository contributors and paginate with 1 per page
thus the last page (from headers) should equal the number of contributors
# File lib/gems_bond/fetchers/github.rb, line 58
def contributors_count
  client = Octokit::Client.new(access_token: token, per_page: 1)
  client.contributors(@repository_path)
  response = client.last_response
  links = response.headers[:link]
  # e.g.:  "[...] <https://api.github.com/repositories/8514/contributors?per_page=1&page=377>; rel=\"last\""
  return 0 unless links

  Integer(links.match(/.*per_page=1&page=(?<last>\d+)>; rel="last"/)[:last], 10)
end
days_since_last_commit() click to toggle source

Returns number of days since last commit @return [Date]

# File lib/gems_bond/fetchers/github.rb, line 86
def days_since_last_commit
  return unless last_commit_date

  Integer(Date.today - last_commit_date)
end
forks_count() click to toggle source

Returns number of forks @return [Integer]

# File lib/gems_bond/fetchers/github.rb, line 43
def forks_count
  @repository["forks"]
end
last_commit_date() click to toggle source

Returns date of last commit (on main branch) @return [Date]

# File lib/gems_bond/fetchers/github.rb, line 77
def last_commit_date
  date = client.commits(@repository_path).first[:commit][:committer][:date]
  return unless date

  Date.parse(date.to_s)
end
lib_size() click to toggle source

Returns size of the lib directory @return [Integer]

# File lib/gems_bond/fetchers/github.rb, line 94
def lib_size
  contents_size = dir_size("lib")
  return unless contents_size

  lines_count_estimation = contents_size / 25
  return lines_count_estimation if lines_count_estimation < 100

  lines_count_estimation - lines_count_estimation % 100
end
open_issues_count() click to toggle source

Returns number of open issues @return [Integer]

# File lib/gems_bond/fetchers/github.rb, line 71
def open_issues_count
  @repository["open_issues"]
end
stars_count() click to toggle source

Returns number of stars @return [Integer]

# File lib/gems_bond/fetchers/github.rb, line 49
def stars_count
  @repository["watchers"]
end
start() click to toggle source

Starts the service @return [Boolean] @note rescue connection errors with nil

Calls superclass method GemsBond::Fetchers::Fetcher#start
# File lib/gems_bond/fetchers/github.rb, line 31
def start
  super
  parse_url
  login
  # ensure repository exists (otherwise it raises Octokit error)
  set_repository
rescue Octokit::Unauthorized, Octokit::InvalidRepository, Octokit::NotFound
  stop
end

Private Instance Methods

client() click to toggle source

Initializes a client @return [Octokit::Client]

# File lib/gems_bond/fetchers/github.rb, line 127
def client
  Octokit::Client.new(access_token: token)
end
dir_size(dir_path) click to toggle source

Returns size of the given directory @param dir_path [String] path to the directory, e.g.: “lib/devise/strategies” @return [Integer] @note sum size of each subdirectories recursively

# File lib/gems_bond/fetchers/github.rb, line 147
def dir_size(dir_path)
  contents = client.contents(@repository_path, path: dir_path)
  # starts accumulator with size of files
  acc =
    contents
    .select { |content| content[:type] == "file" }
    .sum { |content| content[:size] }
  # adds size of subdirectories to the accumulator, with recursion
  acc +=
    contents
    .select { |content| content[:type] == "dir" }
    .sum { |sub_dir| dir_size("#{dir_path}/#{sub_dir[:name]}") }
  acc
rescue Octokit::NotFound
  nil
end
login() click to toggle source

Logs with client @return [String] GitHub'username

# File lib/gems_bond/fetchers/github.rb, line 119
def login
  return unless token

  @login ||= client.user.login
end
parse_url() click to toggle source

Parses url to find out repository path @return [String] @raise Octokit::InvalidRepository if the url pattern is invalid

# File lib/gems_bond/fetchers/github.rb, line 109
def parse_url
  matches = @url.match(REPOSITORY_REGEX)
  raise Octokit::InvalidRepository unless matches

  path = matches[:repository].split("/")
  @repository_path = "#{path[0]}/#{path[1]}"
end
set_repository() click to toggle source

Returns repository object @return [Sawyer::Resource]

# File lib/gems_bond/fetchers/github.rb, line 139
def set_repository
  @repository = client.repo(@repository_path)
end
token() click to toggle source

Returns token from configuration @return [String, nil]

# File lib/gems_bond/fetchers/github.rb, line 133
def token
  GemsBond.configuration&.github_token
end