Merge branch 'feature/migrate-rebase-to-gitaly' into 'master'
Migrate Gitlab::Git::Repository#rebase to Gitaly Closes gitaly#863 See merge request gitlab-org/gitlab-ce!16259
This commit is contained in:
commit
587242656f
|
|
@ -1236,28 +1236,20 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:)
|
def rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:)
|
||||||
rebase_path = worktree_path(REBASE_WORKTREE_PREFIX, rebase_id)
|
gitaly_migrate(:rebase) do |is_enabled|
|
||||||
env = git_env_for_user(user)
|
if is_enabled
|
||||||
|
gitaly_rebase(user, rebase_id,
|
||||||
if remote_repository.is_a?(RemoteRepository)
|
branch: branch,
|
||||||
env.merge!(remote_repository.fetch_env)
|
branch_sha: branch_sha,
|
||||||
remote_repo_path = GITALY_INTERNAL_URL
|
remote_repository: remote_repository,
|
||||||
else
|
remote_branch: remote_branch)
|
||||||
remote_repo_path = remote_repository.path
|
else
|
||||||
end
|
git_rebase(user, rebase_id,
|
||||||
|
branch: branch,
|
||||||
with_worktree(rebase_path, branch, env: env) do
|
branch_sha: branch_sha,
|
||||||
run_git!(
|
remote_repository: remote_repository,
|
||||||
%W(pull --rebase #{remote_repo_path} #{remote_branch}),
|
remote_branch: remote_branch)
|
||||||
chdir: rebase_path, env: env
|
end
|
||||||
)
|
|
||||||
|
|
||||||
rebase_sha = run_git!(%w(rev-parse HEAD), chdir: rebase_path, env: env).strip
|
|
||||||
|
|
||||||
Gitlab::Git::OperationService.new(user, self)
|
|
||||||
.update_branch(branch, rebase_sha, branch_sha)
|
|
||||||
|
|
||||||
rebase_sha
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -2039,6 +2031,40 @@ module Gitlab
|
||||||
tree_id
|
tree_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def gitaly_rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:)
|
||||||
|
gitaly_operation_client.user_rebase(user, rebase_id,
|
||||||
|
branch: branch,
|
||||||
|
branch_sha: branch_sha,
|
||||||
|
remote_repository: remote_repository,
|
||||||
|
remote_branch: remote_branch)
|
||||||
|
end
|
||||||
|
|
||||||
|
def git_rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:)
|
||||||
|
rebase_path = worktree_path(REBASE_WORKTREE_PREFIX, rebase_id)
|
||||||
|
env = git_env_for_user(user)
|
||||||
|
|
||||||
|
if remote_repository.is_a?(RemoteRepository)
|
||||||
|
env.merge!(remote_repository.fetch_env)
|
||||||
|
remote_repo_path = GITALY_INTERNAL_URL
|
||||||
|
else
|
||||||
|
remote_repo_path = remote_repository.path
|
||||||
|
end
|
||||||
|
|
||||||
|
with_worktree(rebase_path, branch, env: env) do
|
||||||
|
run_git!(
|
||||||
|
%W(pull --rebase #{remote_repo_path} #{remote_branch}),
|
||||||
|
chdir: rebase_path, env: env
|
||||||
|
)
|
||||||
|
|
||||||
|
rebase_sha = run_git!(%w(rev-parse HEAD), chdir: rebase_path, env: env).strip
|
||||||
|
|
||||||
|
Gitlab::Git::OperationService.new(user, self)
|
||||||
|
.update_branch(branch, rebase_sha, branch_sha)
|
||||||
|
|
||||||
|
rebase_sha
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def local_fetch_ref(source_path, source_ref:, target_ref:)
|
def local_fetch_ref(source_path, source_ref:, target_ref:)
|
||||||
args = %W(fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
|
args = %W(fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
|
||||||
run_git(args)
|
run_git(args)
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,34 @@ module Gitlab
|
||||||
start_repository: start_repository)
|
start_repository: start_repository)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:)
|
||||||
|
request = Gitaly::UserRebaseRequest.new(
|
||||||
|
repository: @gitaly_repo,
|
||||||
|
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
|
||||||
|
rebase_id: rebase_id.to_s,
|
||||||
|
branch: encode_binary(branch),
|
||||||
|
branch_sha: branch_sha,
|
||||||
|
remote_repository: remote_repository.gitaly_repository,
|
||||||
|
remote_branch: encode_binary(remote_branch)
|
||||||
|
)
|
||||||
|
|
||||||
|
response = GitalyClient.call(
|
||||||
|
@repository.storage,
|
||||||
|
:operation_service,
|
||||||
|
:user_rebase,
|
||||||
|
request,
|
||||||
|
remote_storage: remote_repository.storage
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.pre_receive_error.presence
|
||||||
|
raise Gitlab::Git::HooksService::PreReceiveError, response.pre_receive_error
|
||||||
|
elsif response.git_error.presence
|
||||||
|
raise Gitlab::Git::Repository::GitError, response.git_error
|
||||||
|
else
|
||||||
|
response.rebase_sha
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def call_cherry_pick_or_revert(rpc, user:, commit:, branch_name:, message:, start_branch_name:, start_repository:)
|
def call_cherry_pick_or_revert(rpc, user:, commit:, branch_name:, message:, start_branch_name:, start_repository:)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ describe MergeRequests::RebaseService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when unexpected error occurs' do
|
context 'when unexpected error occurs', :disable_gitaly do
|
||||||
before do
|
before do
|
||||||
allow(repository).to receive(:run_git!).and_raise('Something went wrong')
|
allow(repository).to receive(:run_git!).and_raise('Something went wrong')
|
||||||
end
|
end
|
||||||
|
|
@ -53,7 +53,7 @@ describe MergeRequests::RebaseService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with git command failure' do
|
context 'with git command failure', :disable_gitaly do
|
||||||
before do
|
before do
|
||||||
allow(repository).to receive(:run_git!).and_raise(Gitlab::Git::Repository::GitError, 'Something went wrong')
|
allow(repository).to receive(:run_git!).and_raise(Gitlab::Git::Repository::GitError, 'Something went wrong')
|
||||||
end
|
end
|
||||||
|
|
@ -71,31 +71,41 @@ describe MergeRequests::RebaseService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'valid params' do
|
context 'valid params' do
|
||||||
before do
|
shared_examples 'successful rebase' do
|
||||||
service.execute(merge_request)
|
before do
|
||||||
|
service.execute(merge_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'rebases source branch' do
|
||||||
|
parent_sha = merge_request.source_project.repository.commit(merge_request.source_branch).parents.first.sha
|
||||||
|
target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
|
||||||
|
expect(parent_sha).to eq(target_branch_sha)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'records the new SHA on the merge request' do
|
||||||
|
head_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
|
||||||
|
expect(merge_request.reload.rebase_commit_sha).to eq(head_sha)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'logs correct author and commiter' do
|
||||||
|
head_commit = merge_request.source_project.repository.commit(merge_request.source_branch)
|
||||||
|
|
||||||
|
expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com')
|
||||||
|
expect(head_commit.author_name).to eq('Dmitriy Zaporozhets')
|
||||||
|
expect(head_commit.committer_email).to eq(user.email)
|
||||||
|
expect(head_commit.committer_name).to eq(user.name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'rebases source branch' do
|
context 'when Gitaly rebase feature is enabled' do
|
||||||
parent_sha = merge_request.source_project.repository.commit(merge_request.source_branch).parents.first.sha
|
it_behaves_like 'successful rebase'
|
||||||
target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
|
|
||||||
expect(parent_sha).to eq(target_branch_sha)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'records the new SHA on the merge request' do
|
context 'when Gitaly rebase feature is disabled', :disable_gitaly do
|
||||||
head_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
|
it_behaves_like 'successful rebase'
|
||||||
expect(merge_request.reload.rebase_commit_sha).to eq(head_sha)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'logs correct author and commiter' do
|
context 'git commands', :disable_gitaly do
|
||||||
head_commit = merge_request.source_project.repository.commit(merge_request.source_branch)
|
|
||||||
|
|
||||||
expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com')
|
|
||||||
expect(head_commit.author_name).to eq('Dmitriy Zaporozhets')
|
|
||||||
expect(head_commit.committer_email).to eq(user.email)
|
|
||||||
expect(head_commit.committer_name).to eq(user.name)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'git commands' do
|
|
||||||
it 'sets GL_REPOSITORY env variable when calling git commands' do
|
it 'sets GL_REPOSITORY env variable when calling git commands' do
|
||||||
expect(repository).to receive(:popen).exactly(3)
|
expect(repository).to receive(:popen).exactly(3)
|
||||||
.with(anything, anything, hash_including('GL_REPOSITORY'))
|
.with(anything, anything, hash_including('GL_REPOSITORY'))
|
||||||
|
|
@ -106,27 +116,37 @@ describe MergeRequests::RebaseService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'fork' do
|
context 'fork' do
|
||||||
let(:forked_project) do
|
shared_examples 'successful fork rebase' do
|
||||||
fork_project(project, user, repository: true)
|
let(:forked_project) do
|
||||||
|
fork_project(project, user, repository: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:merge_request_from_fork) do
|
||||||
|
forked_project.repository.create_file(
|
||||||
|
user,
|
||||||
|
'new-file-to-target',
|
||||||
|
'',
|
||||||
|
message: 'Add new file to target',
|
||||||
|
branch_name: 'master')
|
||||||
|
|
||||||
|
create(:merge_request,
|
||||||
|
source_branch: 'master', source_project: forked_project,
|
||||||
|
target_branch: 'master', target_project: project)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'rebases source branch' do
|
||||||
|
parent_sha = forked_project.repository.commit(merge_request_from_fork.source_branch).parents.first.sha
|
||||||
|
target_branch_sha = project.repository.commit(merge_request_from_fork.target_branch).sha
|
||||||
|
expect(parent_sha).to eq(target_branch_sha)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:merge_request_from_fork) do
|
context 'when Gitaly rebase feature is enabled' do
|
||||||
forked_project.repository.create_file(
|
it_behaves_like 'successful fork rebase'
|
||||||
user,
|
|
||||||
'new-file-to-target',
|
|
||||||
'',
|
|
||||||
message: 'Add new file to target',
|
|
||||||
branch_name: 'master')
|
|
||||||
|
|
||||||
create(:merge_request,
|
|
||||||
source_branch: 'master', source_project: forked_project,
|
|
||||||
target_branch: 'master', target_project: project)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'rebases source branch' do
|
context 'when Gitaly rebase feature is disabled', :disable_gitaly do
|
||||||
parent_sha = forked_project.repository.commit(merge_request_from_fork.source_branch).parents.first.sha
|
it_behaves_like 'successful fork rebase'
|
||||||
target_branch_sha = project.repository.commit(merge_request_from_fork.target_branch).sha
|
|
||||||
expect(parent_sha).to eq(target_branch_sha)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue