summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Rodríguez <alejorro70@gmail.com>2017-12-05 16:42:04 -0300
committerAlejandro Rodríguez <alejorro70@gmail.com>2017-12-27 15:12:30 -0300
commit351f205c0580e43ace9d5a47e0b923ffb7cda3b8 (patch)
tree512d30b7f8f54f26a9fca851b473ce6acf8a6544
parentf1d5e509b52c8c05fd570503389930121e12d87f (diff)
downloadgitlab-ce-351f205c0580e43ace9d5a47e0b923ffb7cda3b8.tar.gz
Incorporate ConflictsService.ListConflictFiles Gitaly RPC
-rw-r--r--app/services/merge_requests/conflicts/list_service.rb2
-rw-r--r--lib/gitlab/git/conflict/resolver.rb24
-rw-r--r--lib/gitlab/git/repository.rb4
-rw-r--r--lib/gitlab/gitaly_client/conflicts_service.rb60
-rw-r--r--lib/gitlab/gitaly_client/util.rb6
-rw-r--r--spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb58
-rw-r--r--spec/services/merge_requests/conflicts/list_service_spec.rb26
-rw-r--r--spec/services/merge_requests/conflicts/resolve_service_spec.rb20
8 files changed, 177 insertions, 23 deletions
diff --git a/app/services/merge_requests/conflicts/list_service.rb b/app/services/merge_requests/conflicts/list_service.rb
index 0f677a996f7..ca9a33678e4 100644
--- a/app/services/merge_requests/conflicts/list_service.rb
+++ b/app/services/merge_requests/conflicts/list_service.rb
@@ -23,7 +23,7 @@ module MergeRequests
# when there are no conflict files.
conflicts.files.each(&:lines)
@conflicts_can_be_resolved_in_ui = conflicts.files.length > 0
- rescue Rugged::OdbError, Gitlab::Git::Conflict::Parser::UnresolvableError, Gitlab::Git::Conflict::Resolver::ConflictSideMissing
+ rescue Gitlab::Git::CommandError, Gitlab::Git::Conflict::Parser::UnresolvableError, Gitlab::Git::Conflict::Resolver::ConflictSideMissing
@conflicts_can_be_resolved_in_ui = false
end
end
diff --git a/lib/gitlab/git/conflict/resolver.rb b/lib/gitlab/git/conflict/resolver.rb
index 03e5c0fcd6f..6a7ce4e3490 100644
--- a/lib/gitlab/git/conflict/resolver.rb
+++ b/lib/gitlab/git/conflict/resolver.rb
@@ -13,12 +13,18 @@ module Gitlab
def conflicts
@conflicts ||= begin
- target_index = @target_repository.rugged.merge_commits(@our_commit_oid, @their_commit_oid)
-
- # We don't need to do `with_repo_branch_commit` here, because the target
- # project always fetches source refs when creating merge request diffs.
- conflict_files(@target_repository, target_index)
+ @target_repository.gitaly_migrate(:conflicts_list_conflict_files) do |is_enabled|
+ if is_enabled
+ @target_repository.gitaly_conflicts_client.list_conflict_files(@our_commit_oid, @their_commit_oid)
+ else
+ rugged_list_conflict_files
+ end
+ end
end
+ rescue GRPC::FailedPrecondition => e
+ raise Gitlab::Git::Conflict::Resolver::ConflictSideMissing.new(e.message)
+ rescue Rugged::OdbError, GRPC::BadStatus => e
+ raise Gitlab::Git::CommandError.new(e)
end
def resolve_conflicts(source_repository, user, files, source_branch:, target_branch:, commit_message:)
@@ -84,6 +90,14 @@ module Gitlab
index.add(path: our_path, oid: oid, mode: file.our_mode)
index.conflict_remove(our_path)
end
+
+ def rugged_list_conflict_files
+ target_index = @target_repository.rugged.merge_commits(@our_commit_oid, @their_commit_oid)
+
+ # We don't need to do `with_repo_branch_commit` here, because the target
+ # project always fetches source refs when creating merge request diffs.
+ conflict_files(@target_repository, target_index)
+ end
end
end
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 36dc6b820ce..503f34a3ca5 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -1294,6 +1294,10 @@ module Gitlab
@gitaly_remote_client ||= Gitlab::GitalyClient::RemoteService.new(self)
end
+ def gitaly_conflicts_client
+ @gitaly_conflicts_client ||= Gitlab::GitalyClient::ConflictsService.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
diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb
new file mode 100644
index 00000000000..6508e436301
--- /dev/null
+++ b/lib/gitlab/gitaly_client/conflicts_service.rb
@@ -0,0 +1,60 @@
+module Gitlab
+ module GitalyClient
+ class ConflictsService
+ def initialize(repository)
+ @gitaly_repo = repository.gitaly_repository
+ @repository = repository
+ end
+
+ def list_conflict_files(our_commit_oid, their_commit_oid)
+ request = Gitaly::ListConflictFilesRequest.new(
+ repository: @gitaly_repo,
+ our_commit_oid: our_commit_oid,
+ their_commit_oid: their_commit_oid
+ )
+ response = GitalyClient.call(@repository.storage, :conflicts_service, :list_conflict_files, request)
+ files = []
+ header = nil
+ content = nil
+
+ response.each do |msg|
+ msg.files.each do |gitaly_file|
+ if gitaly_file.header
+ # Add previous file to the collection, except on first iteration
+ files << conflict_file_from_gitaly(header, content) if header
+
+ header = gitaly_file.header
+ content = ""
+ else
+ # Append content to curret file
+ content << gitaly_file.content
+ end
+ end
+ end
+
+ # Add leftover file, if any
+ files << conflict_file_from_gitaly(header, content) if header
+
+ files
+ end
+
+ private
+
+ def conflict_file_from_gitaly(header, content)
+ Gitlab::Git::Conflict::File.new(
+ Gitlab::GitalyClient::Util.git_repository(header.repository),
+ header.commit_oid,
+ conflict_from_gitaly_file_header(header),
+ content
+ )
+ end
+
+ def conflict_from_gitaly_file_header(header)
+ {
+ ours: { path: header.our_path, mode: header.our_mode },
+ theirs: { path: header.their_path }
+ }
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client/util.rb b/lib/gitlab/gitaly_client/util.rb
index b1a033280b4..7a3fffae9b6 100644
--- a/lib/gitlab/gitaly_client/util.rb
+++ b/lib/gitlab/gitaly_client/util.rb
@@ -18,6 +18,12 @@ module Gitlab
)
end
+ def git_repository(gitaly_repository)
+ Gitlab::Git::Repository.new(gitaly_repository.storage_name,
+ gitaly_repository.relative_path,
+ gitaly_repository.gl_repository)
+ end
+
def gitlab_tag_from_gitaly_tag(repository, gitaly_tag)
if gitaly_tag.target_commit.present?
commit = Gitlab::Git::Commit.decorate(repository, gitaly_tag.target_commit)
diff --git a/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb b/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb
new file mode 100644
index 00000000000..de027fc1423
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::ConflictsService do
+ let(:project) { create(:project, :repository) }
+ let(:target_project) { create(:project, :repository) }
+ let(:repository) { project.repository }
+ let(:gitaly_repositoy) { repository.gitaly_repository }
+ let(:target_repository) { target_project.repository }
+ let(:target_gitaly_repository) { target_repository.gitaly_repository }
+
+ describe '#list_conflict_files' do
+ let(:request) do
+ Gitaly::ListConflictFilesRequest.new(
+ repository: target_gitaly_repository, our_commit_oid: our_commit_oid,
+ their_commit_oid: their_commit_oid
+ )
+ end
+ let(:our_commit_oid) { 'f00' }
+ let(:their_commit_oid) { 'f44' }
+ let(:our_path) { 'our/path' }
+ let(:their_path) { 'their/path' }
+ let(:our_mode) { 0744 }
+ let(:header) do
+ double(repository: target_gitaly_repository, commit_oid: our_commit_oid,
+ our_path: our_path, our_mode: 0744, their_path: their_path)
+ end
+ let(:response) do
+ [
+ double(files: [double(header: header), double(content: 'foo', header: nil)]),
+ double(files: [double(content: 'bar', header: nil)])
+ ]
+ end
+ let(:file) { subject[0] }
+ let(:client) { described_class.new(target_repository) }
+
+ subject { client.list_conflict_files(our_commit_oid, their_commit_oid) }
+
+ it 'sends an RPC request' do
+ expect_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:list_conflict_files)
+ .with(request, kind_of(Hash)).and_return([])
+
+ subject
+ end
+
+ it 'forms a Gitlab::Git::ConflictFile collection from the response' do
+ allow_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:list_conflict_files)
+ .with(request, kind_of(Hash)).and_return(response)
+
+ expect(subject.size).to be(1)
+ expect(file.content).to eq('foobar')
+ expect(file.their_path).to eq(their_path)
+ expect(file.our_path).to eq(our_path)
+ expect(file.our_mode).to be(our_mode)
+ expect(file.repository).to eq(target_repository)
+ expect(file.commit_oid).to eq(our_commit_oid)
+ end
+ end
+end
diff --git a/spec/services/merge_requests/conflicts/list_service_spec.rb b/spec/services/merge_requests/conflicts/list_service_spec.rb
index 0b32c51a16f..6cadcd438c3 100644
--- a/spec/services/merge_requests/conflicts/list_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/list_service_spec.rb
@@ -32,14 +32,6 @@ describe MergeRequests::Conflicts::ListService do
expect(conflicts_service(merge_request).can_be_resolved_in_ui?).to be_falsey
end
- it 'returns a falsey value when the MR has a missing ref after a force push' do
- merge_request = create_merge_request('conflict-resolvable')
- service = conflicts_service(merge_request)
- allow_any_instance_of(Rugged::Repository).to receive(:merge_commits).and_raise(Rugged::OdbError)
-
- expect(service.can_be_resolved_in_ui?).to be_falsey
- end
-
it 'returns a falsey value when the MR does not support new diff notes' do
merge_request = create_merge_request('conflict-resolvable')
merge_request.merge_request_diff.update_attributes(start_commit_sha: nil)
@@ -76,5 +68,23 @@ describe MergeRequests::Conflicts::ListService do
expect(conflicts_service(merge_request).can_be_resolved_in_ui?).to be_truthy
end
+
+ it 'returns a falsey value when the MR has a missing ref after a force push' do
+ merge_request = create_merge_request('conflict-resolvable')
+ service = conflicts_service(merge_request)
+ allow_any_instance_of(Gitlab::GitalyClient::ConflictsService).to receive(:list_conflict_files).and_raise(GRPC::Unknown)
+
+ expect(service.can_be_resolved_in_ui?).to be_falsey
+ end
+
+ context 'with gitaly disabled', :skip_gitaly_mock do
+ it 'returns a falsey value when the MR has a missing ref after a force push' do
+ merge_request = create_merge_request('conflict-resolvable')
+ service = conflicts_service(merge_request)
+ allow_any_instance_of(Rugged::Repository).to receive(:merge_commits).and_raise(Rugged::OdbError)
+
+ expect(service.can_be_resolved_in_ui?).to be_falsey
+ end
+ end
end
end
diff --git a/spec/services/merge_requests/conflicts/resolve_service_spec.rb b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
index e28d8d7ae5c..cff09237005 100644
--- a/spec/services/merge_requests/conflicts/resolve_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
@@ -111,15 +111,6 @@ describe MergeRequests::Conflicts::ResolveService do
described_class.new(merge_request_from_fork).execute(user, params)
end
- it 'gets conflicts from the source project' do
- # REFACTOR NOTE: We used to test that `project.repository.rugged` wasn't
- # used in this case, but since the refactor, for simplification,
- # we always use that repository for read only operations.
- expect(forked_project.repository.rugged).to receive(:merge_commits).and_call_original
-
- subject
- end
-
it 'creates a commit with the message' do
subject
@@ -132,6 +123,17 @@ describe MergeRequests::Conflicts::ResolveService do
expect(merge_request_from_fork.source_branch_head.parents.map(&:id))
.to eq(['404fa3fc7c2c9b5dacff102f353bdf55b1be2813', target_head])
end
+
+ context 'when gitaly is disabled', :skip_gitaly_mock do
+ it 'gets conflicts from the source project' do
+ # REFACTOR NOTE: We used to test that `project.repository.rugged` wasn't
+ # used in this case, but since the refactor, for simplification,
+ # we always use that repository for read only operations.
+ expect(forked_project.repository.rugged).to receive(:merge_commits).and_call_original
+
+ subject
+ end
+ end
end
end