class Dependabot::PullRequestCreator

def automerge_candidate?

def automerge_candidate?
  @automerge_candidate
end

def azure_creator

def azure_creator
  Azure.new(
    source: source,
    branch_name: branch_namer.new_branch_name,
    base_commit: base_commit,
    credentials: credentials,
    files: files,
    commit_message: T.must(message.commit_message),
    pr_description: T.must(message.pr_message),
    pr_name: T.must(message.pr_name),
    author_details: author_details,
    labeler: labeler,
    reviewers: T.cast(reviewers, AzureReviewers),
    assignees: T.cast(assignees, T.nilable(T::Array[String])),
    work_item: T.cast(provider_metadata&.fetch(:work_item, nil), T.nilable(Integer))
  )
end

def bitbucket_creator

def bitbucket_creator
  Bitbucket.new(
    source: source,
    branch_name: branch_namer.new_branch_name,
    base_commit: base_commit,
    credentials: credentials,
    files: files,
    commit_message: T.must(message.commit_message),
    pr_description: T.must(message.pr_message),
    pr_name: T.must(message.pr_name),
    author_details: author_details,
    labeler: nil,
    work_item: T.cast(provider_metadata&.fetch(:work_item, nil), T.nilable(Integer))
  )
end

def branch_namer

def branch_namer
  @branch_namer ||= T.let(
    BranchNamer.new(
      dependencies: dependencies,
      files: files,
      target_branch: source.branch,
      dependency_group: dependency_group,
      separator: branch_name_separator,
      prefix: branch_name_prefix,
      max_length: branch_name_max_length,
      includes_security_fixes: includes_security_fixes?
    ),
    T.nilable(Dependabot::PullRequestCreator::BranchNamer)
  )
end

def check_dependencies_have_previous_version

def check_dependencies_have_previous_version
  return if dependencies.all? { |d| requirements_changed?(d) }
  return if dependencies.all?(&:previous_version)
  raise "Dependencies must have a previous version or changed " \
        "requirement to have a pull request created for them!"
end

def codecommit_creator

def codecommit_creator
  Codecommit.new(
    source: source,
    branch_name: branch_namer.new_branch_name,
    base_commit: base_commit,
    credentials: credentials,
    files: files,
    commit_message: T.must(message.commit_message),
    pr_description: T.must(message.pr_message),
    pr_name: T.must(message.pr_name),
    author_details: author_details,
    labeler: labeler,
    require_up_to_date_base: require_up_to_date_base?
  )
end

def create

def create
  case source.provider
  when "github" then github_creator.create
  when "gitlab" then gitlab_creator.create
  when "azure" then azure_creator.create
  when "bitbucket" then bitbucket_creator.create
  when "codecommit" then codecommit_creator.create
  else raise "Unsupported provider #{source.provider}"
  end
end

def github_creator

def github_creator
  Github.new(
    source: source,
    branch_name: branch_namer.new_branch_name,
    base_commit: base_commit,
    credentials: credentials,
    files: files,
    commit_message: T.must(message.commit_message),
    pr_description: T.must(message.pr_message),
    pr_name: T.must(message.pr_name),
    author_details: author_details,
    signature_key: signature_key,
    labeler: labeler,
    reviewers: T.cast(reviewers, GithubReviewers),
    assignees: T.cast(assignees, T.nilable(T::Array[String])),
    milestone: T.cast(milestone, T.nilable(Integer)),
    custom_headers: custom_headers,
    require_up_to_date_base: require_up_to_date_base?
  )
end

def gitlab_creator

def gitlab_creator
  Gitlab.new(
    source: source,
    branch_name: branch_namer.new_branch_name,
    base_commit: base_commit,
    credentials: credentials,
    files: files,
    commit_message: T.must(message.commit_message),
    pr_description: T.must(message.pr_message),
    pr_name: T.must(message.pr_name),
    author_details: author_details,
    labeler: labeler,
    approvers: T.cast(reviewers, T.nilable(T::Hash[Symbol, T::Array[Integer]])),
    assignees: T.cast(assignees, T.nilable(T::Array[Integer])),
    milestone: milestone,
    target_project_id: T.cast(provider_metadata&.fetch(:target_project_id, nil), T.nilable(Integer))
  )
