debian-mirror-gitlab/app/services/merge_requests/push_options_handler_service.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

211 lines
6.3 KiB
Ruby
Raw Normal View History

2019-07-07 11:18:12 +05:30
# frozen_string_literal: true
module MergeRequests
2021-06-08 01:23:25 +05:30
class PushOptionsHandlerService < ::BaseProjectService
2019-07-07 11:18:12 +05:30
LIMIT = 10
2023-07-09 08:55:56 +05:30
attr_reader :errors, :changes, :push_options, :target_project
2021-06-08 01:23:25 +05:30
2023-03-04 22:38:38 +05:30
def initialize(project:, current_user:, changes:, push_options:, params: {})
2021-06-08 01:23:25 +05:30
super(project: project, current_user: current_user, params: params)
2019-07-07 11:18:12 +05:30
@target_project = @project.default_merge_request_target
2019-12-26 22:10:19 +05:30
@changes = Gitlab::ChangesList.new(changes)
2019-07-07 11:18:12 +05:30
@push_options = push_options
@errors = []
end
def execute
validate_service
return self if errors.present?
branches.each do |branch|
execute_for_branch(branch)
rescue Gitlab::Access::AccessDeniedError
errors << 'User access was denied'
rescue StandardError => e
Gitlab::AppLogger.error(e)
errors << 'An unknown error occurred'
end
self
end
private
2019-12-26 22:10:19 +05:30
def branches
changes_by_branch.keys
end
def changes_by_branch
@changes_by_branch ||= changes.each_with_object({}) do |changes, result|
2019-07-07 11:18:12 +05:30
next unless Gitlab::Git.branch_ref?(changes[:ref])
# Deleted branch
next if Gitlab::Git.blank_ref?(changes[:newrev])
# Default branch
branch_name = Gitlab::Git.branch_name(changes[:ref])
next if branch_name == target_project.default_branch
2019-12-26 22:10:19 +05:30
result[branch_name] = changes
end
2019-07-07 11:18:12 +05:30
end
def validate_service
2023-05-08 21:46:49 +05:30
if current_user.nil?
errors << 'User is required'
return
end
unless current_user&.can?(:read_code, target_project)
errors << 'User access was denied'
return
end
2019-07-07 11:18:12 +05:30
unless target_project.merge_requests_enabled?
errors << "Merge requests are not enabled for project #{target_project.full_path}"
end
if branches.size > LIMIT
errors << "Too many branches pushed (#{branches.size} were pushed, limit is #{LIMIT})"
end
if push_options[:target] && !target_project.repository.branch_exists?(push_options[:target])
2021-10-27 15:23:28 +05:30
errors << "Target branch #{target_project.full_path}:#{push_options[:target]} does not exist"
2019-07-07 11:18:12 +05:30
end
end
# Returns a Hash of branch => MergeRequest
def merge_requests
@merge_requests ||= MergeRequest.from_project(target_project)
.opened
.from_source_branches(branches)
.index_by(&:source_branch)
end
def execute_for_branch(branch)
merge_request = merge_requests[branch]
if merge_request
update!(merge_request)
else
create!(branch)
end
end
def create!(branch)
unless push_options[:create]
errors << "A merge_request.create push option is required to create a merge request for branch #{branch}"
return
end
# Use BuildService to assign the standard attributes of a merge request
merge_request = ::MergeRequests::BuildService.new(
2021-06-08 01:23:25 +05:30
project: project,
current_user: current_user,
params: create_params(branch)
2019-07-07 11:18:12 +05:30
).execute
unless merge_request.errors.present?
merge_request = ::MergeRequests::CreateService.new(
2021-06-08 01:23:25 +05:30
project: project,
current_user: current_user,
2023-07-09 08:55:56 +05:30
params: merge_request.attributes.merge(
assignee_ids: merge_request.assignee_ids,
label_ids: merge_request.label_ids
)
2019-07-07 11:18:12 +05:30
).execute
end
collect_errors_from_merge_request(merge_request) unless merge_request.persisted?
end
def update!(merge_request)
merge_request = ::MergeRequests::UpdateService.new(
2021-06-08 01:23:25 +05:30
project: target_project,
current_user: current_user,
params: update_params(merge_request)
2019-07-07 11:18:12 +05:30
).execute(merge_request)
collect_errors_from_merge_request(merge_request) unless merge_request.valid?
end
2019-10-12 21:52:04 +05:30
def base_params
2019-07-07 11:18:12 +05:30
params = {
2019-10-12 21:52:04 +05:30
title: push_options[:title],
description: push_options[:description],
2022-07-16 23:28:13 +05:30
draft: push_options[:draft],
2019-10-12 21:52:04 +05:30
target_branch: push_options[:target],
2019-12-04 20:38:33 +05:30
force_remove_source_branch: push_options[:remove_source_branch],
label: push_options[:label],
2021-04-29 21:17:54 +05:30
unlabel: push_options[:unlabel],
assign: push_options[:assign],
unassign: push_options[:unassign]
2019-07-07 11:18:12 +05:30
}
2019-10-12 21:52:04 +05:30
params.compact!
2019-12-04 20:38:33 +05:30
params[:add_labels] = params.delete(:label).keys if params.has_key?(:label)
params[:remove_labels] = params.delete(:unlabel).keys if params.has_key?(:unlabel)
2022-11-25 23:54:43 +05:30
params[:add_assignee_ids] = convert_to_user_ids(params.delete(:assign).keys) if params.has_key?(:assign)
params[:remove_assignee_ids] = convert_to_user_ids(params.delete(:unassign).keys) if params.has_key?(:unassign)
2021-04-29 21:17:54 +05:30
2021-09-30 23:02:18 +05:30
if push_options[:milestone]
milestone = Milestone.for_projects_and_groups(@project, @project.ancestors_upto)&.find_by_name(push_options[:milestone])
2023-04-23 21:23:45 +05:30
params[:milestone_id] = milestone.id if milestone
2021-09-30 23:02:18 +05:30
end
2022-07-16 23:28:13 +05:30
if params.key?(:description)
params[:description] = params[:description].gsub('\n', "\n")
end
2019-07-07 11:18:12 +05:30
params
end
2019-12-26 22:10:19 +05:30
def merge_params(branch)
return {} unless push_options.key?(:merge_when_pipeline_succeeds)
{
merge_when_pipeline_succeeds: push_options[:merge_when_pipeline_succeeds],
merge_user: current_user,
sha: changes_by_branch.dig(branch, :newrev)
}
end
2019-10-12 21:52:04 +05:30
def create_params(branch)
params = base_params
2019-07-07 11:18:12 +05:30
2019-10-12 21:52:04 +05:30
params.merge!(
2022-11-25 23:54:43 +05:30
assignee_ids: [current_user.id],
2019-10-12 21:52:04 +05:30
source_branch: branch,
source_project: project,
target_project: target_project
)
2019-07-07 11:18:12 +05:30
2019-12-26 22:10:19 +05:30
params.merge!(merge_params(branch))
2019-10-12 21:52:04 +05:30
params[:target_branch] ||= target_project.default_branch
2019-07-07 11:18:12 +05:30
params
end
2019-12-26 22:10:19 +05:30
def update_params(merge_request)
base_params.merge(merge_params(merge_request.source_branch))
2019-10-12 21:52:04 +05:30
end
2022-11-25 23:54:43 +05:30
def convert_to_user_ids(ids_or_usernames)
ids, usernames = ids_or_usernames.partition { |id_or_username| id_or_username.is_a?(Numeric) || id_or_username.match?(/\A\d+\z/) }
ids += User.by_username(usernames).pluck(:id) unless usernames.empty? # rubocop:disable CodeReuse/ActiveRecord
ids
end
2019-07-07 11:18:12 +05:30
def collect_errors_from_merge_request(merge_request)
merge_request.errors.full_messages.each do |error|
errors << error
end
end
end
end