diff options
Diffstat (limited to 'app/services/suggestions/apply_service.rb')
-rw-r--r-- | app/services/suggestions/apply_service.rb | 110 |
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 |