class Dependabot::PullRequestCreator::MessageBuilder::LinkAndMentionSanitizer

Constants

COMMONMARKER_EXTENSIONS
COMMONMARKER_OPTIONS
EOS_REGEX

End of string

GITHUB_REF_REGEX
GITHUB_USERNAME
MENTION_REGEX
TEAM_MENTION_REGEX

regex to match a team mention on github

Attributes

github_redirection_service[R]

Public Class Methods

new(github_redirection_service:) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb, line 31
def initialize(github_redirection_service:)
  @github_redirection_service = github_redirection_service
end

Public Instance Methods

Private Instance Methods

build_mention_nodes(text) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb, line 118
def build_mention_nodes(text)
  nodes = []
  scan = StringScanner.new(text)

  until scan.eos?
    line = scan.scan_until(MENTION_REGEX) ||
           scan.scan_until(EOS_REGEX)
    line_match = line.match(MENTION_REGEX)
    mention = line_match&.to_s
    text_node = CommonMarker::Node.new(:text)

    if mention && !mention.end_with?("/")
      text_node.string_content = line_match.pre_match
      nodes << text_node
      nodes << create_link_node(
        "https://github.com/#{mention.tr('@', '')}", mention.to_s
      )
    else
      text_node.string_content = line
      nodes << text_node
    end
  end

  nodes
end
build_team_mention_nodes(text) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb, line 144
def build_team_mention_nodes(text)
  nodes = []

  scan = StringScanner.new(text)
  until scan.eos?
    line = scan.scan_until(TEAM_MENTION_REGEX) ||
           scan.scan_until(EOS_REGEX)
    line_match = line.match(TEAM_MENTION_REGEX)
    mention = line_match&.to_s
    text_node = CommonMarker::Node.new(:text)

    if mention
      text_node.string_content = line_match.pre_match
      nodes << text_node
      nodes += build_mention_link_text_nodes(mention.to_s)
    else
      text_node.string_content = line
      nodes << text_node
    end
  end

  nodes
end
insert_zero_width_space_in_mention(mention) click to toggle source

NOTE: Add a zero-width space between the @ and the username to prevent email replies on dependabot pull requests triggering notifications to users who've been mentioned in changelogs etc. PR email replies parse the content of the pull request body in plain text.

# File lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb, line 187
def insert_zero_width_space_in_mention(mention)
  mention.sub("@", "@\u200B").encode("utf-8")
end
replace_github_host(text) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb, line 112
def replace_github_host(text)
  text.gsub(
    /(www\.)?github.com/, github_redirection_service || "github.com"
  )
end
sanitize_mentions(doc) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb, line 50
def sanitize_mentions(doc)
  doc.walk do |node|
    if node.type == :text &&
       node.string_content.match?(MENTION_REGEX)
      nodes = if parent_node_link?(node)
                build_mention_link_text_nodes(node.string_content)
              else
                build_mention_nodes(node.string_content)
              end

      nodes.each do |n|
        node.insert_before(n)
      end

      node.delete
    end
  end
end
sanitize_team_mentions(doc) click to toggle source

When we come across something that looks like a team mention (e.g. @dependabot/reviewers), we replace it with a text node. This is because there are ecosystems that have packages that follow the same pattern (e.g. @angular/angular-cli), and we don't want to create an invalid link, since team mentions link to `github.com/org/:organization_name/teams/:team_name`.

# File lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb, line 74
def sanitize_team_mentions(doc)
  doc.walk do |node|
    if node.type == :text &&
       node.string_content.match?(TEAM_MENTION_REGEX)

      nodes = build_team_mention_nodes(node.string_content)

      nodes.each do |n|
        node.insert_before(n)
      end
      node.delete
    end
  end
end