docbrown/app/models/github_issue.rb
Daniel Uber 32a8c39ca2
If there is no body of the linked issue or PR, don't render markdown (#14804)
* If there is no body of the linked issue or PR, don't render markdown

Return a readable and actionable error to the user when they're
linking a PR that doesn't have a body (and we can't render).

This is not needed if there's a fallback path to render _something_ in
the absence of a body (or if it's safe to just skip the `body` rendered
inside the github issue liquid template partial).

* When there is no issue body to render, just show PR title and link

Set the body to an empty string and let github return an empty html
body.

It would be possible to substitute this with a conditional to only
post if a body was present, or assign processed_html directly if not.

* Don't use github api when we have an empty body

Save a network trip and just replace the processed html body with an
empty string when the issue body was nil.
2021-09-28 09:20:49 -05:00

82 lines
2.5 KiB
Ruby

# NOTE: we are using `GithubIssue` to store issues, pull requests and comments
class GithubIssue < ApplicationRecord
CATEGORIES = %w[issue issue_comment].freeze
API_URL_REGEXP = %r{\Ahttps://api.github.com/repos/.*\z}
PATH_COMMENT_REGEXP = %r{/issues/comments/}
PATH_ISSUE_REGEXP = %r{/issues/}
PATH_PULL_REQUEST_REGEXP = %r{/pulls/}
PATH_REPO_REGEXP = %r{.*github.com/repos/}
serialize :issue_serialized, Hash
validates :category, inclusion: { in: CATEGORIES }
validates :url, presence: true, length: { maximum: 400 }, format: API_URL_REGEXP
validates :url, uniqueness: true
class << self
def find_or_fetch(url)
find_by(url: url) || fetch(url)
end
private
def fetch(url)
retrieve_and_save_issue(url)
rescue Github::Errors::NotFound => e
raise e, error_message(url)
end
def retrieve_and_save_issue(url)
issue = new(url: url)
if PATH_COMMENT_REGEXP.match?(url)
repo, issue_id = comment_repo_and_issue_id(url)
issue.issue_serialized = Github::OauthClient.new.issue_comment(repo, issue_id).to_h
issue.category = "issue_comment"
else
repo, issue_id = issue_or_pull_repo_and_issue_id(url)
issue.issue_serialized = Github::OauthClient.new.issue(repo, issue_id).to_h
issue.category = "issue"
end
issue.processed_html = if issue.issue_serialized[:body].present?
# despite the counter intuitive name `.markdown` returns HTML rendered
# from the original markdown
Github::OauthClient.new.markdown(issue.issue_serialized[:body])
else
""
end
issue.save!
issue
end
def clean_url(url)
url.gsub(PATH_REPO_REGEXP, "")
end
def comment_repo_and_issue_id(url)
clean_url(url).split(PATH_COMMENT_REGEXP)
end
def issue_or_pull_repo_and_issue_id(url)
splitter = if PATH_PULL_REQUEST_REGEXP.match?(url)
PATH_PULL_REQUEST_REGEXP
else
PATH_ISSUE_REGEXP
end
clean_url(url).split(splitter)
end
def error_message(url)
if PATH_COMMENT_REGEXP.match?(url)
_, issue_id = comment_repo_and_issue_id(url)
"Issue comment #{issue_id} not found"
else
_, issue_id = issue_or_pull_repo_and_issue_id(url)
"Issue #{issue_id} not found"
end
end
end
end