1# frozen_string_literal: true 2 3module Gitlab 4 module GitalyClient 5 class ConflictsService 6 include Gitlab::EncodingHelper 7 8 MAX_MSG_SIZE = 128.kilobytes.freeze 9 10 def initialize(repository, our_commit_oid, their_commit_oid) 11 @gitaly_repo = repository.gitaly_repository 12 @repository = repository 13 @our_commit_oid = our_commit_oid 14 @their_commit_oid = their_commit_oid 15 end 16 17 def list_conflict_files(allow_tree_conflicts: false) 18 request = Gitaly::ListConflictFilesRequest.new( 19 repository: @gitaly_repo, 20 our_commit_oid: @our_commit_oid, 21 their_commit_oid: @their_commit_oid, 22 allow_tree_conflicts: allow_tree_conflicts 23 ) 24 response = GitalyClient.call(@repository.storage, :conflicts_service, :list_conflict_files, request, timeout: GitalyClient.long_timeout) 25 GitalyClient::ConflictFilesStitcher.new(response, @gitaly_repo) 26 end 27 28 def conflicts? 29 list_conflict_files.any? 30 rescue GRPC::FailedPrecondition, GRPC::Unknown 31 # The server raises FailedPrecondition when it encounters 32 # ConflictSideMissing, which means a conflict exists but its `theirs` or 33 # `ours` data is nil due to a non-existent file in one of the trees. 34 # 35 # GRPC::Unknown comes from Rugged::ReferenceError and Rugged::OdbError. 36 true 37 end 38 39 def resolve_conflicts(target_repository, resolution, source_branch, target_branch) 40 reader = binary_io(resolution.files.to_json) 41 42 req_enum = Enumerator.new do |y| 43 header = resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch) 44 y.yield Gitaly::ResolveConflictsRequest.new(header: header) 45 46 until reader.eof? 47 chunk = reader.read(MAX_MSG_SIZE) 48 49 y.yield Gitaly::ResolveConflictsRequest.new(files_json: chunk) 50 end 51 end 52 53 response = GitalyClient.call(@repository.storage, :conflicts_service, :resolve_conflicts, req_enum, remote_storage: target_repository.storage, timeout: GitalyClient.long_timeout) 54 55 if response.resolution_error.present? 56 raise Gitlab::Git::Conflict::Resolver::ResolutionError, response.resolution_error 57 end 58 end 59 60 private 61 62 def resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch) 63 Gitaly::ResolveConflictsRequestHeader.new( 64 repository: @gitaly_repo, 65 our_commit_oid: @our_commit_oid, 66 target_repository: target_repository.gitaly_repository, 67 their_commit_oid: @their_commit_oid, 68 source_branch: encode_binary(source_branch), 69 target_branch: encode_binary(target_branch), 70 commit_message: encode_binary(resolution.commit_message), 71 user: Gitlab::Git::User.from_gitlab(resolution.user).to_gitaly, 72 timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i) 73 ) 74 end 75 end 76 end 77end 78