e34a321327
When the GitHub importer creates a merge request, it retrieves the SHA but does not actually create the source branch. This makes it impossible to merge an open merge request, particularly if the source branch were from a forked project. In that case, the branch will never exist because the original `project-name:source-branch` name is never created, nor is it a valid branch name. To prevent possible branch name conflicts, forked source branches are now renamed `github/fork/project-name/source-branch` and created when necessary. Note that we only create the source branch if the merge request is open. For projects that have many merge requests, the project would end up with a lot of possibly dead branches. Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/57370
114 lines
3.6 KiB
Ruby
114 lines
3.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module GithubImport
|
|
module Representation
|
|
class PullRequest
|
|
include ToHash
|
|
include ExposeAttribute
|
|
|
|
attr_reader :attributes
|
|
|
|
expose_attribute :iid, :title, :description, :source_branch,
|
|
:source_branch_sha, :target_branch, :target_branch_sha,
|
|
:milestone_number, :author, :assignee, :created_at,
|
|
:updated_at, :merged_at, :source_repository_id,
|
|
:target_repository_id, :source_repository_owner
|
|
|
|
# Builds a PR from a GitHub API response.
|
|
#
|
|
# issue - An instance of `Sawyer::Resource` containing the PR details.
|
|
def self.from_api_response(pr)
|
|
assignee =
|
|
if pr.assignee
|
|
Representation::User.from_api_response(pr.assignee)
|
|
end
|
|
|
|
user = Representation::User.from_api_response(pr.user) if pr.user
|
|
hash = {
|
|
iid: pr.number,
|
|
title: pr.title,
|
|
description: pr.body,
|
|
source_branch: pr.head.ref,
|
|
target_branch: pr.base.ref,
|
|
source_branch_sha: pr.head.sha,
|
|
target_branch_sha: pr.base.sha,
|
|
source_repository_id: pr.head&.repo&.id,
|
|
target_repository_id: pr.base&.repo&.id,
|
|
source_repository_owner: pr.head&.user&.login,
|
|
state: pr.state == 'open' ? :opened : :closed,
|
|
milestone_number: pr.milestone&.number,
|
|
author: user,
|
|
assignee: assignee,
|
|
created_at: pr.created_at,
|
|
updated_at: pr.updated_at,
|
|
merged_at: pr.merged_at
|
|
}
|
|
|
|
new(hash)
|
|
end
|
|
|
|
# Builds a new PR using a Hash that was built from a JSON payload.
|
|
def self.from_json_hash(raw_hash)
|
|
hash = Representation.symbolize_hash(raw_hash)
|
|
|
|
hash[:state] = hash[:state].to_sym
|
|
hash[:author] &&= Representation::User.from_json_hash(hash[:author])
|
|
|
|
# Assignees are optional so we only convert it from a Hash if one was
|
|
# set.
|
|
hash[:assignee] &&= Representation::User
|
|
.from_json_hash(hash[:assignee])
|
|
|
|
new(hash)
|
|
end
|
|
|
|
# attributes - A Hash containing the raw PR details. The keys of this
|
|
# Hash (and any nested hashes) must be symbols.
|
|
def initialize(attributes)
|
|
@attributes = attributes
|
|
end
|
|
|
|
def truncated_title
|
|
title.truncate(255)
|
|
end
|
|
|
|
# Returns a formatted source branch.
|
|
#
|
|
# For cross-project pull requests the branch name will be in the format
|
|
# `github/fork/owner-name/branch-name`.
|
|
def formatted_source_branch
|
|
if cross_project? && source_repository_owner
|
|
"github/fork/#{source_repository_owner}/#{source_branch}"
|
|
elsif source_branch == target_branch
|
|
# Sometimes the source and target branch are the same, but GitLab
|
|
# doesn't support this. This can happen when both the user and
|
|
# source repository have been deleted, and the PR was submitted from
|
|
# the fork's master branch.
|
|
"#{source_branch}-#{iid}"
|
|
else
|
|
source_branch
|
|
end
|
|
end
|
|
|
|
def state
|
|
if merged_at
|
|
:merged
|
|
else
|
|
attributes[:state]
|
|
end
|
|
end
|
|
|
|
def cross_project?
|
|
return true unless source_repository_id
|
|
|
|
source_repository_id != target_repository_id
|
|
end
|
|
|
|
def issuable_type
|
|
'MergeRequest'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|