prontolabs/pronto

View on GitHub
lib/pronto/github.rb

Summary

Maintainability
A
35 mins
Test Coverage
A
95%
require 'pronto/github_pull'

module Pronto
  class Github < Client
    def initialize(repo)
      super(repo)
      @github_pull = Pronto::GithubPull.new(client, slug)
    end

    def pull_comments(sha)
      @comment_cache["#{pull_id}/#{sha}"] ||= begin
        client.pull_comments(slug, pull_id).map do |comment|
          Comment.new(
            sha, comment.body, comment.path, comment.line || comment.original_line
          )
        end
      end
    rescue Octokit::NotFound => e
      @config.logger.log("Error raised and rescued: #{e}")
      msg = "Pull request for sha #{sha} with id #{pull_id} was not found."
      raise Pronto::Error, msg
    end

    def commit_comments(sha)
      @comment_cache[sha.to_s] ||= begin
        client.commit_comments(slug, sha).map do |comment|
          Comment.new(sha, comment.body, comment.path, comment.line)
        end
      end
    end

    def create_commit_comment(comment)
      @config.logger.log("Creating commit comment on #{comment.sha}")
      client.create_commit_comment(slug, comment.sha, comment.body,
                                   comment.path, nil, comment.position)
    end

    def create_pull_comment(comment)
      if comment.path && comment.position
        @config.logger.log("Creating pull request comment on #{pull_id}")
        client.create_pull_comment(
          # Depending on the Octokit version the 6th argument can be either postion or line. We'll
          # provide the `line` as this argument and also provide the line in the options argument.
          # The API uses `line` and ignores position when `line` is provided.
          slug, pull_id, comment.body, pull_sha || comment.sha,
          comment.path, comment.position, { line: comment.position }
        )
      else
        create_commit_comment(comment)
      end
    end

    def publish_pull_request_comments(comments)
      comments_left = comments.clone
      while comments_left.any?
        comments_to_publish = comments_left.slice!(0, warnings_per_review)
        create_pull_request_review(comments_to_publish)
      end
    end

    def create_commit_status(status)
      sha = pull_sha || status.sha
      @config.logger.log("Creating comment status on #{sha}")
      client.create_status(slug, sha, status.state,
                           context: status.context,
                           description: status.description)
    end

    private

    def create_pull_request_review(comments)
      options = {
        event: @config.github_review_type,
        comments: comments.map do |comment|
          {
            path: comment.path,
            line: comment.position,
            body: comment.body
          }
        end
      }
      client.create_pull_request_review(slug, pull_id, options)
    end

    def slug
      return @config.github_slug if @config.github_slug
      @slug ||= begin
        @repo.remote_urls.map do |url|
          hostname = Regexp.escape(@config.github_hostname)
          match = %r{.*#{hostname}(:|\/)(?<slug>.*?)(?:\.git)?\z}.match(url)
          match[:slug] if match
        end.compact.first
      end
    end

    def client
      @client ||= Octokit::Client.new(api_endpoint: @config.github_api_endpoint,
                                      web_endpoint: @config.github_web_endpoint,
                                      access_token: @config.github_access_token,
                                      auto_paginate: true)
    end

    def pull_id
      env_pull_id || pull[:number].to_i
    end

    def pull_sha
      pull[:head][:sha] if pull
    end

    def pull
      @pull ||= if env_pull_id
                  @github_pull.pull_by_id(env_pull_id)
                elsif @repo.branch
                  @github_pull.pull_by_branch(@repo.branch)
                elsif @repo.head_detached?
                  @github_pull.pull_by_commit(@repo.head_commit_sha)
                end
    end

    def warnings_per_review
      @warnings_per_review ||= @config.warnings_per_review
    end
  end
end