lib/dependabot/pull_request_creator/message_builder/issue_linker.rb
# typed: strong # frozen_string_literal: true require "sorbet-runtime" require "dependabot/pull_request_creator/message_builder" module Dependabot class PullRequestCreator class MessageBuilder class IssueLinker extend T::Sig REPO_REGEX = %r{(?<repo>[\w.-]+/(?:(?!\.git|\.\s)[\w.-])+)} TAG_REGEX = /(?<tag>(?:\#|GH-)\d+)/i ISSUE_LINK_REGEXS = T.let([ / (?:(?<=[^A-Za-z0-9\[\\]|^)\\*#{TAG_REGEX}(?=[^A-Za-z0-9\-]|$))| (?:(?<=\s|^)#{REPO_REGEX}#{TAG_REGEX}(?=[^A-Za-z0-9\-]|$)) /x, /\[#{TAG_REGEX}\](?=[^A-Za-z0-9\-\(])/, /\[(?<tag>(?:\#|GH-)?\d+)\]\(\)/i ].freeze, T::Array[Regexp]) sig { returns(T.nilable(String)) } attr_reader :source_url sig { params(source_url: T.nilable(String)).void } def initialize(source_url:) @source_url = source_url end sig { params(text: String).returns(String) } def link_issues(text:) # Loop through each of the issue link regexes, replacing any instances # of them with an absolute link that uses the source URL ISSUE_LINK_REGEXS.reduce(text) do |updated_text, regex| updated_text.gsub(regex) do |issue_link| tag = T.must( T.must(issue_link .match(/(?<tag>(?:\#|GH-)?\d+)/i)) .named_captures.fetch("tag") ) number = tag.match(/\d+/).to_s repo = issue_link .match("#{REPO_REGEX}#{TAG_REGEX}") &.named_captures &.fetch("repo", nil) source = if repo "https://github.com/#{repo}" elsif source_url source_url end if source "[#{repo ? (repo + tag) : tag}](#{source}/issues/#{number})" else issue_link end end end end end end end end