2019-02-13 22:33:31 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-09-13 17:45:13 +05:30
|
|
|
module Gitlab
|
|
|
|
module Conflict
|
|
|
|
class FileCollection
|
2018-03-27 19:54:05 +05:30
|
|
|
include Gitlab::RepositoryCacheAdapter
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
attr_reader :merge_request, :resolver
|
|
|
|
|
|
|
|
def initialize(merge_request)
|
|
|
|
our_commit = merge_request.source_branch_head.raw
|
|
|
|
their_commit = merge_request.target_branch_head.raw
|
2018-03-27 19:54:05 +05:30
|
|
|
@target_repo = merge_request.target_project.repository
|
2018-03-17 18:26:18 +05:30
|
|
|
@source_repo = merge_request.source_project.repository.raw
|
2018-03-27 19:54:05 +05:30
|
|
|
@our_commit_id = our_commit.id
|
|
|
|
@their_commit_id = their_commit.id
|
|
|
|
@resolver = Gitlab::Git::Conflict::Resolver.new(@target_repo.raw, @our_commit_id, @their_commit_id)
|
2018-03-17 18:26:18 +05:30
|
|
|
@merge_request = merge_request
|
2016-09-13 17:45:13 +05:30
|
|
|
end
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
def resolve(user, commit_message, files)
|
|
|
|
msg = commit_message || default_commit_message
|
|
|
|
resolution = Gitlab::Git::Conflict::Resolution.new(user, files, msg)
|
|
|
|
args = {
|
|
|
|
source_branch: merge_request.source_branch,
|
|
|
|
target_branch: merge_request.target_branch
|
|
|
|
}
|
|
|
|
resolver.resolve_conflicts(@source_repo, resolution, args)
|
|
|
|
ensure
|
|
|
|
@merge_request.clear_memoized_shas
|
2016-09-13 17:45:13 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def files
|
2018-03-17 18:26:18 +05:30
|
|
|
@files ||= resolver.conflicts.map do |conflict_file|
|
|
|
|
Gitlab::Conflict::File.new(conflict_file, merge_request: merge_request)
|
2016-09-13 17:45:13 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-03-27 19:54:05 +05:30
|
|
|
def can_be_resolved_in_ui?
|
|
|
|
# Try to parse each conflict. If the MR's mergeable status hasn't been
|
|
|
|
# updated, ensure that we don't say there are conflicts to resolve
|
|
|
|
# when there are no conflict files.
|
|
|
|
files.each(&:lines)
|
|
|
|
files.any?
|
2018-04-04 21:44:52 +05:30
|
|
|
rescue Gitlab::Git::CommandError,
|
|
|
|
Gitlab::Git::Conflict::Parser::UnresolvableError,
|
|
|
|
Gitlab::Git::Conflict::Resolver::ConflictSideMissing,
|
|
|
|
Gitlab::Git::Conflict::File::UnsupportedEncoding
|
2018-03-27 19:54:05 +05:30
|
|
|
false
|
|
|
|
end
|
|
|
|
cache_method :can_be_resolved_in_ui?
|
|
|
|
|
2016-11-03 12:29:30 +05:30
|
|
|
def file_for_path(old_path, new_path)
|
|
|
|
files.find { |file| file.their_path == old_path && file.our_path == new_path }
|
|
|
|
end
|
|
|
|
|
2016-09-13 17:45:13 +05:30
|
|
|
def as_json(opts = nil)
|
|
|
|
{
|
|
|
|
target_branch: merge_request.target_branch,
|
|
|
|
source_branch: merge_request.source_branch,
|
|
|
|
commit_sha: merge_request.diff_head_sha,
|
|
|
|
commit_message: default_commit_message,
|
|
|
|
files: files
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def default_commit_message
|
2018-03-17 18:26:18 +05:30
|
|
|
conflict_filenames = files.map do |conflict|
|
|
|
|
"# #{conflict.our_path}"
|
2016-09-13 17:45:13 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
<<EOM.chomp
|
|
|
|
Merge branch '#{merge_request.target_branch}' into '#{merge_request.source_branch}'
|
|
|
|
|
|
|
|
# Conflicts:
|
|
|
|
#{conflict_filenames.join("\n")}
|
|
|
|
EOM
|
|
|
|
end
|
2018-03-27 19:54:05 +05:30
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def cache
|
|
|
|
@cache ||= begin
|
|
|
|
# Use the commit ids as a namespace so if the MR branches get
|
|
|
|
# updated we instantiate the cache under a different namespace. That
|
|
|
|
# way don't have to worry about explicitly invalidating the cache
|
|
|
|
namespace = "#{@our_commit_id}:#{@their_commit_id}"
|
|
|
|
|
|
|
|
Gitlab::RepositoryCache.new(@target_repo, extra_namespace: namespace)
|
|
|
|
end
|
|
|
|
end
|
2016-09-13 17:45:13 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|