end

def includes_security_fixes?

def includes_security_fixes?
  vulnerabilities_fixed.values.flatten.any?
end

def initialize(source:, base_commit:, dependencies:, files:, credentials:,

def initialize(source:, base_commit:, dependencies:, files:, credentials:,
               pr_message_header: nil, pr_message_footer: nil,
               custom_labels: nil, author_details: nil, signature_key: nil,
               commit_message_options: {}, vulnerabilities_fixed: {},
               reviewers: nil, assignees: nil, milestone: nil, branch_name_separator: "/",
               branch_name_prefix: "dependabot", branch_name_max_length: nil,
               label_language: false, automerge_candidate: false,
               github_redirection_service: DEFAULT_GITHUB_REDIRECTION_SERVICE,
               custom_headers: nil, require_up_to_date_base: false,
               provider_metadata: {}, message: nil, dependency_group: nil, pr_message_max_length: nil,
               pr_message_encoding: nil)
  @dependencies               = dependencies
  @source                     = source
  @base_commit                = base_commit
  @files                      = files
  @credentials                = credentials
  @pr_message_header          = pr_message_header
  @pr_message_footer          = pr_message_footer
  @author_details             = author_details
  @signature_key              = signature_key
  @commit_message_options     = commit_message_options
  @custom_labels              = custom_labels
  @reviewers                  = reviewers
  @assignees                  = assignees
  @milestone                  = milestone
  @vulnerabilities_fixed      = vulnerabilities_fixed
  @branch_name_separator      = branch_name_separator
  @branch_name_prefix         = branch_name_prefix
  @branch_name_max_length     = branch_name_max_length
  @label_language             = label_language
  @automerge_candidate        = automerge_candidate
  @github_redirection_service = github_redirection_service
  @custom_headers             = custom_headers
  @require_up_to_date_base    = require_up_to_date_base
  @provider_metadata          = provider_metadata
  @message                    = message
  @dependency_group           = dependency_group
  @pr_message_max_length      = pr_message_max_length
  @pr_message_encoding        = pr_message_encoding
  check_dependencies_have_previous_version
end

def label_language?

def label_language?
  @label_language
end

def labeler

def labeler
  @labeler ||= T.let(
    Labeler.new(
      source: source,
      custom_labels: custom_labels,
      credentials: credentials,
      includes_security_fixes: includes_security_fixes?,
      dependencies: dependencies,
      label_language: label_language?,
      automerge_candidate: automerge_candidate?
    ),
    T.nilable(Dependabot::PullRequestCreator::Labeler)
  )
end

def message

def message
  return @message unless @message.nil?
  case source.provider
  when "github"
    @pr_message_max_length = Github::PR_DESCRIPTION_MAX_LENGTH if @pr_message_max_length.nil?
  when "azure"
    @pr_message_max_length = Azure::PR_DESCRIPTION_MAX_LENGTH if @pr_message_max_length.nil?
    @pr_message_encoding = Azure::PR_DESCRIPTION_ENCODING if @pr_message_encoding.nil?
  when "codecommit"
    @pr_message_max_length = Codecommit::PR_DESCRIPTION_MAX_LENGTH if @pr_message_max_length.nil?
  when "bitbucket"
    @pr_message_max_length = Bitbucket::PR_DESCRIPTION_MAX_LENGTH if @pr_message_max_length.nil?
  end
  @message = MessageBuilder.new(
    source: source,
    dependencies: dependencies,
    files: files,
    credentials: credentials,
    commit_message_options: commit_message_options,
    pr_message_header: pr_message_header,
    pr_message_footer: pr_message_footer,
    vulnerabilities_fixed: vulnerabilities_fixed,
    github_redirection_service: github_redirection_service,
    dependency_group: dependency_group,
    pr_message_max_length: pr_message_max_length,
    pr_message_encoding: pr_message_encoding
  )
end

def require_up_to_date_base?

def require_up_to_date_base?
  @require_up_to_date_base
end

def requirements_changed?(dependency)

def requirements_changed?(dependency)
  (dependency.requirements - T.must(dependency.previous_requirements)).any?
end