Encapsulate git operations for conflict resolution into lib
This commit is contained in:
parent
e49e443b70
commit
9fda629a34
3 changed files with 52 additions and 60 deletions
|
@ -1,54 +1,10 @@
|
||||||
module MergeRequests
|
module MergeRequests
|
||||||
module Conflicts
|
module Conflicts
|
||||||
class ResolveService < MergeRequests::Conflicts::BaseService
|
class ResolveService < MergeRequests::Conflicts::BaseService
|
||||||
MissingFiles = Class.new(Gitlab::Conflict::ResolutionError)
|
|
||||||
|
|
||||||
def execute(current_user, params)
|
def execute(current_user, params)
|
||||||
rugged = merge_request.source_project.repository.rugged
|
conflicts = Gitlab::Conflict::FileCollection.for_resolution(merge_request)
|
||||||
|
|
||||||
Gitlab::Conflict::FileCollection.for_resolution(merge_request) do |conflicts_for_resolution|
|
conflicts.resolve(current_user, params[:commit_message], params[:files])
|
||||||
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
|
|
||||||
|
|
||||||
merge_index.add(path: our_path, oid: rugged.write(new_file, :blob), mode: file.our_mode)
|
|
||||||
merge_index.conflict_remove(our_path)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,9 @@ module Gitlab
|
||||||
module Conflict
|
module Conflict
|
||||||
class FileCollection
|
class FileCollection
|
||||||
ConflictSideMissing = Class.new(StandardError)
|
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
|
delegate :repository, to: :project
|
||||||
|
|
||||||
|
@ -13,22 +14,41 @@ module Gitlab
|
||||||
# the time because this fetches a ref into the source project, which
|
# the time because this fetches a ref into the source project, which
|
||||||
# isn't needed for reading.
|
# isn't needed for reading.
|
||||||
def for_resolution(merge_request)
|
def for_resolution(merge_request)
|
||||||
project = merge_request.source_project
|
new(merge_request, merge_request.source_project, false)
|
||||||
|
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# We don't need to do `with_repo_branch_commit` here, because the target
|
# We don't need to do `with_repo_branch_commit` here, because the target
|
||||||
# project always fetches source refs when creating merge request diffs.
|
# project always fetches source refs when creating merge request diffs.
|
||||||
def read_only(merge_request)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -75,11 +95,27 @@ EOM
|
||||||
|
|
||||||
private
|
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
|
@merge_request = merge_request
|
||||||
@our_commit = merge_request.source_branch_head.raw.rugged_commit
|
@our_commit = merge_request.source_branch_head.raw.rugged_commit
|
||||||
@their_commit = merge_request.target_branch_head.raw.rugged_commit
|
@their_commit = merge_request.target_branch_head.raw.rugged_commit
|
||||||
@project = project
|
@project = project
|
||||||
|
@read_only = read_only
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -248,7 +248,7 @@ describe MergeRequests::Conflicts::ResolveService do
|
||||||
|
|
||||||
it 'raises a MissingFiles error' do
|
it 'raises a MissingFiles error' do
|
||||||
expect { service.execute(user, invalid_params) }
|
expect { service.execute(user, invalid_params) }
|
||||||
.to raise_error(described_class::MissingFiles)
|
.to raise_error(Gitlab::Conflict::FileCollection::MissingFiles)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue