summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2018-07-03 16:37:17 -0700
committerStan Hu <stanhu@gmail.com>2018-07-03 16:37:17 -0700
commitd3c75ea4d916e0c81de2e8f7c5b1d748af9fa45e (patch)
treedd51512d9c007743cb6bf7d01af1c6b6c9e12c2e
parent5f362686ca20f2ff81f5c86a6f9be9b31177c62b (diff)
downloadgitlab-ce-d3c75ea4d916e0c81de2e8f7c5b1d748af9fa45e.tar.gz
Support creating a remote branch to import closed pull requests
-rw-r--r--lib/bitbucket_server/client.rb10
-rw-r--r--lib/bitbucket_server/connection.rb16
-rw-r--r--lib/gitlab/bitbucket_server_import/importer.rb58
3 files changed, 82 insertions, 2 deletions
diff --git a/lib/bitbucket_server/client.rb b/lib/bitbucket_server/client.rb
index e632adea68c..49654e45226 100644
--- a/lib/bitbucket_server/client.rb
+++ b/lib/bitbucket_server/client.rb
@@ -27,6 +27,16 @@ module BitbucketServer
get_collection(path, :repo)
end
+ def create_branch(project_key, repo, branch_name, sha)
+ payload = {
+ name: branch_name,
+ startPoint: sha,
+ message: 'GitLab temporary branch for import'
+ }
+
+ connection.post("/projects/#{project_key}/repos/#{repo}/branches", payload.to_json)
+ end
+
private
def get_collection(path, type)
diff --git a/lib/bitbucket_server/connection.rb b/lib/bitbucket_server/connection.rb
index 5c3bea3b743..21807c8a229 100644
--- a/lib/bitbucket_server/connection.rb
+++ b/lib/bitbucket_server/connection.rb
@@ -12,7 +12,6 @@ module BitbucketServer
end
def get(path, extra_query = {})
- auth = { username: username, password: token }
response = Gitlab::HTTP.get(build_url(path),
basic_auth: auth,
params: extra_query)
@@ -20,8 +19,23 @@ module BitbucketServer
response.parsed_response
end
+ def post(path, body)
+ Gitlab::HTTP.post(build_url(path),
+ basic_auth: auth,
+ headers: post_headers,
+ body: body)
+ end
+
private
+ def auth
+ @auth ||= { username: username, password: token }
+ end
+
+ def post_headers
+ @post_headers ||= { 'Content-Type' => 'application/json' }
+ end
+
def build_url(path)
return path if path.starts_with?(root_url)
diff --git a/lib/gitlab/bitbucket_server_import/importer.rb b/lib/gitlab/bitbucket_server_import/importer.rb
index 84d16074891..2a33feb68a9 100644
--- a/lib/gitlab/bitbucket_server_import/importer.rb
+++ b/lib/gitlab/bitbucket_server_import/importer.rb
@@ -4,6 +4,16 @@ module Gitlab
include Gitlab::ShellAdapter
attr_reader :project, :project_key, :repository_slug, :client, :errors, :users
+ REMOTE_NAME = 'bitbucket_server'.freeze
+
+ def self.imports_repository?
+ true
+ end
+
+ def self.refmap
+ [:heads, :tags, '+refs/pull-requests/*/to:refs/merge-requests/*/head']
+ end
+
def initialize(project)
@project = project
@project_key = project.import_data.data['project_key']
@@ -12,9 +22,11 @@ module Gitlab
@formatter = Gitlab::ImportFormatter.new
@errors = []
@users = {}
+ @temp_branches = []
end
def execute
+ import_repository
import_pull_requests
handle_errors
@@ -48,11 +60,55 @@ module Gitlab
@repo ||= client.repo(project_key, repository_slug)
end
+ def sha_exists?(sha)
+ project.repository.commit(sha)
+ end
+
+ def track_temp_branch(pull_request, index)
+ temp_branch_name = "gitlab/import/pull-request/#{pull_request.iid}-#{index}"
+
+ @temp_branches << temp_branch_name
+ temp_branch_name
+ end
+
+ def restore_branches(pull_request)
+ shas_to_restore = [pull_request.source_branch_sha, pull_request.target_branch_sha]
+ resync = false
+
+ shas_to_restore.each_with_index do |sha, index|
+ next if sha_exists?(sha)
+
+ branch_name = track_temp_branch(pull_request, index)
+ response = client.create_branch(project_key, repository_slug, branch_name, sha)
+
+ if response.success?
+ resync = true
+ else
+ Rails.logger.warn("BitbucketServerImporter: Unable to recreate branch for SHA #{sha}: #{response.code}")
+ end
+ end
+
+ import_repository if resync
+ end
+
+ def import_repository
+ project.ensure_repository
+ project.repository.fetch_as_mirror(project.import_url, refmap: self.class.refmap, remote_name: REMOTE_NAME)
+ rescue Gitlab::Shell::Error, Gitlab::Git::RepositoryMirroring::RemoteError => e
+ # Expire cache to prevent scenarios such as:
+ # 1. First import failed, but the repo was imported successfully, so +exists?+ returns true
+ # 2. Retried import, repo is broken or not imported but +exists?+ still returns true
+ project.repository.expire_content_cache if project.repository_exists?
+
+ raise RuntimeError, e.message
+ end
+
def import_pull_requests
pull_requests = client.pull_requests(project_key, repository_slug)
-
pull_requests.each do |pull_request|
begin
+ restore_branches(pull_request)
+
description = ''
description += @formatter.author_line(pull_request.author) unless find_user_id(pull_request.author_email)
description += pull_request.description