merge_requests.rb 7.12 KB
Newer Older
1
module API
Valeriy Sizov's avatar
Valeriy Sizov committed
2
  # MergeRequest API
3 4 5
  class MergeRequests < Grape::API
    before { authenticate! }

Hiroyuki Sato's avatar
Hiroyuki Sato committed
6
    resource :projects do
7
      helpers do
8 9 10
        def handle_merge_request_errors!(errors)
          if errors[:project_access].any?
            error!(errors[:project_access], 422)
11 12
          elsif errors[:branch_conflict].any?
            error!(errors[:branch_conflict], 422)
13
          end
14
          not_found!
15 16 17
        end
      end

Valeriy Sizov's avatar
Valeriy Sizov committed
18
      # List merge requests
19
      #
Valeriy Sizov's avatar
Valeriy Sizov committed
20
      # Parameters:
21
      #   id (required) - The ID of a project
22
      #   state (optional) - Return requests "merged", "opened" or "closed"
Valeriy Sizov's avatar
Valeriy Sizov committed
23 24
      #
      # Example:
25
      #   GET /projects/:id/merge_requests
26 27
      #   GET /projects/:id/merge_requests?state=opened
      #   GET /projects/:id/merge_requests?state=closed
Valeriy Sizov's avatar
Valeriy Sizov committed
28
      #
29
      get ":id/merge_requests" do
30
        authorize! :read_merge_request, user_project
31

32 33 34 35 36
        mrs = case params["state"]
              when "opened" then user_project.merge_requests.opened
              when "closed" then user_project.merge_requests.closed
              when "merged" then user_project.merge_requests.merged
              else user_project.merge_requests
37
              end
38 39

        present paginate(mrs), with: Entities::MergeRequest
40
      end
41

Valeriy Sizov's avatar
Valeriy Sizov committed
42
      # Show MR
43
      #
Valeriy Sizov's avatar
Valeriy Sizov committed
44
      # Parameters:
45
      #   id (required)               - The ID of a project
Valeriy Sizov's avatar
Valeriy Sizov committed
46
      #   merge_request_id (required) - The ID of MR
47
      #
Valeriy Sizov's avatar
Valeriy Sizov committed
48
      # Example:
49
      #   GET /projects/:id/merge_request/:merge_request_id
Valeriy Sizov's avatar
Valeriy Sizov committed
50
      #
51
      get ":id/merge_request/:merge_request_id" do
52
        merge_request = user_project.merge_requests.find(params[:merge_request_id])
53

54
        authorize! :read_merge_request, merge_request
55

56
        present merge_request, with: Entities::MergeRequest
57 58
      end

Valeriy Sizov's avatar
Valeriy Sizov committed
59 60 61 62
      # Create MR
      #
      # Parameters:
      #
63
      #   id (required)            - The ID of a project - this will be the source of the merge request
Valeriy Sizov's avatar
Valeriy Sizov committed
64 65
      #   source_branch (required) - The source branch
      #   target_branch (required) - The target branch
66
      #   target_project           - The target project of the merge request defaults to the :id of the project
Valeriy Sizov's avatar
Valeriy Sizov committed
67 68
      #   assignee_id              - Assignee user ID
      #   title (required)         - Title of MR
69
      #   description              - Description of MR
70
      #   labels (optional)        - Labels for MR as a comma-separated list
71
      #
Valeriy Sizov's avatar
Valeriy Sizov committed
72
      # Example:
73
      #   POST /projects/:id/merge_requests
Valeriy Sizov's avatar
Valeriy Sizov committed
74
      #
75
      post ":id/merge_requests" do
76 77 78
        authorize! :write_merge_request, user_project
        required_attributes! [:source_branch, :target_branch, :title]
        attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description]
79
        attrs[:label_list] = params[:labels] if params[:labels].present?
80
        merge_request = ::MergeRequests::CreateService.new(user_project, current_user, attrs).execute
Izaak Alpert's avatar
Izaak Alpert committed
81

82 83 84 85
        if merge_request.valid?
          present merge_request, with: Entities::MergeRequest
        else
          handle_merge_request_errors! merge_request.errors
Valeriy Sizov's avatar
Valeriy Sizov committed
86
        end
87 88
      end

