Skip to content
Snippets Groups Projects
Commit fa5f0164 authored by Alejandro Rodríguez's avatar Alejandro Rodríguez
Browse files

Implement OperationService.UserAddBranch Gitaly RPC

parent 16f85003
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -656,13 +656,13 @@ module Gitlab
end
 
def add_branch(branch_name, user:, target:)
target_object = Ref.dereference_object(lookup(target))
raise InvalidRef.new("target not found: #{target}") unless target_object
OperationService.new(user, self).add_branch(branch_name, target_object.oid)
find_branch(branch_name)
rescue Rugged::ReferenceError => ex
raise InvalidRef, ex
gitaly_migrate(:operation_user_create_branch) do |is_enabled|
if is_enabled
gitaly_add_branch(branch_name, user, target)
else
rugged_add_branch(branch_name, user, target)
end
end
end
 
def add_tag(tag_name, user:, target:, message: nil)
Loading
Loading
@@ -1081,6 +1081,10 @@ module Gitlab
@gitaly_repository_client ||= Gitlab::GitalyClient::RepositoryService.new(self)
end
 
def gitaly_operation_client
@gitaly_operation_client ||= Gitlab::GitalyClient::OperationService.new(self)
end
def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
Gitlab::GitalyClient.migrate(method, status: status, &block)
rescue GRPC::NotFound => e
Loading
Loading
@@ -1472,6 +1476,22 @@ module Gitlab
file.write(gitattributes_content)
end
end
def gitaly_add_branch(branch_name, user, target)
gitaly_operation_client.user_create_branch(branch_name, user, target)
rescue GRPC::FailedPrecondition => ex
raise InvalidRef, ex
end
def rugged_add_branch(branch_name, user, target)
target_object = Ref.dereference_object(lookup(target))
raise InvalidRef.new("target not found: #{target}") unless target_object
OperationService.new(user, self).add_branch(branch_name, target_object.oid)
find_branch(branch_name)
rescue Rugged::ReferenceError
raise InvalidRef, ex
end
end
end
end
Loading
Loading
@@ -40,6 +40,26 @@ module Gitlab
rescue GRPC::FailedPrecondition => e
raise Gitlab::Git::Repository::InvalidRef, e
end
def user_create_branch(branch_name, user, start_point)
request = Gitaly::UserCreateBranchRequest.new(
repository: @gitaly_repo,
branch_name: GitalyClient.encode(branch_name),
user: Util.gitaly_user(user),
start_point: GitalyClient.encode(start_point)
)
response = GitalyClient.call(@repository.storage, :operation_service,
:user_create_branch, request)
if response.pre_receive_error.present?
raise Gitlab::Git::HooksService::PreReceiveError.new(response.pre_receive_error)
end
branch = response.branch
return nil unless branch
target_commit = Gitlab::Git::Commit.decorate(@repository, branch.target_commit)
Gitlab::Git::Branch.new(@repository, branch.name, target_commit.id, target_commit)
end
end
end
end
require 'spec_helper'
describe Gitlab::GitalyClient::OperationService do
let(:project) { create(:project) }
let(:repository) { project.repository.raw }
let(:client) { described_class.new(repository) }
describe '#user_create_branch' do
let(:user) { create(:user) }
let(:gitaly_user) { Gitlab::GitalyClient::Util.gitaly_user(user) }
let(:branch_name) { 'new' }
let(:start_point) { 'master' }
let(:request) do
Gitaly::UserCreateBranchRequest.new(
repository: repository.gitaly_repository,
branch_name: branch_name,
start_point: start_point,
user: gitaly_user
)
end
let(:gitaly_commit) { build(:gitaly_commit) }
let(:commit_id) { gitaly_commit.id }
let(:gitaly_branch) do
Gitaly::Branch.new(name: branch_name, target_commit: gitaly_commit)
end
let(:response) { Gitaly::UserCreateBranchResponse.new(branch: gitaly_branch) }
let(:commit) { Gitlab::Git::Commit.new(repository, gitaly_commit) }
subject { client.user_create_branch(branch_name, user, start_point) }
it 'sends a user_create_branch message and returns a Gitlab::git::Branch' do
expect_any_instance_of(Gitaly::OperationService::Stub)
.to receive(:user_create_branch).with(request, kind_of(Hash))
.and_return(response)
expect(subject.name).to eq(branch_name)
expect(subject.dereferenced_target).to eq(commit)
end
context "when pre_receive_error is present" do
let(:response) do
Gitaly::UserCreateBranchResponse.new(pre_receive_error: "something failed")
end
it "throws a PreReceive exception" do
expect_any_instance_of(Gitaly::OperationService::Stub)
.to receive(:user_create_branch).with(request, kind_of(Hash))
.and_return(response)
expect { subject }.to raise_error(
Gitlab::Git::HooksService::PreReceiveError, "something failed")
end
end
end
end
Loading
Loading
@@ -815,45 +815,70 @@ describe Repository do
end
 
describe '#add_branch' do
context 'when pre hooks were successful' do
it 'runs without errors' do
hook = double(trigger: [true, nil])
expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
let(:branch_name) { 'new_feature' }
let(:target) { 'master' }
 
expect { repository.add_branch(user, 'new_feature', 'master') }.not_to raise_error
end
subject { repository.add_branch(user, branch_name, target) }
 
it 'creates the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
context 'with Gitaly enabled' do
it "calls Gitaly's OperationService" do
expect_any_instance_of(Gitlab::GitalyClient::OperationService)
.to receive(:user_create_branch).with(branch_name, user, target)
.and_return(nil)
 
branch = repository.add_branch(user, 'new_feature', 'master')
subject
end
 
expect(branch.name).to eq('new_feature')
it 'creates_the_branch' do
expect(subject.name).to eq(branch_name)
expect(repository.find_branch(branch_name)).not_to be_nil
end
 
it 'calls the after_create_branch hook' do
expect(repository).to receive(:after_create_branch)
context 'with a non-existing target' do
let(:target) { 'fake-target' }
 
repository.add_branch(user, 'new_feature', 'master')
it "returns false and doesn't create the branch" do
expect(subject).to be(false)
expect(repository.find_branch(branch_name)).to be_nil
end
end
end
 
context 'when pre hooks failed' do
it 'gets an error' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
context 'with Gitaly disabled', skip_gitaly_mock: true do
context 'when pre hooks were successful' do
it 'runs without errors' do
hook = double(trigger: [true, nil])
expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
 
expect do
repository.add_branch(user, 'new_feature', 'master')
end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
expect { subject }.not_to raise_error
end
it 'creates the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
expect(subject.name).to eq(branch_name)
end
it 'calls the after_create_branch hook' do
expect(repository).to receive(:after_create_branch)
subject
end
end
 
it 'does not create the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
context 'when pre hooks failed' do
it 'gets an error' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
 
expect do
repository.add_branch(user, 'new_feature', 'master')
end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
expect(repository.find_branch('new_feature')).to be_nil
expect { subject }.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
end
it 'does not create the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect { subject }.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
expect(repository.find_branch(branch_name)).to be_nil
end
end
end
end
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment