diff options
author | Alejandro RodrÃguez <alejorro70@gmail.com> | 2017-12-05 16:42:04 -0300 |
---|---|---|
committer | Alejandro RodrÃguez <alejorro70@gmail.com> | 2017-12-27 15:12:30 -0300 |
commit | 351f205c0580e43ace9d5a47e0b923ffb7cda3b8 (patch) | |
tree | 512d30b7f8f54f26a9fca851b473ce6acf8a6544 | |
parent | f1d5e509b52c8c05fd570503389930121e12d87f (diff) | |
download | gitlab-ce-351f205c0580e43ace9d5a47e0b923ffb7cda3b8.tar.gz |
Incorporate ConflictsService.ListConflictFiles Gitaly RPC
-rw-r--r-- | app/services/merge_requests/conflicts/list_service.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/git/conflict/resolver.rb | 24 | ||||
-rw-r--r-- | lib/gitlab/git/repository.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/gitaly_client/conflicts_service.rb | 60 | ||||
-rw-r--r-- | lib/gitlab/gitaly_client/util.rb | 6 | ||||
-rw-r--r-- | spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb | 58 | ||||
-rw-r--r-- | spec/services/merge_requests/conflicts/list_service_spec.rb | 26 | ||||
-rw-r--r-- | spec/services/merge_requests/conflicts/resolve_service_spec.rb | 20 |
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 |