b6a9727870
When a merge fails due to a locked file, no feedback was given to the user as to why it failed if the user used the Merge button. However, if the push attempt happened directly in the Web UI, the pre-receive message would be displayed. To be consistent and to make it clear why a merge failed, we now include the pre-receive error message in the merge request widget. Closes https://gitlab.com/gitlab-org/gitlab-ee/issues/10165
128 lines
3.8 KiB
Ruby
128 lines
3.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module MergeRequests
|
|
# MergeService class
|
|
#
|
|
# Do git merge and in case of success
|
|
# mark merge request as merged and execute all hooks and notifications
|
|
# Executed when you do merge via GitLab UI
|
|
#
|
|
class MergeService < MergeRequests::MergeBaseService
|
|
delegate :merge_jid, :state, to: :@merge_request
|
|
|
|
def execute(merge_request)
|
|
if project.merge_requests_ff_only_enabled && !self.is_a?(FfMergeService)
|
|
FfMergeService.new(project, current_user, params).execute(merge_request)
|
|
return
|
|
end
|
|
|
|
@merge_request = merge_request
|
|
|
|
validate!
|
|
|
|
merge_request.in_locked_state do
|
|
if commit
|
|
after_merge
|
|
clean_merge_jid
|
|
success
|
|
end
|
|
end
|
|
log_info("Merge process finished on JID #{merge_jid} with state #{state}")
|
|
rescue MergeError => e
|
|
handle_merge_error(log_message: e.message, save_message_on_model: true)
|
|
end
|
|
|
|
private
|
|
|
|
def validate!
|
|
authorization_check!
|
|
error_check!
|
|
end
|
|
|
|
def authorization_check!
|
|
unless @merge_request.can_be_merged_by?(current_user)
|
|
raise_error('You are not allowed to merge this merge request')
|
|
end
|
|
end
|
|
|
|
def error_check!
|
|
super
|
|
|
|
error =
|
|
if @merge_request.should_be_rebased?
|
|
'Only fast-forward merge is allowed for your project. Please update your source branch'
|
|
elsif !@merge_request.mergeable?
|
|
'Merge request is not mergeable'
|
|
elsif !source
|
|
'No source for merge'
|
|
end
|
|
|
|
raise_error(error) if error
|
|
end
|
|
|
|
def commit
|
|
log_info("Git merge started on JID #{merge_jid}")
|
|
commit_id = try_merge
|
|
|
|
if commit_id
|
|
log_info("Git merge finished on JID #{merge_jid} commit #{commit_id}")
|
|
else
|
|
raise_error('Conflicts detected during merge')
|
|
end
|
|
|
|
merge_request.update!(merge_commit_sha: commit_id)
|
|
end
|
|
|
|
def try_merge
|
|
repository.merge(current_user, source, merge_request, commit_message)
|
|
rescue Gitlab::Git::PreReceiveError => e
|
|
raise_error("Something went wrong during merge pre-receive hook: #{e.message}")
|
|
rescue => e
|
|
handle_merge_error(log_message: e.message)
|
|
raise_error('Something went wrong during merge')
|
|
ensure
|
|
merge_request.update!(in_progress_merge_commit_sha: nil)
|
|
end
|
|
|
|
def after_merge
|
|
log_info("Post merge started on JID #{merge_jid} with state #{state}")
|
|
MergeRequests::PostMergeService.new(project, current_user).execute(merge_request)
|
|
log_info("Post merge finished on JID #{merge_jid} with state #{state}")
|
|
|
|
if delete_source_branch?
|
|
DeleteBranchService.new(@merge_request.source_project, branch_deletion_user)
|
|
.execute(merge_request.source_branch)
|
|
end
|
|
end
|
|
|
|
def clean_merge_jid
|
|
merge_request.update_column(:merge_jid, nil)
|
|
end
|
|
|
|
def branch_deletion_user
|
|
@merge_request.force_remove_source_branch? ? @merge_request.author : current_user
|
|
end
|
|
|
|
# Verify again that the source branch can be removed, since branch may be protected,
|
|
# or the source branch may have been updated, or the user may not have permission
|
|
#
|
|
def delete_source_branch?
|
|
params.fetch('should_remove_source_branch', @merge_request.force_remove_source_branch?) &&
|
|
@merge_request.can_remove_source_branch?(branch_deletion_user)
|
|
end
|
|
|
|
def handle_merge_error(log_message:, save_message_on_model: false)
|
|
Rails.logger.error("MergeService ERROR: #{merge_request_info} - #{log_message}")
|
|
@merge_request.update(merge_error: log_message) if save_message_on_model
|
|
end
|
|
|
|
def log_info(message)
|
|
@logger ||= Rails.logger
|
|
@logger.info("#{merge_request_info} - #{message}")
|
|
end
|
|
|
|
def merge_request_info
|
|
merge_request.to_reference(full: true)
|
|
end
|
|
end
|
|
end
|