ad2bfeb857
I don't know why this happens exactly, but given an upstream and fork repository from a customer, both of which required GC, resolving conflicts would corrupt the fork so badly that it couldn't be cloned. This isn't a perfect fix for that case, because the MR may still need to be merged manually, but it does ensure that the repository is at least usable. My best guess is that when we generate the index for the conflict resolution (which we previously did in the target project), we obtain a reference to an OID that doesn't exist in the source, even though we already fetch the refs from the target into the source. Explicitly setting the source project as the place to get the merge index from seems to prevent repository corruption in this way.
172 lines
5.4 KiB
Ruby
172 lines
5.4 KiB
Ruby
class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
|
|
include ActionView::Helpers::UrlHelper
|
|
include GitlabRoutingHelper
|
|
include MarkupHelper
|
|
include TreeHelper
|
|
|
|
presents :merge_request
|
|
|
|
def ci_status
|
|
if pipeline
|
|
status = pipeline.status
|
|
status = "success_with_warnings" if pipeline.success? && pipeline.has_warnings?
|
|
|
|
status || "preparing"
|
|
else
|
|
ci_service = source_project.try(:ci_service)
|
|
ci_service&.commit_status(diff_head_sha, source_branch)
|
|
end
|
|
end
|
|
|
|
def cancel_merge_when_pipeline_succeeds_path
|
|
if can_cancel_merge_when_pipeline_succeeds?(current_user)
|
|
cancel_merge_when_pipeline_succeeds_namespace_project_merge_request_path(
|
|
project.namespace,
|
|
project,
|
|
merge_request)
|
|
end
|
|
end
|
|
|
|
def create_issue_to_resolve_discussions_path
|
|
if can?(current_user, :create_issue, project) && project.issues_enabled?
|
|
new_namespace_project_issue_path(project.namespace,
|
|
project,
|
|
merge_request_to_resolve_discussions_of: iid)
|
|
end
|
|
end
|
|
|
|
def remove_wip_path
|
|
if can?(current_user, :update_merge_request, merge_request.project)
|
|
remove_wip_namespace_project_merge_request_path(project.namespace, project, merge_request)
|
|
end
|
|
end
|
|
|
|
def merge_path
|
|
if can_be_merged_by?(current_user)
|
|
merge_namespace_project_merge_request_path(project.namespace, project, merge_request)
|
|
end
|
|
end
|
|
|
|
def revert_in_fork_path
|
|
if user_can_fork_project? && can_be_reverted?(current_user)
|
|
continue_params = {
|
|
to: merge_request_path(merge_request),
|
|
notice: "#{edit_in_new_fork_notice} Try to cherry-pick this commit again.",
|
|
notice_now: edit_in_new_fork_notice_now
|
|
}
|
|
|
|
namespace_project_forks_path(merge_request.project.namespace, merge_request.project,
|
|
namespace_key: current_user.namespace.id,
|
|
continue: continue_params)
|
|
end
|
|
end
|
|
|
|
def cherry_pick_in_fork_path
|
|
if user_can_fork_project? && can_be_cherry_picked?
|
|
continue_params = {
|
|
to: merge_request_path(merge_request),
|
|
notice: "#{edit_in_new_fork_notice} Try to revert this commit again.",
|
|
notice_now: edit_in_new_fork_notice_now
|
|
}
|
|
|
|
namespace_project_forks_path(project.namespace, project,
|
|
namespace_key: current_user.namespace.id,
|
|
continue: continue_params)
|
|
end
|
|
end
|
|
|
|
def conflict_resolution_path
|
|
if conflicts.can_be_resolved_in_ui? && conflicts.can_be_resolved_by?(current_user)
|
|
conflicts_namespace_project_merge_request_path(project.namespace, project, merge_request)
|
|
end
|
|
end
|
|
|
|
def target_branch_commits_path
|
|
if target_branch_exists?
|
|
namespace_project_commits_path(project.namespace, project, target_branch)
|
|
end
|
|
end
|
|
|
|
def source_branch_path
|
|
if source_branch_exists?
|
|
namespace_project_branch_path(source_project.namespace, source_project, source_branch)
|
|
end
|
|
end
|
|
|
|
def source_branch_with_namespace_link
|
|
namespace = source_project_namespace
|
|
branch = source_branch
|
|
|
|
if source_branch_exists?
|
|
namespace = link_to(namespace, project_path(source_project))
|
|
branch = link_to(branch, namespace_project_commits_path(source_project.namespace, source_project, source_branch))
|
|
end
|
|
|
|
if for_fork?
|
|
namespace + ":" + branch
|
|
else
|
|
branch
|
|
end
|
|
end
|
|
|
|
def closing_issues_links
|
|
markdown issues_sentence(project, closing_issues), pipeline: :gfm, author: author, project: project
|
|
end
|
|
|
|
def mentioned_issues_links
|
|
mentioned_issues = issues_mentioned_but_not_closing(current_user)
|
|
markdown issues_sentence(project, mentioned_issues), pipeline: :gfm, author: author, project: project
|
|
end
|
|
|
|
def assign_to_closing_issues_link
|
|
issues = MergeRequests::AssignIssuesService.new(project,
|
|
current_user,
|
|
merge_request: merge_request,
|
|
closes_issues: closing_issues
|
|
).assignable_issues
|
|
path = assign_related_issues_namespace_project_merge_request_path(project.namespace, project, merge_request)
|
|
if issues.present?
|
|
pluralize_this_issue = issues.count > 1 ? "these issues" : "this issue"
|
|
link_to "Assign yourself to #{pluralize_this_issue}", path, method: :post
|
|
end
|
|
end
|
|
|
|
def can_revert_on_current_merge_request?
|
|
user_can_collaborate_with_project? && can_be_reverted?(current_user)
|
|
end
|
|
|
|
def can_cherry_pick_on_current_merge_request?
|
|
user_can_collaborate_with_project? && can_be_cherry_picked?
|
|
end
|
|
|
|
private
|
|
|
|
def conflicts
|
|
@conflicts ||= MergeRequests::Conflicts::ListService.new(merge_request)
|
|
end
|
|
|
|
def closing_issues
|
|
@closing_issues ||= closes_issues(current_user)
|
|
end
|
|
|
|
def pipeline
|
|
@pipeline ||= head_pipeline
|
|
end
|
|
|
|
def issues_sentence(project, issues)
|
|
# Sorting based on the `#123` or `group/project#123` reference will sort
|
|
# local issues first.
|
|
issues.map do |issue|
|
|
issue.to_reference(project)
|
|
end.sort.to_sentence
|
|
end
|
|
|
|
def user_can_collaborate_with_project?
|
|
can?(current_user, :push_code, project) ||
|
|
(current_user && current_user.already_forked?(project))
|
|
end
|
|
|
|
def user_can_fork_project?
|
|
can?(current_user, :fork_project, project)
|
|
end
|
|
end
|