0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-11 02:59:07 +08:00
discourse/plugins/discourse-github/app/jobs/regular/rebake_github_pr_posts.rb
Renato Atilio 37134e5659
FIX: Refresh GitHub PR onebox status for URL variants (#41878)
The PR status webhook only knows the canonical PR URL, but posts can
link the PR in forms the onebox engine also accepts: with a path suffix
(/changes, /files), query, fragment, http scheme, or www host. Oneboxes
are cached per exact URL (and full oneboxes under the normalized
encoding), so invalidating only the canonical URL left every other
variant stale. The rebake then re-cooked the old status straight from
cache and the icon never updated.

Match links with an anchored, scheme/host-tolerant pattern and
invalidate the exact URLs stored in TopicLink/Chat::MessageLink (plus
their normalized encodings), so whichever variant a post used gets a
fresh fetch on rebake. The anchoring also stops a webhook for `/pull/12`
from rebaking posts for `/pull/123`, which the old prefix match did.
2026-07-21 20:03:12 -03:00

80 lines
2.2 KiB
Ruby
Vendored

# frozen_string_literal: true
module Jobs
class RebakeGithubPrPosts < ::Jobs::Base
sidekiq_options queue: "low"
PR_PATH = %r{\A/[^/]+/[^/]+/pull/\d+\z}
def execute(args)
url = args[:pr_url]
return unless pr_path(url)
rebake_posts(url)
rebake_chat_messages(url) if SiteSetting.chat_enabled
end
private
def pr_path(url)
path = URI(url.to_s).path
path if path&.match?(PR_PATH)
rescue URI::InvalidURIError
nil
end
# tolerates scheme/host variants (http, www) the onebox engine accepts
def pr_url_pattern(url)
"https?://(www\\.)?github\\.com#{Regexp.escape(pr_path(url))}"
end
# anchored so /pull/12 does not match /pull/123
def pr_links(relation, url)
relation.where("url ~* ?", "^#{pr_url_pattern(url)}([/?#].*)?$")
end
# oneboxes are cached per exact URL - raw for inline, normalized for full
def invalidate_onebox_caches(urls)
urls
.flat_map { |url| [url, normalized(url)] }
.compact
.uniq
.each do |url|
Oneboxer.invalidate(url)
InlineOneboxer.invalidate(url)
end
end
def normalized(url)
UrlHelper.normalized_encode(url).to_s
rescue StandardError
nil
end
def rebake_posts(url)
rows = pr_links(TopicLink, url).distinct.pluck(:url, :post_id)
invalidate_onebox_caches(rows.map(&:first).uniq)
Post
.where(id: rows.map(&:last).uniq)
.where(
"cooked ~* :pattern AND (cooked LIKE '%githubpullrequest%' OR cooked LIKE '%inline-onebox%')",
pattern: pr_url_pattern(url),
)
.find_each { |post| post.rebake!(priority: :low, skip_publish_rebaked_changes: true) }
end
def rebake_chat_messages(url)
rows = pr_links(::Chat::MessageLink, url).distinct.pluck(:url, :chat_message_id)
invalidate_onebox_caches(rows.map(&:first).uniq)
::Chat::Message
.where(id: rows.map(&:last).uniq)
.where(
"cooked ~* :pattern AND (cooked LIKE '%githubpullrequest%' OR cooked LIKE '%inline-onebox%')",
pattern: pr_url_pattern(url),
)
.find_each { |message| message.rebake!(priority: :low, skip_notifications: true) }
end
end
end