Skip to content
Snippets Groups Projects
Commit 9fda629a authored by Alejandro Rodríguez's avatar Alejandro Rodríguez
Browse files

Encapsulate git operations for conflict resolution into lib

parent e49e443b
No related branches found
No related tags found
No related merge requests found
module MergeRequests
module Conflicts
class ResolveService < MergeRequests::Conflicts::BaseService
MissingFiles = Class.new(Gitlab::Conflict::ResolutionError)
def execute(current_user, params)
rugged = merge_request.source_project.repository.rugged
Gitlab::Conflict::FileCollection.for_resolution(merge_request) do |conflicts_for_resolution|
merge_index = conflicts_for_resolution.merge_index
params[:files].each do |file_params|
conflict_file = conflicts_for_resolution.file_for_path(file_params[:old_path], file_params[:new_path])
write_resolved_file_to_index(merge_index, rugged, conflict_file, file_params)
end
unless merge_index.conflicts.empty?
missing_files = merge_index.conflicts.map { |file| file[:ours][:path] }
raise MissingFiles, "Missing resolutions for the following files: #{missing_files.join(', ')}"
end
commit_params = {
message: params[:commit_message] || conflicts_for_resolution.default_commit_message,
parents: [conflicts_for_resolution.our_commit, conflicts_for_resolution.their_commit].map(&:oid),
tree: merge_index.write_tree(rugged)
}
conflicts_for_resolution
.project
.repository
.resolve_conflicts(current_user, merge_request.source_branch, commit_params)
end
end
private
def write_resolved_file_to_index(merge_index, rugged, file, params)
if params[:sections]
new_file = file.resolve_lines(params[:sections]).map(&:text).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
conflicts = Gitlab::Conflict::FileCollection.for_resolution(merge_request)
 
merge_index.add(path: our_path, oid: rugged.write(new_file, :blob), mode: file.our_mode)
merge_index.conflict_remove(our_path)
conflicts.resolve(current_user, params[:commit_message], params[:files])
end
end
end
Loading
Loading
Loading
Loading
@@ -2,8 +2,9 @@ module Gitlab
module Conflict
class FileCollection
ConflictSideMissing = Class.new(StandardError)
MissingFiles = Class.new(ResolutionError)
 
attr_reader :merge_request, :our_commit, :their_commit, :project
attr_reader :merge_request, :our_commit, :their_commit, :project, :read_only
 
delegate :repository, to: :project
 
Loading
Loading
@@ -13,22 +14,41 @@ module Gitlab
# the time because this fetches a ref into the source project, which
# isn't needed for reading.
def for_resolution(merge_request)
project = merge_request.source_project
new(merge_request, project).tap do |file_collection|
project
.repository
.with_repo_branch_commit(merge_request.target_project.repository.raw_repository, merge_request.target_branch) do
yield file_collection
end
end
new(merge_request, merge_request.source_project, false)
end
 
# We don't need to do `with_repo_branch_commit` here, because the target
# project always fetches source refs when creating merge request diffs.
def read_only(merge_request)
new(merge_request, merge_request.target_project)
new(merge_request, merge_request.target_project, true)
end
end
def resolve(user, commit_message, files)
raise "can't resolve a read-only Conflict File Collection" if read_only
repository.with_repo_branch_commit(merge_request.target_project.repository.raw, merge_request.target_branch) do
rugged = repository.rugged
files.each do |file_params|
conflict_file = file_for_path(file_params[:old_path], file_params[:new_path])
write_resolved_file_to_index(merge_index, rugged, conflict_file, file_params)
end
unless merge_index.conflicts.empty?
missing_files = merge_index.conflicts.map { |file| file[:ours][:path] }
raise MissingFiles, "Missing resolutions for the following files: #{missing_files.join(', ')}"
end
commit_params = {
message: commit_message || default_commit_message,
parents: [our_commit, their_commit].map(&:oid),
tree: merge_index.write_tree(rugged)
}
repository.resolve_conflicts(user, merge_request.source_branch, commit_params)
end
end
 
Loading
Loading
@@ -75,11 +95,27 @@ EOM
 
private
 
def initialize(merge_request, project)
def write_resolved_file_to_index(merge_index, rugged, file, params)
if params[:sections]
new_file = file.resolve_lines(params[:sections]).map(&:text).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
merge_index.add(path: our_path, oid: rugged.write(new_file, :blob), mode: file.our_mode)
merge_index.conflict_remove(our_path)
end
def initialize(merge_request, project, read_only)
@merge_request = merge_request
@our_commit = merge_request.source_branch_head.raw.rugged_commit
@their_commit = merge_request.target_branch_head.raw.rugged_commit
@project = project
@read_only = read_only
end
end
end
Loading
Loading
Loading
Loading
@@ -248,7 +248,7 @@ describe MergeRequests::Conflicts::ResolveService do
 
it 'raises a MissingFiles error' do
expect { service.execute(user, invalid_params) }
.to raise_error(described_class::MissingFiles)
.to raise_error(Gitlab::Conflict::FileCollection::MissingFiles)
end
end
end
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment