class GithubBot::Github::Client

Public: The Client class manages the client interactions with GitHub such as file retrieval, pull request comments, and pull request checks

Constants

FILE_REMOVED_STATUS
RAW_TYPE

Public Class Methods

initialize(request) click to toggle source

Public: Initialize the singleton with the incoming request information

@param request [Object] The incoming request payload

# File lib/github_bot/github/client.rb, line 21
def initialize(request)
  @instance = new(request)
end
instance() click to toggle source

Public: Returns the current instance of the Client

@raise [StandardError] Raises error if instance has not been initialized before usage

# File lib/github_bot/github/client.rb, line 28
def instance
  raise StandardError, 'client not initialize' unless @instance

  @instance
end
new(request) click to toggle source

Public: Creates a new instance of the Client to manage the GitHub api transactions

@param request [Object] The incoming request payload

# File lib/github_bot/github/client.rb, line 38
def initialize(request)
  @request = request
end

Public Instance Methods

approving_reviewers() click to toggle source

Public: Returns the current list of approving pull request reviewers

@return [Array<Sawyer::Resource>] The list of approving pull request reviewers

# File lib/github_bot/github/client.rb, line 117
def approving_reviewers
  pull_request_reviewers.select { |r| r.state == 'APPROVED' }
end
comment(message:, **opts) click to toggle source

Public: Added a comment to the existing pull request

@param opts [Hash] The parameter options for adding a comment @option opts [:symbol] :message The message to add to the pull request

# File lib/github_bot/github/client.rb, line 80
def comment(message:, **opts)
  client.add_comment(repository_full_name, pull_request_number, message, **opts)
end
create_check_run(name:, **opts) click to toggle source

Public: Creates a GitHub check run for execution

@return [GithubBot::Github::CheckRun] The created check run

# File lib/github_bot/github/client.rb, line 87
def create_check_run(name:, **opts)
  CheckRun.new(
    name: name,
    repo: repository_full_name,
    sha: head_sha,
    client_api: client,
    **opts
  )
end
file_content(file) click to toggle source

Public: Retrieve the contents of a file

@param file [Sawyer::Resource] The file for retrieving contents

# File lib/github_bot/github/client.rb, line 45
def file_content(file)
  raw_contents file
rescue Octokit::NotFound
  ''
rescue Octokit::Forbidden => e
  if e.errors.any? && e.errors.first[:code] == 'too_large'
    # revert to using the raw_url for getting the content
    return URI.parse(file.raw_url).open.read
  end

  raise e
end
files() click to toggle source

Public: Returns an array of all the files impacted with the current pull request

@return [Array<Sawyer::Resource>] A list of all files impacted with the current pull request

# File lib/github_bot/github/client.rb, line 70
def files
  return [] if pull_request.nil?

  @files ||= client.pull_request_files(repository_full_name, pull_request_number)
end
modified_files() click to toggle source

Public: Return the modified files, excluding those that have been removed, from the pull request

@return [Array<Sawyer::Resource>] A list of modified files impacted with the current pull request

# File lib/github_bot/github/client.rb, line 61
def modified_files
  files.reject do |github_file|
    github_file.status == FILE_REMOVED_STATUS
  end
end
pull_request_comments() click to toggle source

Public: Returns the current list of request comments

@return [Array<Sawyer::Resource>] The list of pull request comments

# File lib/github_bot/github/client.rb, line 124
def pull_request_comments
  @pull_request_comments ||= client.issue_comments(
    repository[:full_name],
    pull_request[:number]
  ).sort_by(&:created_at)
end
pull_request_details() click to toggle source

Public: Returns a GitHub pull request object with the details of the current request

@return [Sawyer::Resource] The pull request details associated to current request

# File lib/github_bot/github/client.rb, line 100
def pull_request_details
  @pull_request_details ||= client.pull_request(repository[:full_name], pull_request[:number])
end
pull_request_reviewers() click to toggle source

Public: Returns the current list of pull request reviewers

@return [Array<Sawyer::Resource>] The list of current pull request reviewers

# File lib/github_bot/github/client.rb, line 107
def pull_request_reviewers
  @pull_request_reviewers ||= client.pull_request_reviews(
    repository[:full_name],
    pull_request[:number]
  ).sort_by(&:submitted_at)
end

Private Instance Methods

client() click to toggle source

Returns an instance of the GitHub client API to utilize

# File lib/github_bot/github/client.rb, line 152
def client
  @client ||= Octokit::Client.new(access_token: installation_access_token, auto_paginate: true)
end
decode(content) click to toggle source

Decode the content retrieved from GitHub

@param content [Sawyer::Resource] The content returned from GitHub to decode @return [String] Returns the Base64-decoded version of the content

# File lib/github_bot/github/client.rb, line 137
def decode(content)
  content&.content ? Base64.decode64(content.content).force_encoding('UTF-8') : ''
end
decode_contents(file) click to toggle source

Decode the contents of the file

# File lib/github_bot/github/client.rb, line 142
def decode_contents(file)
  decode(client.contents(repository_full_name, path: file.filename, ref: head_sha))
end
installation_access_token() click to toggle source

Gets an access token associated to the request

# File lib/github_bot/github/client.rb, line 157
def installation_access_token
  Octokit::Client.new(bearer_token: private_key).create_installation_access_token(installation_id)[:token]
end
method_missing(method, *args, &block) click to toggle source

relay messages to Octokit::Client if responds to allow extension of the client and extend/overwrite those concerned with

# File lib/github_bot/github/client.rb, line 188
def method_missing(method, *args, &block)
  return super unless respond_to_missing?(method)

  return payload[method] if payload.key?(method)

  client.send(method, *args, &block)
end
private_key() click to toggle source

Gets the private key associated to the GitHub application

# File lib/github_bot/github/client.rb, line 162
def private_key
  private_pem =
    if ENV['GITHUB_APP_PEM_PATH']
      File.read(Rails.root.join(ENV['GITHUB_APP_PEM_PATH']))
    elsif ENV['GITHUB_APP_PEM_V2']
      ENV['GITHUB_APP_PEM_V2'].gsub('\\\n', "\n")
    elsif ENV['GITHUB_APP_PEM']
      ENV['GITHUB_APP_PEM'].gsub('\n', "\n")
    else
      raise StandardError, "'GITHUB_APP_PEM_PATH' or 'GITHUB_APP_PEM' needs to be set"
    end

  private_key = OpenSSL::PKey::RSA.new(private_pem)

  current = Time.current.to_i

  payload = {
    iat: current,
    exp: current + (10 * 60),
    iss: ENV['GITHUB_APP_IDENTIFIER']
  }
  JWT.encode(payload, private_key, 'RS256')
end
raw_contents(file) click to toggle source

Get raw contents from passed file

# File lib/github_bot/github/client.rb, line 147
def raw_contents(file)
  client.contents(repository_full_name, path: file.filename, ref: head_sha, headers: { 'Accept': RAW_TYPE })
end
respond_to_missing?(method, *args) click to toggle source

because tasks are executed by a validator, some methods are relayed across from the task back to the validator. this override checks for that existence

# File lib/github_bot/github/client.rb, line 198
def respond_to_missing?(method, *args)
  payload.key?(method) || client.respond_to?(method, *args)
end