class PartyFoul::IssueRenderers::Base

Attributes

body[R]
env[RW]
exception[RW]
sha[RW]

Public Class Methods

new(exception, env) click to toggle source

A new renderer instance for GitHub issues

@param [Exception, Hash]

# File lib/party_foul/issue_renderers/base.rb, line 10
def initialize(exception, env)
  self.exception = exception
  self.env       = env
end

Public Instance Methods

body_options(count = 0) click to toggle source

The hash used for building the table in issue body

@return [Hash]

# File lib/party_foul/issue_renderers/base.rb, line 105
def body_options(count = 0)
  { Exception: exception, 'Last Occurrence' => occurred_at, Count: count + 1 }
end
build_table_from_hash(hash) click to toggle source

Builds an HTML table from hash

@return [String]

# File lib/party_foul/issue_renderers/base.rb, line 119
def build_table_from_hash(hash)
  "<table>#{rows_for_table_from_hash(hash)}</table>"
end
comment() click to toggle source

Renderes the issue comment

Customize by overriding {#comment_options}

# File lib/party_foul/issue_renderers/base.rb, line 45
def comment
  build_table_from_hash(comment_options)
end
comment_options() click to toggle source

The hash used for building the table in the comment body

@return [Hash]

# File lib/party_foul/issue_renderers/base.rb, line 112
def comment_options
  { 'Occurred At' => occurred_at }
end
fingerprint() click to toggle source

A SHA1 hex digested representation of the title. The fingerprint is used to create a unique value in the issue body. This value is used for seraching when matching issues happen again in the future.

@return [String]

# File lib/party_foul/issue_renderers/base.rb, line 75
def fingerprint
  Digest::SHA1.hexdigest(title)
end
labels() click to toggle source

Provides additional labels using the configured options

@return [Array]

# File lib/party_foul/issue_renderers/base.rb, line 143
def labels
  if PartyFoul.additional_labels.respond_to? :call
    PartyFoul.additional_labels.call(self.exception, self.env) || []
  else
    PartyFoul.additional_labels || []
  end
end
occurred_at() click to toggle source

The timestamp when the exception occurred.

@return [String]

# File lib/party_foul/issue_renderers/base.rb, line 98
def occurred_at
  @occurred_at ||= Time.now.strftime('%B %d, %Y %H:%M:%S %z')
end
rows_for_table_from_hash(hash) click to toggle source

Builds the rows of an HTML table from hash. Keys as Headers cells and Values as Data cells If the Value is a Hash it will be rendered as a table

@return [String]

# File lib/party_foul/issue_renderers/base.rb, line 128
def rows_for_table_from_hash(hash)
  hash.inject('') do |rows, row|
    key, value = row
    if row[1].kind_of?(Hash)
      value = build_table_from_hash(row[1])
    else
      value = CGI.escapeHTML(value.to_s)
    end
    rows << "<tr><th>#{key}</th><td>#{value}</td></tr>"
  end
end
stack_trace() click to toggle source

Compiles the stack trace for use in the issue body. Lines in the stack trace that are part of the application will be rendered as links to the relative file and line on GitHub based upon {PartyFoul.web_url}, {PartyFoul.owner}, {PartyFoul.repo}, and {PartyFoul.branch}. The branch will be used at the time the exception happens to grab the SHA for that branch at that time for the purpose of linking.

@return [String]

# File lib/party_foul/issue_renderers/base.rb, line 58
def stack_trace
  exception.backtrace.map do |line|
    if from_bundler?(line)
      format_line(line)
    elsif (matches = extract_file_name_and_line_number(line))
      "<a href='#{PartyFoul.repo_url}/blob/#{sha}/#{matches[2]}#L#{matches[3]}'>#{format_line(line)}</a>"
    else
      format_line(line)
    end
  end.join("\n")
end
title() click to toggle source

Title of the issue with any object ids masked

@return [String]

# File lib/party_foul/issue_renderers/base.rb, line 18
def title
  if PartyFoul.title_prefix
    "[#{PartyFoul.title_prefix}] #{masked_title}"
  else
    masked_title
  end
end
update_body(old_body) click to toggle source

Will update the issue body. The count and the time stamp will both be updated. If the format of the issue body fails to match for whatever reason the issue body will be reset.

@return [String]

# File lib/party_foul/issue_renderers/base.rb, line 84
def update_body(old_body)
  begin
    current_count = old_body.match(/<th>Count<\/th><td>(\d+)<\/td>/)[1].to_i
    old_body.sub!("<th>Count</th><td>#{current_count}</td>", "<th>Count</th><td>#{current_count + 1}</td>")
    old_body.sub!(/<th>Last Occurrence<\/th><td>.+?<\/td>/, "<th>Last Occurrence</th><td>#{occurred_at}</td>")
    old_body
  rescue
    self.body
  end
end

Private Instance Methods

app_root() click to toggle source
# File lib/party_foul/issue_renderers/base.rb, line 153
def app_root
  Dir.pwd
end
bundle_root() click to toggle source
# File lib/party_foul/issue_renderers/base.rb, line 157
def bundle_root
  Bundler.bundle_path.to_s if defined?(Bundler)
end
extract_file_name_and_line_number(line) click to toggle source
# File lib/party_foul/issue_renderers/base.rb, line 167
def extract_file_name_and_line_number(line)
  line.match(/#{app_root}\/((.+?):(\d+))/)
end
format_line(line) click to toggle source
# File lib/party_foul/issue_renderers/base.rb, line 179
def format_line(line)
  if from_bundler?(line)
    line.sub(bundle_root, '[bundle]...')
  else
    line.sub(app_root, '[app]...')
  end
end
from_bundler?(line) click to toggle source
# File lib/party_foul/issue_renderers/base.rb, line 161
def from_bundler?(line)
  if bundle_root
    line.match(bundle_root)
  end
end
masked_title() click to toggle source
# File lib/party_foul/issue_renderers/base.rb, line 175
def masked_title
  raw_title.gsub(/0x(\w+)/, "0xXXXXXX")
end
raw_title() click to toggle source
# File lib/party_foul/issue_renderers/base.rb, line 171
def raw_title
  raise NotImplementedError
end