diff options
author | Toon Claes <toon@gitlab.com> | 2021-05-27 14:14:43 +0300 |
---|---|---|
committer | Toon Claes <toon@gitlab.com> | 2021-05-27 14:14:43 +0300 |
commit | 57386ae0550bd6e01191724e25b6e77ad09c6288 (patch) | |
tree | bc14c18eeed0aaf9476ccc292f6c76d0abaf1efc | |
parent | 6e58da454633a53c86d14a59587ee7a6a9d11031 (diff) | |
parent | 9cd44c23e4c444438192c0a961e399e2e27ef14b (diff) |
Merge branch 'zj-remove-ruby-conflict-resolution' into 'master'
ResolveConflicts: Remove Ruby implementation
Closes #3289
See merge request gitlab-org/gitaly!3546
-rw-r--r-- | internal/gitaly/rubyserver/rubyserver.go | 8 | ||||
-rw-r--r-- | ruby/lib/gitaly_server.rb | 2 | ||||
-rw-r--r-- | ruby/lib/gitaly_server/conflicts_service.rb | 38 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/conflict/file.rb | 97 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/conflict/parser.rb | 86 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/conflict/resolution.rb | 15 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/conflict/resolver.rb | 98 |
7 files changed, 0 insertions, 344 deletions
diff --git a/internal/gitaly/rubyserver/rubyserver.go b/internal/gitaly/rubyserver/rubyserver.go index 237b01c42..03638f7df 100644 --- a/internal/gitaly/rubyserver/rubyserver.go +++ b/internal/gitaly/rubyserver/rubyserver.go @@ -188,14 +188,6 @@ func (s *Server) WikiServiceClient(ctx context.Context) (gitalypb.WikiServiceCli return gitalypb.NewWikiServiceClient(conn), err } -// ConflictsServiceClient returns a ConflictsServiceClient instance that is -// configured to connect to the running Ruby server. This assumes Start() -// has been called already. -func (s *Server) ConflictsServiceClient(ctx context.Context) (gitalypb.ConflictsServiceClient, error) { - conn, err := s.getConnection(ctx) - return gitalypb.NewConflictsServiceClient(conn), err -} - // RemoteServiceClient returns a RemoteServiceClient instance that is // configured to connect to the running Ruby server. This assumes Start() // has been called already. diff --git a/ruby/lib/gitaly_server.rb b/ruby/lib/gitaly_server.rb index 33b6e6862..a7526291b 100644 --- a/ruby/lib/gitaly_server.rb +++ b/ruby/lib/gitaly_server.rb @@ -8,7 +8,6 @@ require_relative 'gitaly_server/utils.rb' require_relative 'gitaly_server/operations_service.rb' require_relative 'gitaly_server/repository_service.rb' require_relative 'gitaly_server/wiki_service.rb' -require_relative 'gitaly_server/conflicts_service.rb' require_relative 'gitaly_server/remote_service.rb' require_relative 'gitaly_server/health_service.rb' require_relative 'gitaly_server/feature_flags.rb' @@ -50,7 +49,6 @@ module GitalyServer server.handle(OperationsService.new) server.handle(RepositoryService.new) server.handle(WikiService.new) - server.handle(ConflictsService.new) server.handle(RemoteService.new) server.handle(HealthService.new) end diff --git a/ruby/lib/gitaly_server/conflicts_service.rb b/ruby/lib/gitaly_server/conflicts_service.rb deleted file mode 100644 index 5173a5135..000000000 --- a/ruby/lib/gitaly_server/conflicts_service.rb +++ /dev/null @@ -1,38 +0,0 @@ -module GitalyServer - class ConflictsService < Gitaly::ConflictsService::Service - include Utils - - def resolve_conflicts(call) - header = nil - files_json = "" - - call.each_remote_read.each_with_index do |request, index| - if index.zero? - header = request.header - else - files_json << request.files_json - end - end - - repo = Gitlab::Git::Repository.from_gitaly(header.repository, call) - remote_repo = Gitlab::Git::GitalyRemoteRepository.new(header.target_repository, call) - resolver = Gitlab::Git::Conflict::Resolver.new(remote_repo, header.our_commit_oid, header.their_commit_oid) - user = Gitlab::Git::User.from_gitaly(header.user) - files = JSON.parse(files_json).map(&:with_indifferent_access) - - begin - resolution = Gitlab::Git::Conflict::Resolution.new(user, files, header.commit_message.dup) - params = { - source_branch: header.source_branch, - target_branch: header.target_branch, - timestamp: header.timestamp - } - resolver.resolve_conflicts(repo, resolution, params) - - Gitaly::ResolveConflictsResponse.new - rescue Gitlab::Git::Conflict::Resolver::ResolutionError => e - Gitaly::ResolveConflictsResponse.new(resolution_error: e.message) - end - end - end -end diff --git a/ruby/lib/gitlab/git/conflict/file.rb b/ruby/lib/gitlab/git/conflict/file.rb deleted file mode 100644 index 762b82707..000000000 --- a/ruby/lib/gitlab/git/conflict/file.rb +++ /dev/null @@ -1,97 +0,0 @@ -module Gitlab - module Git - module Conflict - class File - UnsupportedEncoding = Class.new(StandardError) - - attr_reader :their_path, :our_path, :our_mode, :ancestor_path, :repository, :commit_oid - - attr_accessor :raw_content - - def initialize(repository, commit_oid, conflict, raw_content) - @repository = repository - @commit_oid = commit_oid - @their_path = conflict[:theirs][:path] - @our_path = conflict[:ours][:path] - @our_mode = conflict[:ours][:mode] - @ancestor_path = conflict.dig(:ancestor, :path) - @raw_content = raw_content - end - - def lines - return @lines if defined?(@lines) - - begin - @type = 'text' - @lines = Gitlab::Git::Conflict::Parser.parse(content, - our_path: our_path, - their_path: their_path) - rescue Gitlab::Git::Conflict::Parser::ParserError - @type = 'text-editor' - @lines = nil - end - end - - def content - @content ||= @raw_content.dup.force_encoding('UTF-8') - - raise UnsupportedEncoding unless @content.valid_encoding? - - @content - end - - def type - lines unless @type - - @type.inquiry - end - - def our_blob - # REFACTOR NOTE: the source of `commit_oid` used to be - # `merge_request.diff_refs.head_sha`. Instead of passing this value - # around the new lib structure, I decided to use `@commit_oid` which is - # equivalent to `merge_request.source_branch_head.raw.rugged_commit.oid`. - # That is what `merge_request.diff_refs.head_sha` is equivalent to when - # `merge_request` is not persisted (see `MergeRequest#diff_head_commit`). - # I think using the same oid is more consistent anyways, but if Conflicts - # start breaking, the change described above is a good place to look at. - @our_blob ||= repository.blob_at(@commit_oid, our_path) - end - - def line_code(line) - Gitlab::Git.diff_line_code(our_path, line[:line_new], line[:line_old]) - end - - def resolve_lines(resolution) - section_id = nil - - lines.map do |line| - unless line[:type] - section_id = nil - next line - end - - section_id ||= line_code(line) - - case resolution[section_id] - when 'head' - next unless line[:type] == 'new' - when 'origin' - next unless line[:type] == 'old' - else - raise Gitlab::Git::Conflict::Resolver::ResolutionError, "Missing resolution for section ID: #{section_id}" - end - - line - end.compact - end - - def resolve_content(resolution) - raise Gitlab::Git::Conflict::Resolver::ResolutionError, "Resolved content has no changes for file #{our_path}" if resolution == content - - resolution - end - end - end - end -end diff --git a/ruby/lib/gitlab/git/conflict/parser.rb b/ruby/lib/gitlab/git/conflict/parser.rb deleted file mode 100644 index fb5717dd5..000000000 --- a/ruby/lib/gitlab/git/conflict/parser.rb +++ /dev/null @@ -1,86 +0,0 @@ -module Gitlab - module Git - module Conflict - class Parser - UnresolvableError = Class.new(StandardError) - UnmergeableFile = Class.new(UnresolvableError) - - # Recoverable errors - the conflict can be resolved in an editor, but not with - # sections. - ParserError = Class.new(StandardError) - UnexpectedDelimiter = Class.new(ParserError) - MissingEndDelimiter = Class.new(ParserError) - - class << self - def parse(text, our_path:, their_path:, parent_file: nil) - validate_text!(text) - - line_obj_index = 0 - line_old = 1 - line_new = 1 - type = nil - lines = [] - conflict_start = "<<<<<<< #{our_path}" - conflict_middle = '=======' - conflict_end = ">>>>>>> #{their_path}" - - text.each_line.map do |line| - full_line = line.delete("\n") - - if full_line == conflict_start - validate_delimiter!(type.nil?) - - type = 'new' - elsif full_line == conflict_middle - validate_delimiter!(type == 'new') - - type = 'old' - elsif full_line == conflict_end - validate_delimiter!(type == 'old') - - type = nil - elsif line[0] == '\\' - type = 'nonewline' - lines << { - full_line: full_line, - type: type, - line_obj_index: line_obj_index, - line_old: line_old, - line_new: line_new - } - else - lines << { - full_line: full_line, - type: type, - line_obj_index: line_obj_index, - line_old: line_old, - line_new: line_new - } - - line_old += 1 if type != 'new' - line_new += 1 if type != 'old' - - line_obj_index += 1 - end - end - - raise MissingEndDelimiter unless type.nil? - - lines - end - - private - - def validate_text!(text) - raise UnmergeableFile if text.blank? # Typically a binary file - raise UnmergeableFile if text.length > 200.kilobytes - end - - def validate_delimiter!(condition) - raise UnexpectedDelimiter unless condition - end - end - end - end - end -end diff --git a/ruby/lib/gitlab/git/conflict/resolution.rb b/ruby/lib/gitlab/git/conflict/resolution.rb deleted file mode 100644 index ab9be683e..000000000 --- a/ruby/lib/gitlab/git/conflict/resolution.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Gitlab - module Git - module Conflict - class Resolution - attr_reader :user, :files, :commit_message - - def initialize(user, files, commit_message) - @user = user - @files = files - @commit_message = commit_message - end - end - end - end -end diff --git a/ruby/lib/gitlab/git/conflict/resolver.rb b/ruby/lib/gitlab/git/conflict/resolver.rb deleted file mode 100644 index fa4d2743b..000000000 --- a/ruby/lib/gitlab/git/conflict/resolver.rb +++ /dev/null @@ -1,98 +0,0 @@ -module Gitlab - module Git - module Conflict - class Resolver - ListError = Class.new(StandardError) - ResolutionError = Class.new(StandardError) - - def initialize(target_repository, our_commit_oid, their_commit_oid) - @target_repository = target_repository - @our_commit_oid = our_commit_oid - @their_commit_oid = their_commit_oid - end - - def conflicts - @conflicts = rugged_list_conflict_files - rescue Rugged::ReferenceError, Rugged::OdbError => e - raise ListError, e - end - - def resolve_conflicts(source_repository, resolution, source_branch:, target_branch:, timestamp: nil) - rugged_resolve_conflicts(source_repository, resolution, source_branch, target_branch, timestamp: timestamp) - end - - def conflict_for_path(conflicts, old_path, new_path) - conflicts.find do |conflict| - conflict.their_path == old_path && conflict.our_path == new_path - end - end - - private - - def conflict_files(repository, index) - index.conflicts.map do |conflict| - raise ListError, 'conflict side missing' unless conflict[:theirs] && conflict[:ours] - - Gitlab::Git::Conflict::File.new( - repository, - @our_commit_oid, - conflict, - index.merge_file(conflict[:ours][:path])[:data] - ) - end - end - - def write_resolved_file_to_index(repository, index, file, params) - if params[:sections] - resolved_lines = file.resolve_lines(params[:sections]) - new_file = resolved_lines.map { |line| line[:full_line] }.join("\n") - - new_file << "\n" if file.our_blob.data.end_with?("\n") - elsif params[:content] - new_file = file.resolve_content(params[:content]) - end - - our_path = file.our_path - - oid = repository.rugged.write(new_file, :blob) - 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 - - def rugged_resolve_conflicts(source_repository, resolution, source_branch, target_branch, timestamp: nil) - source_repository.with_repo_branch_commit(@target_repository, target_branch) do - index = source_repository.rugged.merge_commits(@our_commit_oid, @their_commit_oid) - conflicts = conflict_files(source_repository, index) - - resolution.files.each do |file_params| - conflict_file = conflict_for_path(conflicts, file_params[:old_path], file_params[:new_path]) - - write_resolved_file_to_index(source_repository, index, conflict_file, file_params) - end - - unless index.conflicts.empty? - missing_files = index.conflicts.map { |file| file[:ours][:path] } - - raise ResolutionError, "Missing resolutions for the following files: #{missing_files.join(', ')}" - end - - commit_params = { - message: resolution.commit_message, - parents: [@our_commit_oid, @their_commit_oid] - } - - source_repository.commit_index(resolution.user, source_branch, index, commit_params, timestamp) - end - end - end - end - end -end |