discourse/lib/onebox/engine/github_pull_request_onebox.rb
Martin Brennan 560e8aff75
FEATURE: Allow oneboxing private GitHub URLs (#27705)
This commit adds the ability to onebox private GitHub
commits, pull requests, issues, blobs, and actions using
a new `github_onebox_access_token` site setting. The token
must be set up in correctly to have access to the repos needed.

To do this successfully with the Oneboxer, we need to skip
redirects on the github.com host, otherwise we get a 404
on the URL before it is translated into a GitHub API URL
and has the appropriate headers added.
2024-07-10 09:39:31 +10:00

108 lines
3.3 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[:owner]}/#{match[:repository]}/pulls/#{match[:number]}"
end
private
def match
@match ||=
@url.match(%r{github\.com/(?<owner>[^/]+)/(?<repository>[^/]+)/pull/(?<number>[^/]+)})
end
def data
result = raw(github_auth_header).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
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[:owner]}/#{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[:owner]}/#{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[:owner]}/#{match[:repository]}/pulls/comments/#{review_match[1]}",
)
end
end
def load_json(url)
::MultiJson.load(URI.parse(url).open(read_timeout: timeout))
end
end
end
end