discourse/lib/onebox/engine/github_pull_request_onebox.rb
Martin Brennan 97e2b353f6
FEATURE: Allow for multiple GitHub onebox tokens (#27887)
Followup 560e8aff75

GitHub auth tokens cannot be made with permissions to
access multiple organisations. This is quite limiting.
This commit changes the site setting to be a "secret list"
type, which allows for a key/value mapping where the value
is treated like a password in the UI.

Now when a GitHub URL is requested for oneboxing, the
org name from the URL is used to determine which token
to use for the request.

Just in case anyone used the old site setting already,
there is a migration to create a `default` entry
with that token in the new list setting, and for
a period of time we will consider that token valid to
use for all GitHub oneboxes as well.
2024-07-15 13:07:36 +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[: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
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))
end
end
end
end