class GithubBot::Validator::Base

Public: Base class for validators to extend to provide helpful methods for interactions with GitHub

Public Class Methods

new() click to toggle source

Public: Initializes an instance of the validator

# File lib/github_bot/validator/base.rb, line 14
def initialize
  @feedback = []
  @check = nil
end
validate() click to toggle source

Public: Validation method that every consumer will need to override

# File lib/github_bot/validator/base.rb, line 10
def validate; end

Public Instance Methods

check_run(name:, **_opts) { || ... } click to toggle source

Public: Block for execution logic that is the be evaluated and finalized within the GitHub check run content

# File lib/github_bot/validator/base.rb, line 49
def check_run(name:, **_opts)
  # queue request for processing
  @check = client_api.create_check_run(
    name: name,
    output: {
      title: "#{name} validation has been queued...",
      summary: "We're awaiting processing."
    }
  )

  yield if block_given?

  if @feedback.empty?
    @check.complete!(
      output: {
        title: "#{name} validation is complete...",
        summary: "#{name} validation passed!"
      }
    )

  else
    # because limitation of 50 checks per API call execution, break up annotations
    # https://developer.github.com/v3/checks/runs/
    @feedback.each_slice(50).to_a.each do |annotations|
      @check.action_required!(
        output: {
          title: "#{name} validation is complete...",
          summary: "#{name} validation determined there are changes that need attention.",
          annotations: annotations
        }
      )
    end
  end
rescue StandardError => e
  Rails.logger.error message: 'Error occurred during check run', exception: e
  @check.action_required!(
    output: {
      title: "#{name} validation failed...",
      summary: "# Message\n```\n#{e.message}\n```\n# Exception\n```\n#{e.backtrace.join("\n")}\n```"
    }
  )
end
feedback(path:, start_line: 0, end_line: 0, annotation_level:, message:, **opts) click to toggle source

Public: Provide feedback to be generated upon completion of the check run see docs.github.com/en/rest/reference/checks#create-a-check-run for additional details on available parameters for the 'annotations' item

# File lib/github_bot/validator/base.rb, line 22
def feedback(path:, start_line: 0, end_line: 0, annotation_level:, message:, **opts)
  @feedback << {
    path: path,
    start_line: start_line,
    end_line: end_line,
    annotation_level: annotation_level,
    message: message,
    **opts
  }
end
files() click to toggle source

Public: Return all files from request.

# File lib/github_bot/validator/base.rb, line 93
def files
  client_api.files
end
in_progress(**opts) click to toggle source

Public: Moves the check run into the in progress status

# File lib/github_bot/validator/base.rb, line 34
def in_progress(**opts)
  raise StandardError, 'check run has not been established' unless @check

  defaults = {
    output: {
      title: "#{@check.name} validation is in progress...",
      summary: 'We\'re currently validating this request. Please stand by.'
    }
  }

  @check.in_progress!(defaults.deep_merge(opts))
end
load_yaml(file) click to toggle source

Public: Loads the yaml of the file provided

@param file [Sawyer::Resource] The file to load

# File lib/github_bot/validator/base.rb, line 119
def load_yaml(file)
  YAML.safe_load(client_api.file_content(file)).with_indifferent_access
rescue StandardError => e
  feedback(
    path: file.filename,
    annotation_level: 'failure',
    message: 'Malformed yaml content'\
             "exception: #{e.message}"
  )

  {}
end
modified_files() click to toggle source

Public: Return the modified files from request.

# File lib/github_bot/validator/base.rb, line 98
def modified_files
  client_api.modified_files
end
validate_allowed_fields(file:, ident:, hash:, allowed_fields:, **_opts) click to toggle source

Public: Validates for the provided file at a given hash point that the allowed fields are met

@param file [Sawyer::Resource] The file for reference that is being evaluated @param ident [String/Symbol] The text identifier for the hash being evaluated @param hash [Hash] The hash to review keys @param allowed_fields [Array] An array of allowed fields

# File lib/github_bot/validator/base.rb, line 203
def validate_allowed_fields(file:, ident:, hash:, allowed_fields:, **_opts)
  unless hash
    feedback(
      path: file.filename,
      annotation_level: 'failure',
      message: "#{ident}: Element is empty or nil"
    )

    return
  end

  hash.keys&.each do |key|
    unless allowed_fields.include?(key)
      feedback(
        path: file.filename,
        annotation_level: 'failure',
        message: "#{ident}: Key '#{key}' not in the allowed fields [#{allowed_fields.join(', ')}]"
      )
    end
  end
end
validate_fields(file:, ident:, hash:, required_fields:, allowed_fields:, **opts) click to toggle source

Public: Validates for the provided file at a given hash point that the required and allowed fields are met

@param file [Sawyer::Resource] The file for reference that is being evaluated @param ident [String/Symbol] The text identifier for the hash being evaluated @param hash [Hash] The hash to review keys @param required_fields [Array] An array of required elements @param allowed_fields [Array] An array of allowed fields

# File lib/github_bot/validator/base.rb, line 140
def validate_fields(file:, ident:, hash:, required_fields:, allowed_fields:, **opts)
  unless hash
    feedback(
      path: file.filename,
      annotation_level: 'failure',
      message: 'Element is empty or nil'
    )

    return
  end

  validate_required_fields(
    file: file,
    ident: ident,
    hash: hash,
    required_fields: required_fields,
    **opts
  )
  validate_allowed_fields(
    file: file,
    ident: ident,
    hash: hash,
    allowed_fields: allowed_fields,
    **opts
  )
end
validate_file_extension(file, extension) click to toggle source

Public: Validates the file extension for the provided file

@param file [Sawyer::Resource] The file to evaluate @param extension [String] The extension type to evaluate

# File lib/github_bot/validator/base.rb, line 106
def validate_file_extension(file, extension)
  return if File.extname(file.filename) == ".#{extension}"

  feedback(
    path: file.filename,
    annotation_level: 'failure',
    message: "File suffix is incorrect, please use '.#{extension}'"
  )
end
validate_required_fields(file:, ident:, hash:, required_fields:, **_opts) click to toggle source

Public: Validates for the provided file at a given hash point that the required fields are met

@param file [Sawyer::Resource] The file for reference that is being evaluated @param ident [String/Symbol] The text identifier for the hash being evaluated @param hash [Hash] The hash to review keys @param required_fields [Array] An array of required elements

# File lib/github_bot/validator/base.rb, line 174
def validate_required_fields(file:, ident:, hash:, required_fields:, **_opts)
  unless hash
    feedback(
      path: file.filename,
      annotation_level: 'failure',
      message: "#{ident}: Element is empty or nil"
    )

    return
  end

  required_fields.each do |key|
    next unless hash[key].nil?

    feedback(
      path: file.filename,
      annotation_level: 'failure',
      message: "#{ident}: Missing required element '#{key}'"
    )
  end
end

Private Instance Methods

client_api() click to toggle source
# File lib/github_bot/validator/base.rb, line 227
def client_api
  ::GithubBot::Github::Client.instance
end