summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/projects/merge_requests/conflicts_controller.rb2
-rw-r--r--app/services/merge_requests/conflicts/list_service.rb2
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/v3/commits.rb2
-rw-r--r--lib/github/representation/comment.rb2
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb2
-rw-r--r--lib/gitlab/conflict/file.rb7
-rw-r--r--lib/gitlab/conflict/file_collection.rb8
-rw-r--r--lib/gitlab/diff/file.rb2
-rw-r--r--lib/gitlab/git/conflict/file.rb86
-rw-r--r--lib/gitlab/git/conflict/line_code.rb11
-rw-r--r--lib/gitlab/git/conflict/parser.rb91
-rw-r--r--lib/gitlab/git/conflict/resolver.rb91
-rw-r--r--lib/gitlab/git/conflict_file.rb84
-rw-r--r--lib/gitlab/git/conflict_parser.rb89
-rw-r--r--lib/gitlab/git/diff_line_code.rb9
-rw-r--r--lib/gitlab/git/merge.rb89
-rw-r--r--lib/gitlab/github_import/comment_formatter.rb2
-rw-r--r--spec/controllers/projects/merge_requests/conflicts_controller_spec.rb8
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb8
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb20
-rw-r--r--spec/lib/gitlab/git/conflict/parser_spec.rb (renamed from spec/lib/gitlab/git/conflict_parser_spec.rb)26
-rw-r--r--spec/models/diff_note_spec.rb2
-rw-r--r--spec/services/merge_requests/conflicts/resolve_service_spec.rb12
24 files changed, 334 insertions, 323 deletions
diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb
index 39814c1795c..366524b0783 100644
--- a/app/controllers/projects/merge_requests/conflicts_controller.rb
+++ b/app/controllers/projects/merge_requests/conflicts_controller.rb
@@ -53,7 +53,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
flash[:notice] = 'All merge conflicts were resolved. The merge request can now be merged.'
render json: { redirect_to: project_merge_request_url(@project, @merge_request, resolved_conflicts: true) }
- rescue Gitlab::Git::Merge::ResolutionError => e
+ rescue Gitlab::Git::Conflict::Resolver::ResolutionError => e
render status: :bad_request, json: { message: e.message }
end
end
diff --git a/app/services/merge_requests/conflicts/list_service.rb b/app/services/merge_requests/conflicts/list_service.rb
index 86e71e5aec8..0f677a996f7 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::ConflictParser::UnresolvableError, Gitlab::Git::Merge::ConflictSideMissing
+ rescue Rugged::OdbError, Gitlab::Git::Conflict::Parser::UnresolvableError, Gitlab::Git::Conflict::Resolver::ConflictSideMissing
@conflicts_can_be_resolved_in_ui = false
end
end
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index e2d50b4e0a6..6ad97f2deb2 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -186,7 +186,7 @@ module API
lines.each do |line|
next unless line.new_pos == params[:line] && line.type == params[:line_type]
- break opts[:line_code] = Gitlab::Git::DiffLineCode.generate(diff.new_path, line.new_pos, line.old_pos)
+ break opts[:line_code] = Gitlab::Git::Conflict::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
end
break if opts[:line_code]
diff --git a/lib/api/v3/commits.rb b/lib/api/v3/commits.rb
index 042f4338d53..cbb192d5dfc 100644
--- a/lib/api/v3/commits.rb
+++ b/lib/api/v3/commits.rb
@@ -173,7 +173,7 @@ module API
lines.each do |line|
next unless line.new_pos == params[:line] && line.type == params[:line_type]
- break opts[:line_code] = Gitlab::Git::DiffLineCode.generate(diff.new_path, line.new_pos, line.old_pos)
+ break opts[:line_code] = Gitlab::Git::Conflict::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
end
break if opts[:line_code]
diff --git a/lib/github/representation/comment.rb b/lib/github/representation/comment.rb
index b87a11672ed..0cb871630fd 100644
--- a/lib/github/representation/comment.rb
+++ b/lib/github/representation/comment.rb
@@ -23,7 +23,7 @@ module Github
private
def generate_line_code(line)
- Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos)
+ Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def on_diff?
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index f613d8e8179..38ba5b97ed0 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -241,7 +241,7 @@ module Gitlab
end
def generate_line_code(pr_comment)
- Gitlab::Git::DiffLineCode.generate(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos)
+ Gitlab::Git::Conflict::LineCode.generate(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos)
end
def pull_request_comment_attributes(comment)
diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb
index 2d8a21f4905..3392388a45f 100644
--- a/lib/gitlab/conflict/file.rb
+++ b/lib/gitlab/conflict/file.rb
@@ -6,7 +6,10 @@ module Gitlab
CONTEXT_LINES = 3
- attr_reader :merge_request, :raw
+ attr_reader :merge_request
+
+ # 'raw' holds the Gitlab::Git::Conflict::File that this instance wraps
+ attr_reader :raw
delegate :type, :content, :their_path, :our_path, :our_mode, :our_blob, :repository, to: :raw
@@ -107,7 +110,7 @@ module Gitlab
end
def line_code(line)
- Gitlab::Git::DiffLineCode.generate(our_path, line.new_pos, line.old_pos)
+ Gitlab::Git::Conflict::LineCode.generate(our_path, line.new_pos, line.old_pos)
end
def create_match_line(line)
diff --git a/lib/gitlab/conflict/file_collection.rb b/lib/gitlab/conflict/file_collection.rb
index 573a953b2aa..fb28e80ff73 100644
--- a/lib/gitlab/conflict/file_collection.rb
+++ b/lib/gitlab/conflict/file_collection.rb
@@ -1,14 +1,14 @@
module Gitlab
module Conflict
class FileCollection
- attr_reader :merge_request, :merge
+ attr_reader :merge_request, :resolver
def initialize(merge_request)
source_repo = merge_request.source_project.repository.raw
our_commit = merge_request.source_branch_head.raw
their_commit = merge_request.target_branch_head.raw
target_repo = merge_request.target_project.repository.raw
- @merge = Gitlab::Git::Merge.new(source_repo, our_commit, target_repo, their_commit)
+ @resolver = Gitlab::Git::Conflict::Resolver.new(source_repo, our_commit, target_repo, their_commit)
@merge_request = merge_request
end
@@ -18,11 +18,11 @@ module Gitlab
target_branch: merge_request.target_branch,
commit_message: commit_message || default_commit_message
}
- merge.resolve_conflicts(user, files, args)
+ resolver.resolve_conflicts(user, files, args)
end
def files
- @files ||= merge.conflicts.map do |conflict_file|
+ @files ||= resolver.conflicts.map do |conflict_file|
Gitlab::Conflict::File.new(conflict_file, merge_request: merge_request)
end
end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index bc2c25c9cb6..3f8d2041c29 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -49,7 +49,7 @@ module Gitlab
def line_code(line)
return if line.meta?
- Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos)
+ Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def line_for_line_code(code)
diff --git a/lib/gitlab/git/conflict/file.rb b/lib/gitlab/git/conflict/file.rb
new file mode 100644
index 00000000000..b2bc653904d
--- /dev/null
+++ b/lib/gitlab/git/conflict/file.rb
@@ -0,0 +1,86 @@
+module Gitlab
+ module Git
+ module Conflict
+ class File
+ attr_reader :content, :their_path, :our_path, :our_mode, :repository
+
+ def initialize(repository, commit_oid, conflict, content)
+ @repository = repository
+ @commit_oid = commit_oid
+ @their_path = conflict[:theirs][:path]
+ @our_path = conflict[:ours][:path]
+ @our_mode = conflict[:ours][:mode]
+ @content = 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 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::Conflict::LineCode.generate(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)
+ if resolution == content
+ raise Gitlab::Git::Conflict::Resolver::ResolutionError, "Resolved content has no changes for file #{our_path}"
+ end
+
+ resolution
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/conflict/line_code.rb b/lib/gitlab/git/conflict/line_code.rb
new file mode 100644
index 00000000000..bdbb4c9cb83
--- /dev/null
+++ b/lib/gitlab/git/conflict/line_code.rb
@@ -0,0 +1,11 @@
+module Gitlab
+ module Git
+ module Conflict
+ class LineCode
+ def self.generate(file_path, new_line_position, old_line_position)
+ "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/conflict/parser.rb b/lib/gitlab/git/conflict/parser.rb
new file mode 100644
index 00000000000..3effa9d2d31
--- /dev/null
+++ b/lib/gitlab/git/conflict/parser.rb
@@ -0,0 +1,91 @@
+module Gitlab
+ module Git
+ module Conflict
+ class Parser
+ UnresolvableError = Class.new(StandardError)
+ UnmergeableFile = Class.new(UnresolvableError)
+ UnsupportedEncoding = 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
+
+ text.force_encoding('UTF-8')
+
+ raise UnsupportedEncoding unless text.valid_encoding?
+ end
+
+ def validate_delimiter!(condition)
+ raise UnexpectedDelimiter unless condition
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/conflict/resolver.rb b/lib/gitlab/git/conflict/resolver.rb
new file mode 100644
index 00000000000..df509c5f4ce
--- /dev/null
+++ b/lib/gitlab/git/conflict/resolver.rb
@@ -0,0 +1,91 @@
+module Gitlab
+ module Git
+ module Conflict
+ class Resolver
+ ConflictSideMissing = Class.new(StandardError)
+ ResolutionError = Class.new(StandardError)
+
+ def initialize(repository, our_commit, target_repository, their_commit)
+ @repository = repository
+ @our_commit = our_commit.rugged_commit
+ @target_repository = target_repository
+ @their_commit = their_commit.rugged_commit
+ end
+
+ def conflicts
+ @conflicts ||= begin
+ target_index = @target_repository.rugged.merge_commits(@our_commit, @their_commit)
+
+ # We don't need to do `with_repo_branch_commit` here, because the target
+ # project always fetches source refs when creating merge request diffs.
+ target_index.conflicts.map do |conflict|
+ raise ConflictSideMissing unless conflict[:theirs] && conflict[:ours]
+
+ Gitlab::Git::Conflict::File.new(
+ @target_repository,
+ @our_commit.oid,
+ conflict,
+ target_index.merge_file(conflict[:ours][:path])[:data]
+ )
+ end
+ end
+ end
+
+ def resolve_conflicts(user, files, source_branch:, target_branch:, commit_message:)
+ @repository.with_repo_branch_commit(@target_repository, target_branch) do
+ files.each do |file_params|
+ conflict_file = conflict_for_path(file_params[:old_path], file_params[:new_path])
+
+ write_resolved_file_to_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: commit_message,
+ parents: [@our_commit, @their_commit].map(&:oid)
+ }
+
+ @repository.commit_index(user, source_branch, index, commit_params)
+ end
+ end
+
+ def conflict_for_path(old_path, new_path)
+ conflicts.find do |conflict|
+ conflict.their_path == old_path && conflict.our_path == new_path
+ end
+ end
+
+ private
+
+ # We can only write when getting the merge index from the source
+ # project, because we will write to that project. We don't use this all
+ # the time because this fetches a ref into the source project, which
+ # isn't needed for reading.
+ def index
+ @index ||= @repository.rugged.merge_commits(@our_commit, @their_commit)
+ end
+
+ def write_resolved_file_to_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.ends_with?("\n")
+ elsif params[:content]
+ new_file = file.resolve_content(params[:content])
+ end
+
+ our_path = file.our_path
+
+ index.add(path: our_path, oid: @repository.rugged.write(new_file, :blob), mode: file.our_mode)
+ index.conflict_remove(our_path)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/conflict_file.rb b/lib/gitlab/git/conflict_file.rb
deleted file mode 100644
index 95a1a9bbe5b..00000000000
--- a/lib/gitlab/git/conflict_file.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-module Gitlab
- module Git
- class ConflictFile
- attr_reader :content, :their_path, :our_path, :our_mode, :repository
-
- def initialize(repository, commit_oid, conflict, content)
- @repository = repository
- @commit_oid = commit_oid
- @their_path = conflict[:theirs][:path]
- @our_path = conflict[:ours][:path]
- @our_mode = conflict[:ours][:mode]
- @content = content
- end
-
- def lines
- return @lines if defined?(@lines)
-
- begin
- @type = 'text'
- @lines = Gitlab::Git::ConflictParser.parse(content,
- our_path: our_path,
- their_path: their_path)
- rescue Gitlab::Git::ConflictParser::ParserError
- @type = 'text-editor'
- @lines = nil
- end
- 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::DiffLineCode.generate(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::Merge::ResolutionError, "Missing resolution for section ID: #{section_id}"
- end
-
- line
- end.compact
- end
-
- def resolve_content(resolution)
- if resolution == content
- raise Gitlab::Git::Merge::ResolutionError, "Resolved content has no changes for file #{our_path}"
- end
-
- resolution
- end
- end
- end
-end
diff --git a/lib/gitlab/git/conflict_parser.rb b/lib/gitlab/git/conflict_parser.rb
deleted file mode 100644
index 90b03848aee..00000000000
--- a/lib/gitlab/git/conflict_parser.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-module Gitlab
- module Git
- class ConflictParser
- UnresolvableError = Class.new(StandardError)
- UnmergeableFile = Class.new(UnresolvableError)
- UnsupportedEncoding = 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
-
- text.force_encoding('UTF-8')
-
- raise UnsupportedEncoding unless text.valid_encoding?
- end
-
- def validate_delimiter!(condition)
- raise UnexpectedDelimiter unless condition
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/git/diff_line_code.rb b/lib/gitlab/git/diff_line_code.rb
deleted file mode 100644
index aab963ba928..00000000000
--- a/lib/gitlab/git/diff_line_code.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module Gitlab
- module Git
- class DiffLineCode
- def self.generate(file_path, new_line_position, old_line_position)
- "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}"
- end
- end
- end
-end
diff --git a/lib/gitlab/git/merge.rb b/lib/gitlab/git/merge.rb
deleted file mode 100644
index 3a0205c17f4..00000000000
--- a/lib/gitlab/git/merge.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-module Gitlab
- module Git
- class Merge
- ConflictSideMissing = Class.new(StandardError)
- ResolutionError = Class.new(StandardError)
-
- def initialize(repository, our_commit, target_repository, their_commit)
- @repository = repository
- @our_commit = our_commit.rugged_commit
- @target_repository = target_repository
- @their_commit = their_commit.rugged_commit
- end
-
- def conflicts
- @conflicts ||= begin
- target_index = @target_repository.rugged.merge_commits(@our_commit, @their_commit)
-
- # We don't need to do `with_repo_branch_commit` here, because the target
- # project always fetches source refs when creating merge request diffs.
- target_index.conflicts.map do |conflict|
- raise ConflictSideMissing unless conflict[:theirs] && conflict[:ours]
-
- Gitlab::Git::ConflictFile.new(
- @target_repository,
- @our_commit.oid,
- conflict,
- target_index.merge_file(conflict[:ours][:path])[:data]
- )
- end
- end
- end
-
- def resolve_conflicts(user, files, source_branch:, target_branch:, commit_message:)
- @repository.with_repo_branch_commit(@target_repository, target_branch) do
- files.each do |file_params|
- conflict_file = conflict_for_path(file_params[:old_path], file_params[:new_path])
-
- write_resolved_file_to_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: commit_message,
- parents: [@our_commit, @their_commit].map(&:oid)
- }
-
- @repository.commit_index(user, source_branch, index, commit_params)
- end
- end
-
- def conflict_for_path(old_path, new_path)
- conflicts.find do |conflict|
- conflict.their_path == old_path && conflict.our_path == new_path
- end
- end
-
- private
-
- # We can only write when getting the merge index from the source
- # project, because we will write to that project. We don't use this all
- # the time because this fetches a ref into the source project, which
- # isn't needed for reading.
- def index
- @index ||= @repository.rugged.merge_commits(@our_commit, @their_commit)
- end
-
- def write_resolved_file_to_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.ends_with?("\n")
- elsif params[:content]
- new_file = file.resolve_content(params[:content])
- end
-
- our_path = file.our_path
-
- index.add(path: our_path, oid: @repository.rugged.write(new_file, :blob), mode: file.our_mode)
- index.conflict_remove(our_path)
- end
- end
- end
-end
diff --git a/lib/gitlab/github_import/comment_formatter.rb b/lib/gitlab/github_import/comment_formatter.rb
index 6490cd7002d..f8757507b78 100644
--- a/lib/gitlab/github_import/comment_formatter.rb
+++ b/lib/gitlab/github_import/comment_formatter.rb
@@ -38,7 +38,7 @@ module Gitlab
end
def generate_line_code(line)
- Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos)
+ Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def on_diff?
diff --git a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
index 7047f14c758..c6d50c28106 100644
--- a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
@@ -17,8 +17,8 @@ describe Projects::MergeRequests::ConflictsController do
describe 'GET show' do
context 'when the conflicts cannot be resolved in the UI' do
before do
- allow(Gitlab::Git::ConflictParser).to receive(:parse)
- .and_raise(Gitlab::Git::ConflictParser::UnmergeableFile)
+ allow(Gitlab::Git::Conflict::Parser).to receive(:parse)
+ .and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile)
get :show,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
@@ -109,8 +109,8 @@ describe Projects::MergeRequests::ConflictsController do
context 'when the conflicts cannot be resolved in the UI' do
before do
- allow(Gitlab::Git::ConflictParser).to receive(:parse)
- .and_raise(Gitlab::Git::ConflictParser::UnmergeableFile)
+ allow(Gitlab::Git::Conflict::Parser).to receive(:parse)
+ .and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile)
conflict_for_path('files/ruby/regex.rb')
end
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 89dd545829b..bf981d2f6f6 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::Conflict::File do
let(:index) { rugged.merge_commits(our_commit, their_commit) }
let(:rugged_conflict) { index.conflicts.last }
let(:raw_conflict_content) { index.merge_file('files/ruby/regex.rb')[:data] }
- let(:raw_conflict_file) { Gitlab::Git::ConflictFile.new(repository, our_commit.oid, rugged_conflict, raw_conflict_content) }
+ let(:raw_conflict_file) { Gitlab::Git::Conflict::File.new(repository, our_commit.oid, rugged_conflict, raw_conflict_content) }
let(:conflict_file) { described_class.new(raw_conflict_file, merge_request: merge_request) }
describe '#resolve_lines' do
@@ -54,13 +54,13 @@ describe Gitlab::Conflict::File do
invalid_hash = section_keys.map { |key| [key, 'invalid'] }.to_h
expect { conflict_file.resolve_lines({}) }
- .to raise_error(Gitlab::Git::Merge::ResolutionError)
+ .to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)
expect { conflict_file.resolve_lines(empty_hash) }
- .to raise_error(Gitlab::Git::Merge::ResolutionError)
+ .to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)
expect { conflict_file.resolve_lines(invalid_hash) }
- .to raise_error(Gitlab::Git::Merge::ResolutionError)
+ .to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)
end
end
diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb
index 79c47653d55..e0c775bb0e9 100644
--- a/spec/lib/gitlab/diff/position_spec.rb
+++ b/spec/lib/gitlab/diff/position_spec.rb
@@ -40,7 +40,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, subject.new_line, 0)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, subject.new_line, 0)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -108,7 +108,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, subject.new_line, 15)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, subject.new_line, 15)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -149,7 +149,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, subject.new_line, subject.old_line)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, subject.new_line, subject.old_line)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -189,7 +189,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, 13, subject.old_line)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, 13, subject.old_line)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -233,7 +233,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, subject.new_line, 5)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, subject.new_line, 5)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -274,7 +274,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, subject.new_line, subject.old_line)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, subject.new_line, subject.old_line)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -314,7 +314,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, 4, subject.old_line)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, 4, subject.old_line)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -357,7 +357,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, 0, subject.old_line)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, 0, subject.old_line)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -399,7 +399,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, subject.new_line, 0)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, subject.new_line, 0)
expect(subject.line_code(project.repository)).to eq(line_code)
end
@@ -447,7 +447,7 @@ describe Gitlab::Diff::Position do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(subject.file_path, 0, subject.old_line)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(subject.file_path, 0, subject.old_line)
expect(subject.line_code(project.repository)).to eq(line_code)
end
diff --git a/spec/lib/gitlab/git/conflict_parser_spec.rb b/spec/lib/gitlab/git/conflict/parser_spec.rb
index 42eccb8cd4d..7b035a381f1 100644
--- a/spec/lib/gitlab/git/conflict_parser_spec.rb
+++ b/spec/lib/gitlab/git/conflict/parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Git::ConflictParser do
+describe Gitlab::Git::Conflict::Parser do
describe '.parse' do
def parse_text(text)
described_class.parse(text, our_path: 'README.md', their_path: 'README.md')
@@ -125,12 +125,12 @@ CONFLICT
context 'when there is a non-start delimiter first' do
it 'raises UnexpectedDelimiter when there is a middle delimiter first' do
expect { parse_text('=======') }
- .to raise_error(Gitlab::Git::ConflictParser::UnexpectedDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnexpectedDelimiter)
end
it 'raises UnexpectedDelimiter when there is an end delimiter first' do
expect { parse_text('>>>>>>> README.md') }
- .to raise_error(Gitlab::Git::ConflictParser::UnexpectedDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnexpectedDelimiter)
end
it 'does not raise when there is an end delimiter for a different path first' do
@@ -145,12 +145,12 @@ CONFLICT
it 'raises UnexpectedDelimiter when it is followed by an end delimiter' do
expect { parse_text(start_text + '>>>>>>> README.md' + end_text) }
- .to raise_error(Gitlab::Git::ConflictParser::UnexpectedDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnexpectedDelimiter)
end
it 'raises UnexpectedDelimiter when it is followed by another start delimiter' do
expect { parse_text(start_text + start_text + end_text) }
- .to raise_error(Gitlab::Git::ConflictParser::UnexpectedDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnexpectedDelimiter)
end
it 'does not raise when it is followed by a start delimiter for a different path' do
@@ -165,12 +165,12 @@ CONFLICT
it 'raises UnexpectedDelimiter when it is followed by another middle delimiter' do
expect { parse_text(start_text + '=======' + end_text) }
- .to raise_error(Gitlab::Git::ConflictParser::UnexpectedDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnexpectedDelimiter)
end
it 'raises UnexpectedDelimiter when it is followed by a start delimiter' do
expect { parse_text(start_text + start_text + end_text) }
- .to raise_error(Gitlab::Git::ConflictParser::UnexpectedDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnexpectedDelimiter)
end
it 'does not raise when it is followed by a start delimiter for another path' do
@@ -183,25 +183,25 @@ CONFLICT
start_text = "<<<<<<< README.md\n=======\n"
expect { parse_text(start_text) }
- .to raise_error(Gitlab::Git::ConflictParser::MissingEndDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::MissingEndDelimiter)
expect { parse_text(start_text + '>>>>>>> some-other-path.md') }
- .to raise_error(Gitlab::Git::ConflictParser::MissingEndDelimiter)
+ .to raise_error(Gitlab::Git::Conflict::Parser::MissingEndDelimiter)
end
end
context 'other file types' do
it 'raises UnmergeableFile when lines is blank, indicating a binary file' do
expect { parse_text('') }
- .to raise_error(Gitlab::Git::ConflictParser::UnmergeableFile)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnmergeableFile)
expect { parse_text(nil) }
- .to raise_error(Gitlab::Git::ConflictParser::UnmergeableFile)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnmergeableFile)
end
it 'raises UnmergeableFile when the file is over 200 KB' do
expect { parse_text('a' * 204801) }
- .to raise_error(Gitlab::Git::ConflictParser::UnmergeableFile)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnmergeableFile)
end
# All text from Rugged has an encoding of ASCII_8BIT, so force that in
@@ -216,7 +216,7 @@ CONFLICT
context 'when the file contains non-UTF-8 characters' do
it 'raises UnsupportedEncoding' do
expect { parse_text("a\xC4\xFC".force_encoding(Encoding::ASCII_8BIT)) }
- .to raise_error(Gitlab::Git::ConflictParser::UnsupportedEncoding)
+ .to raise_error(Gitlab::Git::Conflict::Parser::UnsupportedEncoding)
end
end
end
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 67a8efa6524..9db8a61e9ca 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -105,7 +105,7 @@ describe DiffNote do
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Git::DiffLineCode.generate(position.file_path, position.formatter.new_line, 15)
+ line_code = Gitlab::Git::Conflict::LineCode.generate(position.file_path, position.formatter.new_line, 15)
expect(subject.line_code).to eq(line_code)
end
diff --git a/spec/services/merge_requests/conflicts/resolve_service_spec.rb b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
index 4ecd318b5b6..5376083e7f5 100644
--- a/spec/services/merge_requests/conflicts/resolve_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
@@ -204,16 +204,16 @@ describe MergeRequests::Conflicts::ResolveService do
it 'raises a ResolutionError error' do
expect { service.execute(user, invalid_params) }
- .to raise_error(Gitlab::Git::Merge::ResolutionError)
+ .to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)
end
end
context 'when the content of a file is unchanged' do
- let(:merge) do
- MergeRequests::Conflicts::ListService.new(merge_request).conflicts.merge
+ let(:resolver) do
+ MergeRequests::Conflicts::ListService.new(merge_request).conflicts.resolver
end
let(:regex_conflict) do
- merge.conflict_for_path('files/ruby/regex.rb', 'files/ruby/regex.rb')
+ resolver.conflict_for_path('files/ruby/regex.rb', 'files/ruby/regex.rb')
end
let(:invalid_params) do
@@ -235,7 +235,7 @@ describe MergeRequests::Conflicts::ResolveService do
it 'raises a ResolutionError error' do
expect { service.execute(user, invalid_params) }
- .to raise_error(Gitlab::Git::Merge::ResolutionError)
+ .to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)
end
end
@@ -255,7 +255,7 @@ describe MergeRequests::Conflicts::ResolveService do
it 'raises a ResolutionError error' do
expect { service.execute(user, invalid_params) }
- .to raise_error(Gitlab::Git::Merge::ResolutionError)
+ .to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)
end
end
end