class Dependabot::PullRequestCreator::MessageBuilder
MessageBuilder
builds PR message for a dependency update
Attributes
commit_message_options[R]
credentials[R]
dependencies[R]
files[R]
github_redirection_service[R]
pr_message_header[R]
source[R]
vulnerabilities_fixed[R]
Public Class Methods
new(source:, dependencies:, files:, credentials:, pr_message_header: nil, pr_message_footer: nil, commit_message_options: {}, vulnerabilities_fixed: {}, github_redirection_service:)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 25 def initialize(source:, dependencies:, files:, credentials:, pr_message_header: nil, pr_message_footer: nil, commit_message_options: {}, vulnerabilities_fixed: {}, github_redirection_service:) @dependencies = dependencies @files = files @source = source @credentials = credentials @pr_message_header = pr_message_header @pr_message_footer = pr_message_footer @commit_message_options = commit_message_options @vulnerabilities_fixed = vulnerabilities_fixed @github_redirection_service = github_redirection_service end
Public Instance Methods
commit_message()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 53 def commit_message message = commit_subject + "\n\n" message += commit_message_intro message += metadata_links message += "\n\n" + message_trailers if message_trailers message end
message()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 61 def message Dependabot::PullRequestCreator::Message.new( pr_name: pr_name, pr_message: pr_message, commit_message: commit_message ) end
pr_message()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 48 def pr_message suffixed_pr_message_header + commit_message_intro + \ metadata_cascades + prefixed_pr_message_footer end
pr_name()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 40 def pr_name pr_name = pr_name_prefixer.pr_name_prefix pr_name += library? ? library_pr_name : application_pr_name return pr_name if files.first.directory == "/" pr_name + " in #{files.first.directory}" end
Private Instance Methods
application_pr_name()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 86 def application_pr_name pr_name = "bump " pr_name = pr_name.capitalize if pr_name_prefixer.capitalize_first_word? pr_name + if dependencies.count == 1 dependency = dependencies.first "#{dependency.display_name} "\ "#{from_version_msg(previous_version(dependency))}"\ "to #{new_version(dependency)}" elsif updating_a_property? dependency = dependencies.first "#{property_name} "\ "#{from_version_msg(previous_version(dependency))}"\ "to #{new_version(dependency)}" elsif updating_a_dependency_set? dependency = dependencies.first "#{dependency_set.fetch(:group)} dependency set "\ "#{from_version_msg(previous_version(dependency))}"\ "to #{new_version(dependency)}" else names = dependencies.map(&:name) "#{names[0..-2].join(', ')} and #{names[-1]}" end end
changelog_url(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 326 def changelog_url(dependency) metadata_finder(dependency).changelog_url end
commit_message_intro()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 126 def commit_message_intro return requirement_commit_message_intro if library? version_commit_message_intro end
commit_subject()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 116 def commit_subject subject = pr_name.gsub("⬆️", ":arrow_up:").gsub("🔒", ":lock:") return subject unless subject.length > 72 subject = subject.gsub(/ from [^\s]*? to [^\s]*/, "") return subject unless subject.length > 72 subject.split(" in ").first end
commits_url(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 330 def commits_url(dependency) metadata_finder(dependency).commits_url end
dependency_links()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 266 def dependency_links dependencies.map do |dependency| if source_url(dependency) "[#{dependency.display_name}](#{source_url(dependency)})" elsif homepage_url(dependency) "[#{dependency.display_name}](#{homepage_url(dependency)})" else dependency.display_name end end end
dependency_set()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 256 def dependency_set @dependency_set ||= dependencies.first.requirements. find { |r| r.dig(:metadata, :dependency_set) }&. dig(:metadata, :dependency_set) raise "No dependency set!" unless @dependency_set @dependency_set end
dependency_set_intro()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 214 def dependency_set_intro dependency = dependencies.first "Bumps `#{dependency_set.fetch(:group)}` "\ "dependency set #{from_version_msg(previous_version(dependency))}"\ "to #{new_version(dependency)}." end
docker_digest_from_reqs(requirements)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 404 def docker_digest_from_reqs(requirements) requirements. map { |r| r.dig(:source, "digest") || r.dig(:source, :digest) }. compact.first end
from_version_msg(previous_version)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 228 def from_version_msg(previous_version) return "" unless previous_version "from #{previous_version} " end
homepage_url(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 334 def homepage_url(dependency) metadata_finder(dependency).homepage_url end
library?()
click to toggle source
TODO: Bring this in line with existing library checks that we do in the update checkers, which are also overriden by passing an explicit `requirements_update_strategy`.
TODO re-use in BranchNamer
# File lib/dependabot/pull_request_creator/message_builder.rb, line 461 def library? # Reject any nested child gemspecs/vendored git dependencies root_files = files.map(&:name). select { |p| Pathname.new(p).dirname.to_s == "." } return true if root_files.select { |nm| nm.end_with?(".gemspec") }.any? dependencies.any? { |d| previous_version(d).nil? } end
library_pr_name()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 71 def library_pr_name pr_name = "update " pr_name = pr_name.capitalize if pr_name_prefixer.capitalize_first_word? pr_name + if dependencies.count == 1 "#{dependencies.first.display_name} requirement "\ "#{from_version_msg(old_library_requirement(dependencies.first))}"\ "to #{new_library_requirement(dependencies.first)}" else names = dependencies.map(&:name) "requirements for #{names[0..-2].join(', ')} and #{names[-1]}" end end
message_trailers()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 144 def message_trailers return unless on_behalf_of_message || signoff_message [on_behalf_of_message, signoff_message].compact.join("\n") end
metadata_cascades()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 298 def metadata_cascades return metadata_cascades_for_dep(dependencies.first) if dependencies.one? dependencies.map do |dep| msg = "\nUpdates `#{dep.display_name}` "\ "#{from_version_msg(previous_version(dep))}"\ "to #{new_version(dep)}" if vulnerabilities_fixed[dep.name]&.one? msg += " **This update includes a security fix.**" elsif vulnerabilities_fixed[dep.name]&.any? msg += " **This update includes security fixes.**" end msg + metadata_cascades_for_dep(dep) end.join end
metadata_cascades_for_dep(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 316 def metadata_cascades_for_dep(dependency) MetadataPresenter.new( dependency: dependency, source: source, metadata_finder: metadata_finder(dependency), vulnerabilities_fixed: vulnerabilities_fixed[dependency.name], github_redirection_service: github_redirection_service ).to_s end
metadata_finder(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 350 def metadata_finder(dependency) @metadata_finder ||= {} @metadata_finder[dependency.name] ||= MetadataFinders. for_package_manager(dependency.package_manager). new(dependency: dependency, credentials: credentials) end
metadata_links()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 278 def metadata_links return metadata_links_for_dep(dependencies.first) if dependencies.count == 1 dependencies.map do |dep| "\n\nUpdates `#{dep.display_name}` "\ "#{from_version_msg(previous_version(dep))}to "\ "#{new_version(dep)}"\ "#{metadata_links_for_dep(dep)}" end.join end
metadata_links_for_dep(dep)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 289 def metadata_links_for_dep(dep) msg = "" msg += "\n- [Release notes](#{releases_url(dep)})" if releases_url(dep) msg += "\n- [Changelog](#{changelog_url(dep)})" if changelog_url(dep) msg += "\n- [Upgrade guide](#{upgrade_url(dep)})" if upgrade_url(dep) msg += "\n- [Commits](#{commits_url(dep)})" if commits_url(dep) msg end
multidependency_intro()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 222 def multidependency_intro "Bumps #{dependency_links[0..-2].join(', ')} "\ "and #{dependency_links[-1]}. These "\ "dependencies needed to be updated together." end
multidependency_property_intro()
click to toggle source
rubocop:enable Metrics/PerceivedComplexity
# File lib/dependabot/pull_request_creator/message_builder.rb, line 206 def multidependency_property_intro dependency = dependencies.first "Bumps `#{property_name}` "\ "#{from_version_msg(previous_version(dependency))}"\ "to #{new_version(dependency)}." end
new_library_requirement(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 437 def new_library_requirement(dependency) updated_reqs = dependency.requirements - dependency.previous_requirements gemspec = updated_reqs.find { |r| r[:file].match?(%r{^[^/]*\.gemspec$}) } return gemspec.fetch(:requirement) if gemspec req = updated_reqs.first.fetch(:requirement) return req if req return new_ref(dependency) if ref_changed?(dependency) && new_ref(dependency) raise "No new requirement!" end
new_ref(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 417 def new_ref(dependency) new_refs = dependency.requirements.map do |r| r.dig(:source, "ref") || r.dig(:source, :ref) end.compact.uniq return new_refs.first if new_refs.count == 1 end
new_version(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 390 def new_version(dependency) if dependency.version.match?(/^[0-9a-f]{40}$/) return new_ref(dependency) if ref_changed?(dependency) && new_ref(dependency) "`#{dependency.version[0..6]}`" elsif dependency.version == dependency.previous_version && package_manager == "docker" digest = docker_digest_from_reqs(dependency.requirements) "`#{digest.split(':').last[0..6]}`" else dependency.version end end
old_library_requirement(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 424 def old_library_requirement(dependency) old_reqs = dependency.previous_requirements - dependency.requirements gemspec = old_reqs.find { |r| r[:file].match?(%r{^[^/]*\.gemspec$}) } return gemspec.fetch(:requirement) if gemspec req = old_reqs.first.fetch(:requirement) return req if req return previous_ref(dependency) if ref_changed?(dependency) end
on_behalf_of_message()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 158 def on_behalf_of_message signoff_details = commit_message_options[:signoff_details] return unless signoff_details.is_a?(Hash) return unless signoff_details[:org_name] && signoff_details[:org_email] "On-behalf-of: @#{signoff_details[:org_name]} "\ "<#{signoff_details[:org_email]}>" end
package_manager()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 479 def package_manager @package_manager ||= dependencies.first.package_manager end
pr_name_prefix()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 112 def pr_name_prefix pr_name_prefixer.pr_name_prefix end
pr_name_prefixer()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 358 def pr_name_prefixer @pr_name_prefixer ||= PrNamePrefixer.new( source: source, dependencies: dependencies, credentials: credentials, commit_message_options: commit_message_options, security_fix: vulnerabilities_fixed.values.flatten.any? ) end
previous_ref(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 410 def previous_ref(dependency) previous_refs = dependency.previous_requirements.map do |r| r.dig(:source, "ref") || r.dig(:source, :ref) end.compact.uniq return previous_refs.first if previous_refs.count == 1 end
previous_version(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 369 def previous_version(dependency) # If we don't have a previous version, we *may* still be able to figure # one out if a ref was provided and has been changed (in which case the # previous ref was essentially the version). if dependency.previous_version.nil? return ref_changed?(dependency) ? previous_ref(dependency) : nil end if dependency.previous_version.match?(/^[0-9a-f]{40}$/) return previous_ref(dependency) if ref_changed?(dependency) && previous_ref(dependency) "`#{dependency.previous_version[0..6]}`" elsif dependency.version == dependency.previous_version && package_manager == "docker" digest = docker_digest_from_reqs(dependency.previous_requirements) "`#{digest.split(':').last[0..6]}`" else dependency.previous_version end end
property_name()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 246 def property_name @property_name ||= dependencies.first.requirements. find { |r| r.dig(:metadata, :property_name) }&. dig(:metadata, :property_name) raise "No property name!" unless @property_name @property_name end
ref_changed?(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 452 def ref_changed?(dependency) previous_ref(dependency) != new_ref(dependency) end
releases_url(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 338 def releases_url(dependency) metadata_finder(dependency).releases_url end
requirement_commit_message_intro()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 167 def requirement_commit_message_intro msg = "Updates the requirements on " msg += if dependencies.count == 1 "#{dependency_links.first} " else "#{dependency_links[0..-2].join(', ')} and #{dependency_links[-1]} " end msg + "to permit the latest version." end
signoff_message()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 150 def signoff_message signoff_details = commit_message_options[:signoff_details] return unless signoff_details.is_a?(Hash) return unless signoff_details[:name] && signoff_details[:email] "Signed-off-by: #{signoff_details[:name]} <#{signoff_details[:email]}>" end
source_url(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 342 def source_url(dependency) metadata_finder(dependency).source_url end
suffixed_pr_message_header()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 138 def suffixed_pr_message_header return "" unless pr_message_header "#{pr_message_header}\n\n" end
switching_from_ref_to_release?(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 470 def switching_from_ref_to_release?(dependency) unless dependency.previous_version&.match?(/^[0-9a-f]{40}$/) || dependency.previous_version.nil? && previous_ref(dependency) return false end Gem::Version.correct?(dependency.version) end
updating_a_dependency_set?()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 240 def updating_a_dependency_set? dependencies.first. requirements. any? { |r| r.dig(:metadata, :dependency_set) } end
updating_a_property?()
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 234 def updating_a_property? dependencies.first. requirements. any? { |r| r.dig(:metadata, :property_name) } end
upgrade_url(dependency)
click to toggle source
# File lib/dependabot/pull_request_creator/message_builder.rb, line 346 def upgrade_url(dependency) metadata_finder(dependency).upgrade_guide_url end
version_commit_message_intro()
click to toggle source
rubocop:disable Metrics/PerceivedComplexity
# File lib/dependabot/pull_request_creator/message_builder.rb, line 181 def version_commit_message_intro return multidependency_property_intro if dependencies.count > 1 && updating_a_property? return dependency_set_intro if dependencies.count > 1 && updating_a_dependency_set? return multidependency_intro if dependencies.count > 1 dependency = dependencies.first msg = "Bumps #{dependency_links.first} "\ "#{from_version_msg(previous_version(dependency))}"\ "to #{new_version(dependency)}." msg += " This release includes the previously tagged commit." if switching_from_ref_to_release?(dependency) if vulnerabilities_fixed[dependency.name]&.one? msg += " **This update includes a security fix.**" elsif vulnerabilities_fixed[dependency.name]&.any? msg += " **This update includes security fixes.**" end msg end