class GitHeroes::Engine

Constants

POINTS

Public Class Methods

new(client:nil, org:nil, weeks:nil) click to toggle source
# File lib/git_heroes/engine.rb, line 10
def initialize(client:nil, org:nil, weeks:nil)
  @client       = client
  @organisation = org

  # output/calculated fields
  @data         = {}
  @users        = Set.new
  @durations    = []

  @end_time     = Time.now.beginning_of_week
  week_count    = weeks
  @weeks        = (1..week_count).map { |idx| @end_time - idx.weeks }
  @start_time   = @weeks.last
end

Public Instance Methods

export(path) click to toggle source
# File lib/git_heroes/engine.rb, line 36
def export(path)
  CSV.open(path, 'w') do |csv|
    weeks = @weeks.sort.reverse
    weeks_keys = weeks.map { |w| w.week_key }
    header = %w(login) + weeks.map { |w| w.strftime('%Y.%W (%b %d)') }
    csv << header
    @users.each do |user|
      row = [user]
      weeks_keys.each do |weeks_keys|
        row << @data[user][weeks_keys]
      end
      csv << row
    end
  end
end
export_durations(path) click to toggle source
# File lib/git_heroes/engine.rb, line 52
def export_durations(path)
  CSV.open(path, 'w') do |csv|
    csv << %w(login week duration)
    @durations.each do |login, week, duration|
      csv << [
        login,
        week.strftime('%Y.%W (%b %d)'),
        duration / 86400
      ]
    end
  end
end
run() click to toggle source
# File lib/git_heroes/engine.rb, line 26
def run
  repositories = @client.organization_repositories(@organisation)
  repositories.each do |repository|
    each_pull_request(repository) do |pull_request, get_options|
      process_pull_request(pull_request, get_options)
    end
  end
end

Private Instance Methods

each_comment(pull_request, get_options) { |comment| ... } click to toggle source
# File lib/git_heroes/engine.rb, line 113
def each_comment(pull_request, get_options)
  # comments on PR itself
  uri = pull_request.rels[:comments].href
  @client.request(:get, uri, get_options).each do |comment|
    yield comment
  end

  # comments on diff (unsupported by Octokit)
  uri = "https://api.github.com/repos/#{pull_request.base.repo.full_name}/pulls/#{pull_request.number}/comments"
  @client.request(:get, uri, get_options).each do |comment|
    yield comment
  end
end
each_pull_request(repository) { |pull_request, get_options| ... } click to toggle source
# File lib/git_heroes/engine.rb, line 128
def each_pull_request(repository)
  [:open, :closed].each do |status|
    page = 1
    while true
      pull_requests = @client.pull_requests(repository.full_name, status, per_page: 20, page: page)
      break if pull_requests.empty?
      break if pull_requests.all? { |pr| pr.created_at < @start_time }
      page += 1

      pull_requests.each do |pull_request|
        # skip unmerged closed PRs
        next if pull_request.closed_at? && !pull_request.merged_at?
        # skip too old PRs
        next if pull_request.created_at < @start_time

        get_options = {}
        if pull_request.merged_at? || pull_request.closed_at?
          # old, cacheable forever
          get_options[:headers] = { 'X-Force-Cache' => '1' }
        end

        begin
          pull_request = @client.request(:get, pull_request.rels[:self].href, get_options)
        rescue Octokit::InternalServerError => e
          $stderr.puts "skipping PR #{pull_request.inspect}"
          next
        end

        yield pull_request, get_options
      end
    end
  end
end
give_points(kind, user, timestamp) click to toggle source
# File lib/git_heroes/engine.rb, line 98
def give_points(kind, user, timestamp)
  return unless @start_time < timestamp && timestamp < @end_time
  week_key = timestamp.week_key
  @users.add user
  @data[user] ||= {}
  @data[user][week_key] ||= 0
  @data[user][week_key] += POINTS[kind]
end
process_pull_request(pull_request, get_options) click to toggle source
# File lib/git_heroes/engine.rb, line 69
def process_pull_request(pull_request, get_options)
  non_self_comments = 0
  ttl = pull_request.merged_at? ? nil : 1.day

  each_comment(pull_request, get_options) do |comment|
    next if comment.user.login == pull_request.user.login
    give_points(:comment, comment.user.login, comment.created_at)
    non_self_comments += 1
  end

  merger = pull_request.merged_by
  self_merge = (merger && merger.login == pull_request.user.login)

  if (non_self_comments > 0) || !self_merge
    give_points(:pull,  pull_request.user.login, pull_request.created_at) 
  end

  if pull_request.merged_by
    give_points(:merge, pull_request.merged_by.login, pull_request.merged_at)
  end

  if pull_request.merged_at
    record_duration(pull_request.merged_at - pull_request.created_at, 
                    pull_request.user.login, 
                    pull_request.merged_at)
  end
end
record_duration(duration, user, timestamp) click to toggle source
# File lib/git_heroes/engine.rb, line 107
def record_duration(duration, user, timestamp)
  return unless @start_time < timestamp && timestamp < @end_time
  @durations << [user, timestamp, duration]
end