class Dependabot::PullRequestCreator::MessageBuilder::MetadataPresenter

Attributes

dependency[R]
github_redirection_service[R]
metadata_finder[R]
source[R]
vulnerabilities_fixed[R]

Public Class Methods

new(dependency:, source:, metadata_finder:, vulnerabilities_fixed:, github_redirection_service:) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 26
def initialize(dependency:, source:, metadata_finder:,
               vulnerabilities_fixed:, github_redirection_service:)
  @dependency = dependency
  @source = source
  @metadata_finder = metadata_finder
  @vulnerabilities_fixed = vulnerabilities_fixed
  @github_redirection_service = github_redirection_service
end

Public Instance Methods

to_s() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 35
def to_s
  msg = ""
  msg += vulnerabilities_cascade
  msg += release_cascade
  msg += changelog_cascade
  msg += upgrade_guide_cascade
  msg += commits_cascade
  msg += maintainer_changes_cascade
  msg += break_tag unless msg == ""
  "\n" + sanitize_links_and_mentions(msg, unsafe: true)
end

Private Instance Methods

break_tag() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 238
def break_tag
  source_provider_supports_html? ? "\n<br />" : "\n\n"
end
build_details_tag(summary:, body:) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 147
def build_details_tag(summary:, body:)
  # Azure DevOps does not support <details> tag (https://developercommunity.visualstudio.com/content/problem/608769/add-support-for-in-markdown.html)
  # CodeCommit does not support the <details> tag (no url available)
  if source_provider_supports_html?
    msg = "<details>\n<summary>#{summary}</summary>\n\n"
    msg += body
    msg + "</details>\n"
  else
    "\n\##{summary}\n\n#{body}"
  end
end
changelog_cascade() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 80
def changelog_cascade
  return "" unless changelog_url && changelog_text

  msg = "*Sourced from "\
        "[#{dependency.display_name}'s changelog]"\
        "(#{changelog_url}).*\n\n"
  msg += quote_and_truncate(changelog_text)
  msg = link_issues(text: msg)
  msg = fix_relative_links(text: msg, base_url: changelog_url)
  msg = sanitize_template_tags(msg)
  msg = sanitize_links_and_mentions(msg)

  build_details_tag(summary: "Changelog", body: msg)
end
commits_cascade() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 110
def commits_cascade
  return "" unless commits_url && commits

  msg = ""

  commits.reverse.first(10).each do |commit|
    title = commit[:message].strip.split("\n").first
    title = title.slice(0..76) + "..." if title && title.length > 80
    title = title&.gsub(/(?<=[^\w.-])([_*`~])/, '\\1')
    sha = commit[:sha][0, 7]
    msg += "- [`#{sha}`](#{commit[:html_url]}) #{title}\n"
  end

  msg = msg.gsub(/\<.*?\>/) { |tag| "\\#{tag}" }

  msg +=
    if commits.count > 10
      "- Additional commits viewable in "\
      "[compare view](#{commits_url})\n"
    else
      "- See full diff in [compare view](#{commits_url})\n"
    end
  msg = link_issues(text: msg)
  msg = sanitize_links_and_mentions(msg)

  build_details_tag(summary: "Commits", body: msg)
end
maintainer_changes_cascade() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 138
def maintainer_changes_cascade
  return "" unless maintainer_changes

  build_details_tag(
    summary: "Maintainer changes",
    body: sanitize_links_and_mentions(maintainer_changes) + "\n"
  )
end
quote_and_truncate(text, limit: 50) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 225
def quote_and_truncate(text, limit: 50)
  lines = text.split("\n")
  lines.first(limit).tap do |limited_lines|
    limited_lines.map! { |line| "> #{line}\n" }
    limited_lines << truncated_line if lines.count > limit
  end.join
end
release_cascade() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 63
def release_cascade
  return "" unless releases_text && releases_url

  msg = "*Sourced from [#{dependency.display_name}'s releases]"\
        "(#{releases_url}).*\n\n"
  msg += quote_and_truncate(releases_text)
  msg = link_issues(text: msg)
  msg = fix_relative_links(
    text: msg,
    base_url: source_url + "/blob/HEAD/"
  )
  msg = sanitize_template_tags(msg)
  msg = sanitize_links_and_mentions(msg)

  build_details_tag(summary: "Release notes", body: msg)
end
sanitize_template_tags(text) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 254
def sanitize_template_tags(text)
  text.gsub(/\<.*?\>/) do |tag|
    tag_contents = tag.match(/\<(.*?)\>/).captures.first.strip

    # Unclosed calls to template overflow out of the blockquote block,
    # wrecking the rest of our PRs. Other tags don't share this problem.
    next "\\#{tag}" if tag_contents.start_with?("template")

    tag
  end
end
serialized_vulnerability_details(details) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 159
def serialized_vulnerability_details(details)
  msg = vulnerability_source_line(details)

  msg += "> **#{details['title'].lines.map(&:strip).join(' ')}**\n" if details["title"]

  if (description = details["description"])
    description.strip.lines.first(20).each { |line| msg += "> #{line}" }
    msg += truncated_line if description.strip.lines.count > 20
  end

  msg += "\n" unless msg.end_with?("\n")
  msg += "> \n"
  msg += vulnerability_version_range_lines(details)
  msg + "\n"
end
source_provider_supports_html?() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 242
def source_provider_supports_html?
  !%w(azure codecommit).include?(source.provider)
end
truncated_line() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 233
def truncated_line
  # Tables can spill out of truncated details, so we close them
  "></tr></table> \n ... (truncated)\n"
end
upgrade_guide_cascade() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 95
def upgrade_guide_cascade
  return "" unless upgrade_guide_url && upgrade_guide_text

  msg = "*Sourced from "\
        "[#{dependency.display_name}'s upgrade guide]"\
        "(#{upgrade_guide_url}).*\n\n"
  msg += quote_and_truncate(upgrade_guide_text)
  msg = link_issues(text: msg)
  msg = fix_relative_links(text: msg, base_url: upgrade_guide_url)
  msg = sanitize_template_tags(msg)
  msg = sanitize_links_and_mentions(msg)

  build_details_tag(summary: "Upgrade guide", body: msg)
end
vulnerabilities_cascade() click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 49
def vulnerabilities_cascade
  return "" unless vulnerabilities_fixed&.any?

  msg = ""
  vulnerabilities_fixed.each do |v|
    msg += serialized_vulnerability_details(v)
  end

  msg = sanitize_template_tags(msg)
  msg = sanitize_links_and_mentions(msg)

  build_details_tag(summary: "Vulnerabilities fixed", body: msg)
end
vulnerability_source_line(details) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 175
def vulnerability_source_line(details)
  if details["source_url"] && details["source_name"]
    "*Sourced from [#{details['source_name']}]"\
    "(#{details['source_url']}).*\n\n"
  elsif details["source_name"]
    "*Sourced from #{details['source_name']}.*\n\n"
  else
    ""
  end
end
vulnerability_version_range_lines(details) click to toggle source
# File lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb, line 186
def vulnerability_version_range_lines(details)
  msg = ""
  %w(
    patched_versions
    unaffected_versions
    affected_versions
  ).each do |tp|
    type = tp.split("_").first.capitalize
    next unless details[tp]

    versions_string = details[tp].any? ? details[tp].join("; ") : "none"
    versions_string = versions_string.gsub(/(?<!\\)~/, '\~')
    msg += "> #{type} versions: #{versions_string}\n"
  end
  msg
end