-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Extract TitleBuilder for PR title composition #14285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,126 @@ | ||||||||||
| # typed: strict | ||||||||||
| # frozen_string_literal: true | ||||||||||
|
|
||||||||||
| require "sorbet-runtime" | ||||||||||
| require "dependabot/dependency" | ||||||||||
| require "dependabot/logger" | ||||||||||
| require "dependabot/pull_request_creator/pr_name_prefixer" | ||||||||||
|
|
||||||||||
| module Dependabot | ||||||||||
| class PullRequestCreator | ||||||||||
| class MessageBuilder | ||||||||||
| # Composes a final PR title from a base title + prefix. | ||||||||||
| # | ||||||||||
| # Works in two modes: | ||||||||||
| # 1. With a full PrNamePrefixer (updater path — has source/credentials for | ||||||||||
| # commit style auto-detection) | ||||||||||
| # 2. With just commit_message_options (API path — explicit prefix only, | ||||||||||
| # no network calls needed) | ||||||||||
| class TitleBuilder | ||||||||||
| extend T::Sig | ||||||||||
|
|
||||||||||
| sig { returns(String) } | ||||||||||
| attr_reader :base_title | ||||||||||
|
|
||||||||||
| sig { returns(T.nilable(Dependabot::PullRequestCreator::PrNamePrefixer)) } | ||||||||||
| attr_reader :prefixer | ||||||||||
|
|
||||||||||
| sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) } | ||||||||||
| attr_reader :commit_message_options | ||||||||||
|
|
||||||||||
| sig { returns(T.nilable(T::Array[Dependabot::Dependency])) } | ||||||||||
| attr_reader :dependencies | ||||||||||
|
|
||||||||||
| sig do | ||||||||||
| params( | ||||||||||
| base_title: String, | ||||||||||
| prefixer: T.nilable(Dependabot::PullRequestCreator::PrNamePrefixer), | ||||||||||
| commit_message_options: T.nilable(T::Hash[Symbol, T.untyped]), | ||||||||||
| dependencies: T.nilable(T::Array[Dependabot::Dependency]) | ||||||||||
| ).void | ||||||||||
| end | ||||||||||
| def initialize(base_title:, prefixer: nil, commit_message_options: nil, dependencies: nil) | ||||||||||
kbukum1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
| @base_title = base_title | ||||||||||
| @prefixer = prefixer | ||||||||||
| @commit_message_options = commit_message_options | ||||||||||
| @dependencies = dependencies | ||||||||||
| end | ||||||||||
|
|
||||||||||
| # Generates a base title for multi-ecosystem combined PR updates. | ||||||||||
| sig { params(group_name: String, update_count: Integer).returns(String) } | ||||||||||
| def self.multi_ecosystem_base_title(group_name:, update_count:) | ||||||||||
| "bump the \"#{group_name}\" group with " \ | ||||||||||
| "#{update_count} update#{'s' unless update_count == 1} across multiple ecosystems" | ||||||||||
| end | ||||||||||
|
|
||||||||||
| sig { returns(String) } | ||||||||||
| def build | ||||||||||
| name = base_title.dup | ||||||||||
| name[0] = T.must(name[0]).capitalize if capitalize? | ||||||||||
| "#{prefix}#{name}" | ||||||||||
| end | ||||||||||
|
|
||||||||||
| private | ||||||||||
|
|
||||||||||
| sig { returns(String) } | ||||||||||
| def prefix | ||||||||||
| return T.must(prefixer).pr_name_prefix if prefixer | ||||||||||
|
|
||||||||||
| build_explicit_prefix | ||||||||||
| rescue StandardError => e | ||||||||||
| Dependabot.logger.error("Error while generating PR name prefix: #{e.message}") | ||||||||||
| Dependabot.logger.error(e.backtrace&.join("\n")) | ||||||||||
| "" | ||||||||||
| end | ||||||||||
|
|
||||||||||
| sig { returns(T::Boolean) } | ||||||||||
| def capitalize? | ||||||||||
| return T.must(prefixer).capitalize_first_word? if prefixer | ||||||||||
|
|
||||||||||
| false | ||||||||||
| end | ||||||||||
|
|
||||||||||
| # Builds prefix from explicit commit_message_options only. | ||||||||||
| # Same logic as PrNamePrefixer#prefix_from_explicitly_provided_details | ||||||||||
| # but without requiring source/credentials. | ||||||||||
| sig { returns(String) } | ||||||||||
| def build_explicit_prefix | ||||||||||
| return "" unless commit_message_options&.key?(:prefix) | ||||||||||
|
|
||||||||||
| prefix = explicit_prefix_string | ||||||||||
| return "" if prefix.empty? | ||||||||||
|
|
||||||||||
| prefix += "(#{scope})" if commit_message_options&.dig(:include_scope) | ||||||||||
| # Append colon after alphanumeric or closing bracket to follow | ||||||||||
| # conventional commit format (e.g., "chore: ..." or "fix(deps): ...") | ||||||||||
| prefix += ":" if prefix.match?(/[A-Za-z0-9\)\]]\Z/) | ||||||||||
| prefix += " " unless prefix.end_with?(" ") | ||||||||||
| prefix | ||||||||||
| end | ||||||||||
|
|
||||||||||
| sig { returns(String) } | ||||||||||
| def explicit_prefix_string | ||||||||||
| if production_dependencies? | ||||||||||
| commit_message_options&.dig(:prefix).to_s | ||||||||||
| elsif commit_message_options&.key?(:prefix_development) | ||||||||||
| commit_message_options&.dig(:prefix_development).to_s | ||||||||||
| else | ||||||||||
| commit_message_options&.dig(:prefix).to_s | ||||||||||
| end | ||||||||||
| end | ||||||||||
|
|
||||||||||
| sig { returns(T::Boolean) } | ||||||||||
| def production_dependencies? | ||||||||||
| dependencies&.any?(&:production?) != false | ||||||||||
|
||||||||||
| dependencies&.any?(&:production?) != false | |
| return true if dependencies.nil? || dependencies.empty? | |
| dependencies.any?(&:production?) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,230 @@ | ||||||||||||||||||||||||||||||||||||||||||
| # typed: false | ||||||||||||||||||||||||||||||||||||||||||
| # frozen_string_literal: true | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| require "spec_helper" | ||||||||||||||||||||||||||||||||||||||||||
| require "dependabot/pull_request_creator/pr_name_prefixer" | ||||||||||||||||||||||||||||||||||||||||||
| require "dependabot/pull_request_creator/message_builder/title_builder" | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| RSpec.describe Dependabot::PullRequestCreator::MessageBuilder::TitleBuilder do | ||||||||||||||||||||||||||||||||||||||||||
| before do | ||||||||||||||||||||||||||||||||||||||||||
| Dependabot::Dependency.register_production_check( | ||||||||||||||||||||||||||||||||||||||||||
| "npm_and_yarn", | ||||||||||||||||||||||||||||||||||||||||||
| lambda do |groups| | ||||||||||||||||||||||||||||||||||||||||||
| return true if groups.empty? | ||||||||||||||||||||||||||||||||||||||||||
| return true if groups.include?("optionalDependencies") | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| groups.include?("dependencies") | ||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
kbukum1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
+20
|
||||||||||||||||||||||||||||||||||||||||||
| require "dependabot/pull_request_creator/pr_name_prefixer" | |
| require "dependabot/pull_request_creator/message_builder/title_builder" | |
| RSpec.describe Dependabot::PullRequestCreator::MessageBuilder::TitleBuilder do | |
| before do | |
| Dependabot::Dependency.register_production_check( | |
| "npm_and_yarn", | |
| lambda do |groups| | |
| return true if groups.empty? | |
| return true if groups.include?("optionalDependencies") | |
| groups.include?("dependencies") | |
| end | |
| ) | |
| end | |
| require "dependabot/npm_and_yarn" | |
| require "dependabot/pull_request_creator/pr_name_prefixer" | |
| require "dependabot/pull_request_creator/message_builder/title_builder" | |
| RSpec.describe Dependabot::PullRequestCreator::MessageBuilder::TitleBuilder do |
Uh oh!
There was an error while loading. Please reload this page.