summaryrefslogtreecommitdiff
path: root/app/services/merge_requests/update_service.rb
blob: e042c0a64340aba6dbaf627c39ea6deb9bc66045 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# frozen_string_literal: true

module MergeRequests
  class UpdateService < MergeRequests::BaseService
    def execute(merge_request)
      # We don't allow change of source/target projects and source branch
      # after merge request was created
      params.delete(:source_project_id)
      params.delete(:target_project_id)
      params.delete(:source_branch)

      merge_from_quick_action(merge_request) if params[:merge]

      if merge_request.closed_without_fork?
        params.delete(:target_branch)
        params.delete(:force_remove_source_branch)
      end

      if params.has_key?(:force_remove_source_branch)
        merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch)
      end

      handle_wip_event(merge_request)
      update_task_event(merge_request) || update(merge_request)
    end

    # rubocop:disable Metrics/AbcSize
    def handle_changes(merge_request, options)
      old_associations = options.fetch(:old_associations, {})
      old_labels = old_associations.fetch(:labels, [])
      old_mentioned_users = old_associations.fetch(:mentioned_users, [])

      if has_changes?(merge_request, old_labels: old_labels)
        todo_service.mark_pending_todos_as_done(merge_request, current_user)
      end

      if merge_request.previous_changes.include?('title') ||
          merge_request.previous_changes.include?('description')
        todo_service.update_merge_request(merge_request, current_user, old_mentioned_users)
      end

      if merge_request.previous_changes.include?('target_branch')
        create_branch_change_note(merge_request, 'target',
                                  merge_request.previous_changes['target_branch'].first,
                                  merge_request.target_branch)
      end

      if merge_request.previous_changes.include?('assignee_id')
        reassigned_merge_request_args = [merge_request, current_user]

        old_assignee_id = merge_request.previous_changes['assignee_id'].first
        reassigned_merge_request_args << User.find(old_assignee_id) if old_assignee_id

        create_assignee_note(merge_request)
        notification_service.async.reassigned_merge_request(*reassigned_merge_request_args)
        todo_service.reassigned_merge_request(merge_request, current_user)
      end

      if merge_request.previous_changes.include?('target_branch') ||
          merge_request.previous_changes.include?('source_branch')
        merge_request.mark_as_unchecked
      end

      handle_milestone_change(merge_request)

      added_labels = merge_request.labels - old_labels
      if added_labels.present?
        notification_service.async.relabeled_merge_request(
          merge_request,
          added_labels,
          current_user
        )
      end

      added_mentions = merge_request.mentioned_users - old_mentioned_users
      if added_mentions.present?
        notification_service.async.new_mentions_in_merge_request(
          merge_request,
          added_mentions,
          current_user
        )
      end
    end
    # rubocop:enable Metrics/AbcSize

    def handle_task_changes(merge_request)
      todo_service.mark_pending_todos_as_done(merge_request, current_user)
      todo_service.update_merge_request(merge_request, current_user)
    end

    def merge_from_quick_action(merge_request)
      last_diff_sha = params.delete(:merge)
      return unless merge_request.mergeable_with_quick_action?(current_user, last_diff_sha: last_diff_sha)

      merge_request.update(merge_error: nil)

      if merge_request.head_pipeline && merge_request.head_pipeline.active?
        MergeRequests::MergeWhenPipelineSucceedsService.new(project, current_user).execute(merge_request)
      else
        merge_request.merge_async(current_user.id, {})
      end
    end

    def reopen_service
      MergeRequests::ReopenService
    end

    def close_service
      MergeRequests::CloseService
    end

    def after_update(issuable)
      issuable.cache_merge_request_closes_issues!(current_user)
    end

    private

    def handle_milestone_change(merge_request)
      return if skip_milestone_email

      return unless merge_request.previous_changes.include?('milestone_id')

      if merge_request.milestone.nil?
        notification_service.async.removed_milestone_merge_request(merge_request, current_user)
      else
        notification_service.async.changed_milestone_merge_request(merge_request, merge_request.milestone, current_user)
      end
    end

    def create_branch_change_note(issuable, branch_type, old_branch, new_branch)
      SystemNoteService.change_branch(
        issuable, issuable.project, current_user, branch_type,
        old_branch, new_branch)
    end
  end
end