gitlab-org--gitlab-foss/app/services/merge_requests/push_options_handler_service.rb
Nick Thomas f9b4d5efbd
Fix MR assignees for push options
With multiple MR assignees, `merge_request.assignee_id` is always nil,
and `merge_request.assignee_ids` isn't in `merge_request.attributes`.
So the existing code doesn't set assignees in the created MR.

This fix gets all the tests passing, but we should also check that no
other associations in the MergeRequest need similar fixups.
2019-04-09 20:40:12 +01:00

162 lines
4.4 KiB
Ruby

# frozen_string_literal: true
module MergeRequests
class PushOptionsHandlerService
LIMIT = 10
attr_reader :branches, :changes_by_branch, :current_user, :errors,
:project, :push_options, :target_project
def initialize(project, current_user, changes, push_options)
@project = project
@target_project = @project.default_merge_request_target
@current_user = current_user
@branches = get_branches(changes)
@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
def get_branches(raw_changes)
Gitlab::ChangesList.new(raw_changes).map do |changes|
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
branch_name
end.compact.uniq
end
def validate_service
errors << 'User is required' if current_user.nil?
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])
errors << "Branch #{push_options[:target]} does not exist"
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(
project,
current_user,
create_params(branch)
).execute
unless merge_request.errors.present?
merge_request = ::MergeRequests::CreateService.new(
project,
current_user,
merge_request.attributes.merge(assignees: merge_request.assignees)
).execute
end
collect_errors_from_merge_request(merge_request) unless merge_request.persisted?
end
def update!(merge_request)
merge_request = ::MergeRequests::UpdateService.new(
target_project,
current_user,
update_params
).execute(merge_request)
collect_errors_from_merge_request(merge_request) unless merge_request.valid?
end
def create_params(branch)
params = {
assignees: [current_user],
source_branch: branch,
source_project: project,
target_branch: push_options[:target] || target_project.default_branch,
target_project: target_project
}
if push_options.key?(:merge_when_pipeline_succeeds)
params.merge!(
merge_when_pipeline_succeeds: push_options[:merge_when_pipeline_succeeds],
merge_user: current_user
)
end
params
end
def update_params
params = {}
if push_options.key?(:merge_when_pipeline_succeeds)
params.merge!(
merge_when_pipeline_succeeds: push_options[:merge_when_pipeline_succeeds],
merge_user: current_user
)
end
if push_options.key?(:target)
params[:target_branch] = push_options[:target]
end
params
end
def collect_errors_from_merge_request(merge_request)
merge_request.errors.full_messages.each do |error|
errors << error
end
end
end
end