2020-06-08 20:08:47 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
module Suggestions
|
|
|
|
class SuggestionSet
|
|
|
|
attr_reader :suggestions
|
|
|
|
|
|
|
|
def initialize(suggestions)
|
|
|
|
@suggestions = suggestions
|
|
|
|
end
|
|
|
|
|
|
|
|
def project
|
|
|
|
first_suggestion.project
|
|
|
|
end
|
|
|
|
|
|
|
|
def branch
|
|
|
|
first_suggestion.branch
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid?
|
|
|
|
error_message.nil?
|
|
|
|
end
|
|
|
|
|
|
|
|
def error_message
|
|
|
|
@error_message ||= _error_message
|
|
|
|
end
|
|
|
|
|
|
|
|
def actions
|
2020-06-22 08:08:47 -04:00
|
|
|
@actions ||= suggestions_per_file.map do |file_suggestion|
|
2020-06-08 20:08:47 -04:00
|
|
|
{
|
|
|
|
action: 'update',
|
2020-06-22 08:08:47 -04:00
|
|
|
file_path: file_suggestion.file_path,
|
2020-06-08 20:08:47 -04:00
|
|
|
content: file_suggestion.new_content
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def file_paths
|
|
|
|
@file_paths ||= suggestions.map(&:file_path).uniq
|
|
|
|
end
|
|
|
|
|
2021-04-23 14:10:18 -04:00
|
|
|
def authors
|
|
|
|
suggestions.map { |suggestion| suggestion.note.author }.uniq
|
|
|
|
end
|
|
|
|
|
2020-06-08 20:08:47 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
def first_suggestion
|
|
|
|
suggestions.first
|
|
|
|
end
|
|
|
|
|
|
|
|
def suggestions_per_file
|
|
|
|
@suggestions_per_file ||= _suggestions_per_file
|
|
|
|
end
|
|
|
|
|
|
|
|
def _suggestions_per_file
|
2020-06-22 08:08:47 -04:00
|
|
|
suggestions
|
|
|
|
.group_by { |suggestion| suggestion.diff_file.file_path }
|
|
|
|
.map { |file_path, group| FileSuggestion.new(file_path, group) }
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def _error_message
|
|
|
|
suggestions.each do |suggestion|
|
|
|
|
message = error_for_suggestion(suggestion)
|
|
|
|
|
|
|
|
return message if message
|
|
|
|
end
|
|
|
|
|
2020-06-22 08:08:47 -04:00
|
|
|
has_line_conflict = suggestions_per_file.any? do |file_suggestion|
|
2020-06-08 20:08:47 -04:00
|
|
|
file_suggestion.line_conflict?
|
|
|
|
end
|
|
|
|
|
|
|
|
if has_line_conflict
|
|
|
|
return _('Suggestions are not applicable as their lines cannot overlap.')
|
|
|
|
end
|
|
|
|
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def error_for_suggestion(suggestion)
|
|
|
|
unless suggestion.diff_file
|
|
|
|
return _('A file was not found.')
|
|
|
|
end
|
|
|
|
|
|
|
|
unless on_same_branch?(suggestion)
|
|
|
|
return _('Suggestions must all be on the same branch.')
|
|
|
|
end
|
|
|
|
|
|
|
|
unless suggestion.appliable?(cached: false)
|
2020-07-21 05:09:34 -04:00
|
|
|
return suggestion.inapplicable_reason(cached: false)
|
2020-06-08 20:08:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
unless latest_source_head?(suggestion)
|
|
|
|
return _('A file has been changed.')
|
|
|
|
end
|
|
|
|
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_same_branch?(suggestion)
|
|
|
|
branch == suggestion.branch
|
|
|
|
end
|
|
|
|
|
|
|
|
# Checks whether the latest source branch HEAD matches with
|
|
|
|
# the position HEAD we're using to update the file content. Since
|
|
|
|
# the persisted HEAD is updated async (for MergeRequest),
|
|
|
|
# it's more consistent to fetch this data directly from the
|
|
|
|
# repository.
|
|
|
|
def latest_source_head?(suggestion)
|
|
|
|
suggestion.position.head_sha == suggestion.noteable.source_branch_sha
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|