discourse/lib/onebox/engine/github_pull_request_onebox.rb
Martin Brennan f5cbc3e3b8
FEATURE: Allow oneboxing private GitHub repo URLs and add private indicator to HTML (#27947)
Followup 560e8aff75

The linked commit allowed oneboxing private GitHub PRs,
issues, commits, and so on, but it didn't actually allow
oneboxing the root repo e.g https://github.com/discourse/discourse-reactions

We didn't have an engine for this, we were relying on OpenGraph
tags on the HTML rendering of the page like we do with other
oneboxes.

To fix this, we needed a new github engine for repos specifically.

Also, this commit adds a `data-github-private-repo` attribute to
PR, issue, and repo onebox HTML so we have an indicator of
whether the repo was private, which can be used for theme components
and so on.
2024-07-19 12:21:45 +10:00

111 lines
3.4 KiB
Ruby

# frozen_string_literal: true
require_relative "../mixins/github_body"
require_relative "../mixins/github_auth_header"
module Onebox
module Engine
class GithubPullRequestOnebox
include Engine
include LayoutSupport
include JSON
include Onebox::Mixins::GithubBody
include Onebox::Mixins::GithubAuthHeader
GITHUB_COMMENT_REGEX = /(<!--.*?-->\r\n)/
matches_regexp(%r{^https?://(?:www\.)?(?:(?:\w)+\.)?(github)\.com(?:/)?(?:.)*/pull})
always_https
def url
"https://api.github.com/repos/#{match[:org]}/#{match[:repository]}/pulls/#{match[:number]}"
end
private
def match
@match ||=
@url.match(%r{github\.com/(?<org>[^/]+)/(?<repository>[^/]+)/pull/(?<number>[^/]+)})
end
def data
result = raw(github_auth_header(match[:org])).clone
result["link"] = link
created_at = Time.parse(result["created_at"])
result["created_at"] = created_at.strftime("%I:%M%p - %d %b %y %Z")
result["created_at_date"] = created_at.strftime("%F")
result["created_at_time"] = created_at.strftime("%T")
ulink = URI(link)
result["domain"] = "#{ulink.host}/#{ulink.path.split("/")[1]}/#{ulink.path.split("/")[2]}"
result["body"], result["excerpt"] = compute_body(result["body"])
if result["commit"] = load_commit(link)
result["body"], result["excerpt"] =
compute_body(result["commit"]["commit"]["message"].lines[1..].join)
elsif result["comment"] = load_comment(link)
result["body"], result["excerpt"] = compute_body(result["comment"]["body"])
elsif result["discussion"] = load_review(link)
result["body"], result["excerpt"] = compute_body(result["discussion"]["body"])
else
result["pr"] = true
end
result["i18n"] = i18n
result["i18n"]["pr_summary"] = I18n.t(
"onebox.github.pr_summary",
{
commits: result["commits"],
changed_files: result["changed_files"],
additions: result["additions"],
deletions: result["deletions"],
},
)
result["is_private"] = result.dig("base", "repo", "private")
result
end
def i18n
{
opened: I18n.t("onebox.github.opened"),
commit_by: I18n.t("onebox.github.commit_by"),
comment_by: I18n.t("onebox.github.comment_by"),
review_by: I18n.t("onebox.github.review_by"),
}
end
def load_commit(link)
if commit_match = link.match(%r{commits/(\h+)})
load_json(
"https://api.github.com/repos/#{match[:org]}/#{match[:repository]}/commits/#{commit_match[1]}",
)
end
end
def load_comment(link)
if comment_match = link.match(/#issuecomment-(\d+)/)
load_json(
"https://api.github.com/repos/#{match[:org]}/#{match[:repository]}/issues/comments/#{comment_match[1]}",
)
end
end
def load_review(link)
if review_match = link.match(/#discussion_r(\d+)/)
load_json(
"https://api.github.com/repos/#{match[:org]}/#{match[:repository]}/pulls/comments/#{review_match[1]}",
)
end
end
def load_json(url)
::MultiJson.load(
URI.parse(url).open({ read_timeout: timeout }.merge(github_auth_header(match[:org]))),
)
end
end
end
end