Valeriy Sizov's avatar
Valeriy Sizov committed
89 90 91
      # Update MR
      #
      # Parameters:
92
      #   id (required)               - The ID of a project
Valeriy Sizov's avatar
Valeriy Sizov committed
93 94 95 96 97
      #   merge_request_id (required) - ID of MR
      #   source_branch               - The source branch
      #   target_branch               - The target branch
      #   assignee_id                 - Assignee user ID
      #   title                       - Title of MR
98
      #   state_event                 - Status of MR. (close|reopen|merge)
99
      #   description                 - Description of MR
100
      #   labels (optional)           - Labels for a MR as a comma-separated list
Valeriy Sizov's avatar
Valeriy Sizov committed
101
      # Example:
102
      #   PUT /projects/:id/merge_request/:merge_request_id
Valeriy Sizov's avatar
Valeriy Sizov committed
103
      #
104
      put ":id/merge_request/:merge_request_id" do
105
        attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event, :description]
106
        attrs[:label_list] = params[:labels] if params[:labels].present?
107 108 109
        merge_request = user_project.merge_requests.find(params[:merge_request_id])
        authorize! :modify_merge_request, merge_request
        merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request)
110

111 112 113 114
        if merge_request.valid?
          present merge_request, with: Entities::MergeRequest
        else
          handle_merge_request_errors! merge_request.errors
115
        end
116 117
      end

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
      # Merge MR
      #
      # Parameters:
      #   id (required)               - The ID of a project
      #   merge_request_id (required) - ID of MR
      #   merge_commit_message (optional) - Custom merge commit message
      # Example:
      #   PUT /projects/:id/merge_request/:merge_request_id/merge
      #
      put ":id/merge_request/:merge_request_id/merge" do
        merge_request = user_project.merge_requests.find(params[:merge_request_id])

        action = if user_project.protected_branch?(merge_request.target_branch)
                   :push_code_to_protected_branches
                 else
                   :push_code
                 end

136
        if can?(current_user, action, user_project)
137 138 139 140
          if merge_request.unchecked?
            merge_request.check_if_can_be_merged
          end

141 142 143
          if merge_request.open?
            if merge_request.can_be_merged?
              merge_request.automerge!(current_user, params[:merge_commit_message] || merge_request.merge_commit_message)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
144
              present merge_request, with: Entities::MergeRequest
145 146 147
            else
              render_api_error!('Branch cannot be merged', 405)
            end
148
          else
149 150 151
            # Merge request can not be merged
            # because it is already closed/merged
            not_allowed!
152 153
          end
        else
154 155 156
          # Merge request can not be merged
          # because user dont have permissions to push into target branch
          unauthorized!
157 158 159 160
        end
      end


161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
      # Get a merge request's comments
      #
      # Parameters:
      #   id (required) - The ID of a project
      #   merge_request_id (required) - ID of MR
      # Examples:
      #   GET /projects/:id/merge_request/:merge_request_id/comments
      #
      get ":id/merge_request/:merge_request_id/comments" do
        merge_request = user_project.merge_requests.find(params[:merge_request_id])

        authorize! :read_merge_request, merge_request

        present paginate(merge_request.notes), with: Entities::MRNote
      end

Valeriy Sizov's avatar
Valeriy Sizov committed
177 178 179
      # Post comment to merge request
      #
      # Parameters:
180
      #   id (required) - The ID of a project
Valeriy Sizov's avatar
Valeriy Sizov committed
181 182
      #   merge_request_id (required) - ID of MR
      #   note (required) - Text of comment
183
      # Examples:
184
      #   POST /projects/:id/merge_request/:merge_request_id/comments
Valeriy Sizov's avatar
Valeriy Sizov committed
185
      #
186
      post ":id/merge_request/:merge_request_id/comments" do
187
        required_attributes! [:note]
188

189 190 191
        merge_request = user_project.merge_requests.find(params[:merge_request_id])
        note = merge_request.notes.new(note: params[:note], project_id: user_project.id)
        note.author = current_user
Valeriy Sizov's avatar
Valeriy Sizov committed
192

193 194 195 196
        if note.save
          present note, with: Entities::MRNote
        else
          not_found!
197 198
        end
      end
199 200 201
    end
  end
end