2019-01-31 13:32:44 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module MergeRequests
|
|
|
|
# Performs the merge between source SHA and the target branch. Instead
|
|
|
|
# of writing the result to the MR target branch, it targets the `target_ref`.
|
|
|
|
#
|
|
|
|
# Ideally this should leave the `target_ref` state with the same state the
|
|
|
|
# target branch would have if we used the regular `MergeService`, but without
|
|
|
|
# every side-effect that comes with it (MR updates, mails, source branch
|
|
|
|
# deletion, etc). This service should be kept idempotent (i.e. can
|
|
|
|
# be executed regardless of the `target_ref` current state).
|
|
|
|
#
|
|
|
|
class MergeToRefService < MergeRequests::MergeBaseService
|
|
|
|
def execute(merge_request)
|
|
|
|
@merge_request = merge_request
|
|
|
|
|
2019-02-11 10:14:11 -05:00
|
|
|
validate!
|
2019-01-31 13:32:44 -05:00
|
|
|
|
|
|
|
commit_id = commit
|
|
|
|
|
2019-02-11 10:14:11 -05:00
|
|
|
raise_error('Conflicts detected during merge') unless commit_id
|
2019-01-31 13:32:44 -05:00
|
|
|
|
|
|
|
success(commit_id: commit_id)
|
|
|
|
rescue MergeError => error
|
|
|
|
error(error.message)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2019-02-11 10:14:11 -05:00
|
|
|
def validate!
|
|
|
|
authorization_check!
|
|
|
|
error_check!
|
|
|
|
end
|
|
|
|
|
2019-01-31 13:32:44 -05:00
|
|
|
def error_check!
|
2019-02-12 16:21:14 -05:00
|
|
|
super
|
|
|
|
|
2019-01-31 13:32:44 -05:00
|
|
|
error =
|
2019-02-12 05:22:44 -05:00
|
|
|
if Feature.disabled?(:merge_to_tmp_merge_ref_path, project)
|
|
|
|
'Feature is not enabled'
|
|
|
|
elsif !merge_method_supported?
|
2019-01-31 13:32:44 -05:00
|
|
|
"#{project.human_merge_method} to #{target_ref} is currently not supported."
|
|
|
|
elsif !hooks_validation_pass?(merge_request)
|
|
|
|
hooks_validation_error(merge_request)
|
|
|
|
elsif @merge_request.should_be_rebased?
|
|
|
|
'Fast-forward merge is not possible. Please update your source branch.'
|
|
|
|
elsif !@merge_request.mergeable_to_ref?
|
|
|
|
"Merge request is not mergeable to #{target_ref}"
|
|
|
|
elsif !source
|
|
|
|
'No source for merge'
|
|
|
|
end
|
|
|
|
|
2019-02-11 10:14:11 -05:00
|
|
|
raise_error(error) if error
|
|
|
|
end
|
|
|
|
|
|
|
|
def authorization_check!
|
|
|
|
unless Ability.allowed?(current_user, :admin_merge_request, project)
|
|
|
|
raise_error("You are not allowed to merge to this ref")
|
|
|
|
end
|
2019-01-31 13:32:44 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def target_ref
|
|
|
|
merge_request.merge_ref_path
|
|
|
|
end
|
|
|
|
|
|
|
|
def commit
|
|
|
|
repository.merge_to_ref(current_user, source, merge_request, target_ref, commit_message)
|
|
|
|
rescue Gitlab::Git::PreReceiveError => error
|
|
|
|
raise MergeError, error.message
|
|
|
|
end
|
|
|
|
|
|
|
|
def merge_method_supported?
|
|
|
|
[:merge, :rebase_merge].include?(project.merge_method)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|