summaryrefslogtreecommitdiff
path: root/app/services/suggestions/apply_service.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/suggestions/apply_service.rb')
-rw-r--r--app/services/suggestions/apply_service.rb110
1 files changed, 25 insertions, 85 deletions
diff --git a/app/services/suggestions/apply_service.rb b/app/services/suggestions/apply_service.rb
index 479eed3ce57..ab80b23a37b 100644
--- a/app/services/suggestions/apply_service.rb
+++ b/app/services/suggestions/apply_service.rb
@@ -2,109 +2,49 @@
module Suggestions
class ApplyService < ::BaseService
- DEFAULT_SUGGESTION_COMMIT_MESSAGE = 'Apply suggestion to %{file_path}'
-
- PLACEHOLDERS = {
- 'project_path' => ->(suggestion, user) { suggestion.project.path },
- 'project_name' => ->(suggestion, user) { suggestion.project.name },
- 'file_path' => ->(suggestion, user) { suggestion.file_path },
- 'branch_name' => ->(suggestion, user) { suggestion.branch },
- 'username' => ->(suggestion, user) { user.username },
- 'user_full_name' => ->(suggestion, user) { user.name }
- }.freeze
-
- # This regex is built dynamically using the keys from the PLACEHOLDER struct.
- # So, we can easily add new placeholder just by modifying the PLACEHOLDER hash.
- # This regex will build the new PLACEHOLDER_REGEX with the new information
- PLACEHOLDERS_REGEX = Regexp.union(PLACEHOLDERS.keys.map { |key| Regexp.new(Regexp.escape(key)) }).freeze
-
- attr_reader :current_user
-
- def initialize(current_user)
+ def initialize(current_user, *suggestions)
@current_user = current_user
+ @suggestion_set = Gitlab::Suggestions::SuggestionSet.new(suggestions)
end
- def execute(suggestion)
- unless suggestion.appliable?(cached: false)
- return error('Suggestion is not appliable')
- end
-
- unless latest_source_head?(suggestion)
- return error('The file has been changed')
+ def execute
+ if suggestion_set.valid?
+ result
+ else
+ error(suggestion_set.error_message)
end
+ end
- diff_file = suggestion.diff_file
-
- unless diff_file
- return error('The file was not found')
- end
+ private
- params = file_update_params(suggestion, diff_file)
- result = ::Files::UpdateService.new(suggestion.project, current_user, params).execute
+ attr_reader :current_user, :suggestion_set
- if result[:status] == :success
- suggestion.update(commit_id: result[:result], applied: true)
+ def result
+ multi_service.execute.tap do |result|
+ update_suggestions(result)
end
-
- result
- rescue Files::UpdateService::FileChangedError
- error('The file has been changed')
end
- private
+ def update_suggestions(result)
+ return unless result[:status] == :success
- # 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
+ Suggestion.id_in(suggestion_set.suggestions)
+ .update_all(commit_id: result[:result], applied: true)
end
- def file_update_params(suggestion, diff_file)
- blob = diff_file.new_blob
- project = suggestion.project
- file_path = suggestion.file_path
- branch_name = suggestion.branch
- file_content = new_file_content(suggestion, blob)
- commit_message = processed_suggestion_commit_message(suggestion)
-
- file_last_commit =
- Gitlab::Git::Commit.last_for_path(project.repository,
- blob.commit_id,
- blob.path)
-
- {
- file_path: file_path,
- branch_name: branch_name,
- start_branch: branch_name,
+ def multi_service
+ params = {
commit_message: commit_message,
- file_content: file_content,
- last_commit_sha: file_last_commit&.id
+ branch_name: suggestion_set.branch,
+ start_branch: suggestion_set.branch,
+ actions: suggestion_set.actions
}
- end
-
- def new_file_content(suggestion, blob)
- range = suggestion.from_line_index..suggestion.to_line_index
- blob.load_all_data!
- content = blob.data.lines
- content[range] = suggestion.to_content
-
- content.join
- end
-
- def suggestion_commit_message(project)
- project.suggestion_commit_message.presence || DEFAULT_SUGGESTION_COMMIT_MESSAGE
+ ::Files::MultiService.new(suggestion_set.project, current_user, params)
end
- def processed_suggestion_commit_message(suggestion)
- message = suggestion_commit_message(suggestion.project)
-
- Gitlab::StringPlaceholderReplacer.replace_string_placeholders(message, PLACEHOLDERS_REGEX) do |key|
- PLACEHOLDERS[key].call(suggestion, current_user)
- end
+ def commit_message
+ Gitlab::Suggestions::CommitMessage.new(current_user, suggestion_set).message
end
end
end