class GithubCommenter::CLI

Public Class Methods

github_pr_options() click to toggle source
# File lib/github_commenter/cli.rb, line 13
def github_pr_options
  option :from_env, enum: %w[ circleci ], description: "complete things from ENV variables of CI. override github,repo,pr,after,until"

  # github things
  option :github, description: "github API entry point (default: https://api.github.com/v3)"
  option :repo,   description: "respoitory of github e.g. okitan/github_commenter"
  option :pr, type: :numeric, description: "number of PR"

  option :github_access_token, required: true, default: ENV["GITHUB_ACCESS_TOKEN"]

  # comments
  option :after, description: "post comment when commits of inserting this line after this hash exist"
  option :until, description: "post comment when commits of inserting this line exists"
end

Public Instance Methods

pr() click to toggle source
# File lib/github_commenter/cli.rb, line 39
def pr
  @options, comments = parse_options

  post_pr_comments(filter_comments(comments, after: @options["after"], _until: @options["before"]))
end

Protected Instance Methods

complete_options(options) click to toggle source
# File lib/github_commenter/cli.rb, line 133
def complete_options(options)
  complete = case options[:from_env]
  when "circleci"
    completed_params_of_circleci(options)
  else
    {}
  end

  options.merge(complete)
end
completed_params_of_circleci(options) click to toggle source
# File lib/github_commenter/cli.rb, line 144
def completed_params_of_circleci(options)
  if pr = ENV["CI_PULL_REQUEST"]
    pr_num = pr.split("/").last.to_i

    template = Addressable::Template.new("https://{host}/{organization}/{repository}/compare/{after}...{until}")

    if params = template.extract(ENV["CIRCLE_COMPARE_URL"])
      github = if params["host"] == "github.com"
        "https://api.github.com/v3"
      else
        "https://#{params["host"]}/api/v3" # I don't know this is correct
      end

      return {
        "github" => github,
        "repo"   => [ params["organization"], params["repository"] ].join("/"),
        "pr"     => pr_num,
        "after"  => params["after"],
        "until"  => params["until"]
      }
    else
      warn `env`
      raise "really?"
    end
  end

  {}
end
filter_comments(comments, after: nil, _until: nil) click to toggle source
# File lib/github_commenter/cli.rb, line 76
def filter_comments(comments, after: nil, _until: nil)
  after ||= pr_info.base.sha

  # XXX: commandline injection risk
  diff = GitDiffParser.parse(::Git::Diff.new(::Git.open("."), after, _until).patch)

  comments.select do |comment|
    if comment[:file]
      find_patch_position_of_comment(diff, comment)
    else # pr comment
      false # TODO: post to pr
    end
  end
end
find_patch_position_of_comment(diff, comment) click to toggle source
# File lib/github_commenter/cli.rb, line 91
def find_patch_position_of_comment(diff, comment)
  diff_of_file = diff.find {|f| f.file == comment[:file] }

  if diff_of_file
    line = diff_of_file.changed_lines.find {|line| line.number == comment[:line].to_i }

    return line.patch_position if line
  end

  nil
end
github_client() click to toggle source
# File lib/github_commenter/cli.rb, line 63
def github_client
  @github_client ||= begin
    Octokit.configure {|config| config.api_endpoint = @options["github"] }
    Octokit::Client.new(access_token: @options["github_access_token"])
  end
end
parse_comments(string) click to toggle source
# File lib/github_commenter/cli.rb, line 119
def parse_comments(string)
  case options[:input_format]
  when "ltsv"
    require "ltsv"

    LTSV.parse(string).map do |line|
      line[:line] = line[:line].to_i if line[:line]
      line
    end
  else
    raise "unknown input format: #{options[:input_format]}"
  end
end
parse_options() click to toggle source
# File lib/github_commenter/cli.rb, line 103
def parse_options
  comments = if stdin?
    parse_comments($stdin.read)
  else
    if options[:message] && options[:file] && options[:line]
      [ { message: options[:message], file: options[:file], line: options[:line] } ]
    else
      raise ::Thor::RequiredArgumentMissingError, "no comments found. gives stdin or use --message option"
    end
  end

  options = complete_options(self.options)

  return [ options, comments ]
end
post_pr_comments(comments) click to toggle source
# File lib/github_commenter/cli.rb, line 46
def post_pr_comments(comments)
  base = pr_info.base.sha
  head = ::Git::Log.new(::Git.open("."), 1).last.sha

  diff = GitDiffParser.parse(`git diff #{base}`)

  comments.each do |comment|
    patch_position = find_patch_position_of_comment(diff, comment)

    if @options["debug"]
      warn "PR comment to #{@options["repo"]}/pulls/#{@options["pr"]}@#{head}##{comment[:file]}:#{patch_position} => #{comment[:message]}"
    else
      github_client.create_pull_request_comment(@options["repo"], @options["pr"], comment[:message], head, comment[:file], patch_position)
    end
  end
end
pr_info() click to toggle source
# File lib/github_commenter/cli.rb, line 70
def pr_info
  @pr_info ||= begin
    github_client.pull_request(@options["repo"], @options["pr"])
  end
end
stdin?() click to toggle source
# File lib/github_commenter/cli.rb, line 173
def stdin?
  # http://www.ownway.info/Ruby/idiom/judge_stdin
  File.pipe?($stdin) || File.select([$stdin], [], [], 0)
end