1//
2// Copyright 2017, Sander van Harmelen
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package gitlab
18
19import (
20 "fmt"
21 "time"
22)
23
24// MergeRequestsService handles communication with the merge requests related
25// methods of the GitLab API.
26//
27// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html
28type MergeRequestsService struct {
29 client *Client
30 timeStats *timeStatsService
31}
32
33// MergeRequest represents a GitLab merge request.
34//
35// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html
36type MergeRequest struct {
37 ID int `json:"id"`
38 IID int `json:"iid"`
39 TargetBranch string `json:"target_branch"`
40 SourceBranch string `json:"source_branch"`
41 ProjectID int `json:"project_id"`
42 Title string `json:"title"`
43 State string `json:"state"`
44 CreatedAt *time.Time `json:"created_at"`
45 UpdatedAt *time.Time `json:"updated_at"`
46 Upvotes int `json:"upvotes"`
47 Downvotes int `json:"downvotes"`
48 Author *BasicUser `json:"author"`
49 Assignee *BasicUser `json:"assignee"`
50 Assignees []*BasicUser `json:"assignees"`
51 SourceProjectID int `json:"source_project_id"`
52 TargetProjectID int `json:"target_project_id"`
53 Labels Labels `json:"labels"`
54 Description string `json:"description"`
55 WorkInProgress bool `json:"work_in_progress"`
56 Milestone *Milestone `json:"milestone"`
57 MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"`
58 MergeStatus string `json:"merge_status"`
59 MergeError string `json:"merge_error"`
60 MergedBy *BasicUser `json:"merged_by"`
61 MergedAt *time.Time `json:"merged_at"`
62 ClosedBy *BasicUser `json:"closed_by"`
63 ClosedAt *time.Time `json:"closed_at"`
64 Subscribed bool `json:"subscribed"`
65 SHA string `json:"sha"`
66 MergeCommitSHA string `json:"merge_commit_sha"`
67 UserNotesCount int `json:"user_notes_count"`
68 ChangesCount string `json:"changes_count"`
69 ShouldRemoveSourceBranch bool `json:"should_remove_source_branch"`
70 ForceRemoveSourceBranch bool `json:"force_remove_source_branch"`
71 WebURL string `json:"web_url"`
72 DiscussionLocked bool `json:"discussion_locked"`
73 Changes []struct {
74 OldPath string `json:"old_path"`
75 NewPath string `json:"new_path"`
76 AMode string `json:"a_mode"`
77 BMode string `json:"b_mode"`
78 Diff string `json:"diff"`
79 NewFile bool `json:"new_file"`
80 RenamedFile bool `json:"renamed_file"`
81 DeletedFile bool `json:"deleted_file"`
82 } `json:"changes"`
83 TimeStats *TimeStats `json:"time_stats"`
84 Squash bool `json:"squash"`
85 Pipeline *PipelineInfo `json:"pipeline"`
86 HeadPipeline *Pipeline `json:"head_pipeline"`
87 DiffRefs struct {
88 BaseSha string `json:"base_sha"`
89 HeadSha string `json:"head_sha"`
90 StartSha string `json:"start_sha"`
91 } `json:"diff_refs"`
92 DivergedCommitsCount int `json:"diverged_commits_count"`
93 RebaseInProgress bool `json:"rebase_in_progress"`
94 ApprovalsBeforeMerge int `json:"approvals_before_merge"`
95 Reference string `json:"reference"`
96 TaskCompletionStatus struct {
97 Count int `json:"count"`
98 CompletedCount int `json:"completed_count"`
99 } `json:"task_completion_status"`
100}
101
102func (m MergeRequest) String() string {
103 return Stringify(m)
104}
105
106// MergeRequestDiffVersion represents Gitlab merge request version.
107//
108// Gitlab API docs:
109// https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version
110type MergeRequestDiffVersion struct {
111 ID int `json:"id"`
112 HeadCommitSHA string `json:"head_commit_sha,omitempty"`
113 BaseCommitSHA string `json:"base_commit_sha,omitempty"`
114 StartCommitSHA string `json:"start_commit_sha,omitempty"`
115 CreatedAt *time.Time `json:"created_at,omitempty"`
116 MergeRequestID int `json:"merge_request_id,omitempty"`
117 State string `json:"state,omitempty"`
118 RealSize string `json:"real_size,omitempty"`
119 Commits []*Commit `json:"commits,omitempty"`
120 Diffs []*Diff `json:"diffs,omitempty"`
121}
122
123func (m MergeRequestDiffVersion) String() string {
124 return Stringify(m)
125}
126
127// ListMergeRequestsOptions represents the available ListMergeRequests()
128// options.
129//
130// GitLab API docs:
131// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
132type ListMergeRequestsOptions struct {
133 ListOptions
134 State *string `url:"state,omitempty" json:"state,omitempty"`
135 OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
136 Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
137 Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
138 View *string `url:"view,omitempty" json:"view,omitempty"`
139 Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
140 CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
141 CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
142 UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
143 UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
144 Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
145 AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
146 AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
147 MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
148 SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
149 TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
150 Search *string `url:"search,omitempty" json:"search,omitempty"`
151 In *string `url:"in,omitempty" json:"in,omitempty"`
152 WIP *string `url:"wip,omitempty" json:"wip,omitempty"`
153}
154
155// ListMergeRequests gets all merge requests. The state parameter can be used
156// to get only merge requests with a given state (opened, closed, or merged)
157// or all of them (all). The pagination parameters page and per_page can be
158// used to restrict the list of merge requests.
159//
160// GitLab API docs:
161// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
162func (s *MergeRequestsService) ListMergeRequests(opt *ListMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
163 req, err := s.client.NewRequest("GET", "merge_requests", opt, options)
164 if err != nil {
165 return nil, nil, err
166 }
167
168 var m []*MergeRequest
169 resp, err := s.client.Do(req, &m)
170 if err != nil {
171 return nil, resp, err
172 }
173
174 return m, resp, err
175}
176
177// ListGroupMergeRequestsOptions represents the available ListGroupMergeRequests()
178// options.
179//
180// GitLab API docs:
181// https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests
182type ListGroupMergeRequestsOptions struct {
183 ListOptions
184 State *string `url:"state,omitempty" json:"state,omitempty"`
185 OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
186 Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
187 Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
188 View *string `url:"view,omitempty" json:"view,omitempty"`
189 Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"`
190 CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
191 CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
192 UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
193 UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
194 Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
195 AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
196 AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
197 MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
198 SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
199 TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
200 Search *string `url:"search,omitempty" json:"search,omitempty"`
201}
202
203// ListGroupMergeRequests gets all merge requests for this group.
204//
205// GitLab API docs:
206// https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests
207func (s *MergeRequestsService) ListGroupMergeRequests(gid interface{}, opt *ListGroupMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
208 group, err := parseID(gid)
209 if err != nil {
210 return nil, nil, err
211 }
212 u := fmt.Sprintf("groups/%s/merge_requests", pathEscape(group))
213
214 req, err := s.client.NewRequest("GET", u, opt, options)
215 if err != nil {
216 return nil, nil, err
217 }
218
219 var m []*MergeRequest
220 resp, err := s.client.Do(req, &m)
221 if err != nil {
222 return nil, resp, err
223 }
224
225 return m, resp, err
226}
227
228// ListProjectMergeRequestsOptions represents the available ListMergeRequests()
229// options.
230//
231// GitLab API docs:
232// https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests
233type ListProjectMergeRequestsOptions struct {
234 ListOptions
235 IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"`
236 State *string `url:"state,omitempty" json:"state,omitempty"`
237 OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
238 Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
239 Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
240 View *string `url:"view,omitempty" json:"view,omitempty"`
241 Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"`
242 CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
243 CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
244 UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
245 UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
246 Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
247 AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
248 AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
249 MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
250 SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
251 TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
252 Search *string `url:"search,omitempty" json:"search,omitempty"`
253 WIP *string `url:"wip,omitempty" json:"wip,omitempty"`
254}
255
256// ListProjectMergeRequests gets all merge requests for this project.
257//
258// GitLab API docs:
259// https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests
260func (s *MergeRequestsService) ListProjectMergeRequests(pid interface{}, opt *ListProjectMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
261 project, err := parseID(pid)
262 if err != nil {
263 return nil, nil, err
264 }
265 u := fmt.Sprintf("projects/%s/merge_requests", pathEscape(project))
266
267 req, err := s.client.NewRequest("GET", u, opt, options)
268 if err != nil {
269 return nil, nil, err
270 }
271
272 var m []*MergeRequest
273 resp, err := s.client.Do(req, &m)
274 if err != nil {
275 return nil, resp, err
276 }
277
278 return m, resp, err
279}
280
281// GetMergeRequestsOptions represents the available GetMergeRequests()
282// options.
283//
284// GitLab API docs:
285// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr
286type GetMergeRequestsOptions struct {
287 RenderHTML *bool `url:"render_html,omitempty" json:"render_html,omitempty"`
288 IncludeDivergedCommitsCount *bool `url:"include_diverged_commits_count,omitempty" json:"include_diverged_commits_count,omitempty"`
289 IncludeRebaseInProgress *bool `url:"include_rebase_in_progress,omitempty" json:"include_rebase_in_progress,omitempty"`
290}
291
292// GetMergeRequest shows information about a single merge request.
293//
294// GitLab API docs:
295// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr
296func (s *MergeRequestsService) GetMergeRequest(pid interface{}, mergeRequest int, opt *GetMergeRequestsOptions, options ...OptionFunc) (*MergeRequest, *Response, error) {
297 project, err := parseID(pid)
298 if err != nil {
299 return nil, nil, err
300 }
301 u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest)
302
303 req, err := s.client.NewRequest("GET", u, opt, options)
304 if err != nil {
305 return nil, nil, err
306 }
307
308 m := new(MergeRequest)
309 resp, err := s.client.Do(req, m)
310 if err != nil {
311 return nil, resp, err
312 }
313
314 return m, resp, err
315}
316
317// GetMergeRequestApprovals gets information about a merge requests approvals
318//
319// GitLab API docs:
320// https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals
321func (s *MergeRequestsService) GetMergeRequestApprovals(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequestApprovals, *Response, error) {
322 project, err := parseID(pid)
323 if err != nil {
324 return nil, nil, err
325 }
326 u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", pathEscape(project), mergeRequest)
327
328 req, err := s.client.NewRequest("GET", u, nil, options)
329 if err != nil {
330 return nil, nil, err
331 }
332
333 a := new(MergeRequestApprovals)
334 resp, err := s.client.Do(req, a)
335 if err != nil {
336 return nil, resp, err
337 }
338
339 return a, resp, err
340}
341
342// GetMergeRequestCommitsOptions represents the available GetMergeRequestCommits()
343// options.
344//
345// GitLab API docs:
346// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits
347type GetMergeRequestCommitsOptions ListOptions
348
349// GetMergeRequestCommits gets a list of merge request commits.
350//
351// GitLab API docs:
352// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits
353func (s *MergeRequestsService) GetMergeRequestCommits(pid interface{}, mergeRequest int, opt *GetMergeRequestCommitsOptions, options ...OptionFunc) ([]*Commit, *Response, error) {
354 project, err := parseID(pid)
355 if err != nil {
356 return nil, nil, err
357 }
358 u := fmt.Sprintf("projects/%s/merge_requests/%d/commits", pathEscape(project), mergeRequest)
359
360 req, err := s.client.NewRequest("GET", u, opt, options)
361 if err != nil {
362 return nil, nil, err
363 }
364
365 var c []*Commit
366 resp, err := s.client.Do(req, &c)
367 if err != nil {
368 return nil, resp, err
369 }
370
371 return c, resp, err
372}
373
374// GetMergeRequestChanges shows information about the merge request including
375// its files and changes.
376//
377// GitLab API docs:
378// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes
379func (s *MergeRequestsService) GetMergeRequestChanges(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) {
380 project, err := parseID(pid)
381 if err != nil {
382 return nil, nil, err
383 }
384 u := fmt.Sprintf("projects/%s/merge_requests/%d/changes", pathEscape(project), mergeRequest)
385
386 req, err := s.client.NewRequest("GET", u, nil, options)
387 if err != nil {
388 return nil, nil, err
389 }
390
391 m := new(MergeRequest)
392 resp, err := s.client.Do(req, m)
393 if err != nil {
394 return nil, resp, err
395 }
396
397 return m, resp, err
398}
399
400// ListMergeRequestPipelines gets all pipelines for the provided merge request.
401//
402// GitLab API docs:
403// https://docs.gitlab.com/ce/api/merge_requests.html#list-mr-pipelines
404func (s *MergeRequestsService) ListMergeRequestPipelines(pid interface{}, mergeRequest int, options ...OptionFunc) ([]*PipelineInfo, *Response, error) {
405 project, err := parseID(pid)
406 if err != nil {
407 return nil, nil, err
408 }
409 u := fmt.Sprintf("projects/%s/merge_requests/%d/pipelines", pathEscape(project), mergeRequest)
410
411 req, err := s.client.NewRequest("GET", u, nil, options)
412 if err != nil {
413 return nil, nil, err
414 }
415
416 var p []*PipelineInfo
417 resp, err := s.client.Do(req, &p)
418 if err != nil {
419 return nil, resp, err
420 }
421
422 return p, resp, err
423}
424
425// GetIssuesClosedOnMergeOptions represents the available GetIssuesClosedOnMerge()
426// options.
427//
428// GitLab API docs:
429// https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge
430type GetIssuesClosedOnMergeOptions ListOptions
431
432// GetIssuesClosedOnMerge gets all the issues that would be closed by merging the
433// provided merge request.
434//
435// GitLab API docs:
436// https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge
437func (s *MergeRequestsService) GetIssuesClosedOnMerge(pid interface{}, mergeRequest int, opt *GetIssuesClosedOnMergeOptions, options ...OptionFunc) ([]*Issue, *Response, error) {
438 project, err := parseID(pid)
439 if err != nil {
440 return nil, nil, err
441 }
442 u := fmt.Sprintf("projects/%s/merge_requests/%d/closes_issues", pathEscape(project), mergeRequest)
443
444 req, err := s.client.NewRequest("GET", u, opt, options)
445 if err != nil {
446 return nil, nil, err
447 }
448
449 var i []*Issue
450 resp, err := s.client.Do(req, &i)
451 if err != nil {
452 return nil, resp, err
453 }
454
455 return i, resp, err
456}
457
458// CreateMergeRequestOptions represents the available CreateMergeRequest()
459// options.
460//
461// GitLab API docs:
462// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr
463type CreateMergeRequestOptions struct {
464 Title *string `url:"title,omitempty" json:"title,omitempty"`
465 Description *string `url:"description,omitempty" json:"description,omitempty"`
466 SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
467 TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
468 Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
469 AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
470 AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"`
471 TargetProjectID *int `url:"target_project_id,omitempty" json:"target_project_id,omitempty"`
472 MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
473 RemoveSourceBranch *bool `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"`
474 Squash *bool `url:"squash,omitempty" json:"squash,omitempty"`
475 AllowCollaboration *bool `url:"allow_collaboration,omitempty" json:"allow_collaboration,omitempty"`
476}
477
478// CreateMergeRequest creates a new merge request.
479//
480// GitLab API docs:
481// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr
482func (s *MergeRequestsService) CreateMergeRequest(pid interface{}, opt *CreateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) {
483 project, err := parseID(pid)
484 if err != nil {
485 return nil, nil, err
486 }
487 u := fmt.Sprintf("projects/%s/merge_requests", pathEscape(project))
488
489 req, err := s.client.NewRequest("POST", u, opt, options)
490 if err != nil {
491 return nil, nil, err
492 }
493
494 m := new(MergeRequest)
495 resp, err := s.client.Do(req, m)
496 if err != nil {
497 return nil, resp, err
498 }
499
500 return m, resp, err
501}
502
503// UpdateMergeRequestOptions represents the available UpdateMergeRequest()
504// options.
505//
506// GitLab API docs:
507// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
508type UpdateMergeRequestOptions struct {
509 Title *string `url:"title,omitempty" json:"title,omitempty"`
510 Description *string `url:"description,omitempty" json:"description,omitempty"`
511 TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
512 AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
513 AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"`
514 Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
515 MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
516 StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
517 RemoveSourceBranch *bool `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"`
518 Squash *bool `url:"squash,omitempty" json:"squash,omitempty"`
519 DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"`
520 AllowCollaboration *bool `url:"allow_collaboration,omitempty" json:"allow_collaboration,omitempty"`
521}
522
523// UpdateMergeRequest updates an existing project milestone.
524//
525// GitLab API docs:
526// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
527func (s *MergeRequestsService) UpdateMergeRequest(pid interface{}, mergeRequest int, opt *UpdateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) {
528 project, err := parseID(pid)
529 if err != nil {
530 return nil, nil, err
531 }
532 u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest)
533
534 req, err := s.client.NewRequest("PUT", u, opt, options)
535 if err != nil {
536 return nil, nil, err
537 }
538
539 m := new(MergeRequest)
540 resp, err := s.client.Do(req, m)
541 if err != nil {
542 return nil, resp, err
543 }
544
545 return m, resp, err
546}
547
548// DeleteMergeRequest deletes a merge request.
549//
550// GitLab API docs:
551// https://docs.gitlab.com/ce/api/merge_requests.html#delete-a-merge-request
552func (s *MergeRequestsService) DeleteMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*Response, error) {
553 project, err := parseID(pid)
554 if err != nil {
555 return nil, err
556 }
557 u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest)
558
559 req, err := s.client.NewRequest("DELETE", u, nil, options)
560 if err != nil {
561 return nil, err
562 }
563
564 return s.client.Do(req, nil)
565}
566
567// AcceptMergeRequestOptions represents the available AcceptMergeRequest()
568// options.
569//
570// GitLab API docs:
571// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr
572type AcceptMergeRequestOptions struct {
573 MergeCommitMessage *string `url:"merge_commit_message,omitempty" json:"merge_commit_message,omitempty"`
574 SquashCommitMessage *string `url:"squash_commit_message,omitempty" json:"squash_commit_message,omitempty"`
575 Squash *bool `url:"squash,omitempty" json:"squash,omitempty"`
576 ShouldRemoveSourceBranch *bool `url:"should_remove_source_branch,omitempty" json:"should_remove_source_branch,omitempty"`
577 MergeWhenPipelineSucceeds *bool `url:"merge_when_pipeline_succeeds,omitempty" json:"merge_when_pipeline_succeeds,omitempty"`
578 SHA *string `url:"sha,omitempty" json:"sha,omitempty"`
579}
580
581// AcceptMergeRequest merges changes submitted with MR using this API. If merge
582// success you get 200 OK. If it has some conflicts and can not be merged - you
583// get 405 and error message 'Branch cannot be merged'. If merge request is
584// already merged or closed - you get 405 and error message 'Method Not Allowed'
585//
586// GitLab API docs:
587// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr
588func (s *MergeRequestsService) AcceptMergeRequest(pid interface{}, mergeRequest int, opt *AcceptMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) {
589 project, err := parseID(pid)
590 if err != nil {
591 return nil, nil, err
592 }
593 u := fmt.Sprintf("projects/%s/merge_requests/%d/merge", pathEscape(project), mergeRequest)
594
595 req, err := s.client.NewRequest("PUT", u, opt, options)
596 if err != nil {
597 return nil, nil, err
598 }
599
600 m := new(MergeRequest)
601 resp, err := s.client.Do(req, m)
602 if err != nil {
603 return nil, resp, err
604 }
605
606 return m, resp, err
607}
608
609// CancelMergeWhenPipelineSucceeds cancels a merge when pipeline succeeds. If
610// you don't have permissions to accept this merge request - you'll get a 401.
611// If the merge request is already merged or closed - you get 405 and error
612// message 'Method Not Allowed'. In case the merge request is not set to be
613// merged when the pipeline succeeds, you'll also get a 406 error.
614//
615// GitLab API docs:
616// https://docs.gitlab.com/ce/api/merge_requests.html#cancel-merge-when-pipeline-succeeds
617func (s *MergeRequestsService) CancelMergeWhenPipelineSucceeds(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) {
618 project, err := parseID(pid)
619 if err != nil {
620 return nil, nil, err
621 }
622 u := fmt.Sprintf("projects/%s/merge_requests/%d/cancel_merge_when_pipeline_succeeds", pathEscape(project), mergeRequest)
623
624 req, err := s.client.NewRequest("PUT", u, nil, options)
625 if err != nil {
626 return nil, nil, err
627 }
628
629 m := new(MergeRequest)
630 resp, err := s.client.Do(req, m)
631 if err != nil {
632 return nil, resp, err
633 }
634
635 return m, resp, err
636}
637
638// RebaseMergeRequest automatically rebases the source_branch of the merge
639// request against its target_branch. If you don’t have permissions to push
640// to the merge request’s source branch, you’ll get a 403 Forbidden response.
641//
642// GitLab API docs:
643// https://docs.gitlab.com/ce/api/merge_requests.html#rebase-a-merge-request
644func (s *MergeRequestsService) RebaseMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*Response, error) {
645 project, err := parseID(pid)
646 if err != nil {
647 return nil, err
648 }
649 u := fmt.Sprintf("projects/%s/merge_requests/%d/rebase", pathEscape(project), mergeRequest)
650
651 req, err := s.client.NewRequest("PUT", u, nil, options)
652 if err != nil {
653 return nil, err
654 }
655
656 return s.client.Do(req, nil)
657}
658
659// GetMergeRequestDiffVersionsOptions represents the available
660// GetMergeRequestDiffVersions() options.
661//
662// GitLab API docs:
663// https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions
664type GetMergeRequestDiffVersionsOptions ListOptions
665
666// GetMergeRequestDiffVersions get a list of merge request diff versions.
667//
668// GitLab API docs:
669// https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions
670func (s *MergeRequestsService) GetMergeRequestDiffVersions(pid interface{}, mergeRequest int, opt *GetMergeRequestDiffVersionsOptions, options ...OptionFunc) ([]*MergeRequestDiffVersion, *Response, error) {
671 project, err := parseID(pid)
672 if err != nil {
673 return nil, nil, err
674 }
675 u := fmt.Sprintf("projects/%s/merge_requests/%d/versions", pathEscape(project), mergeRequest)
676
677 req, err := s.client.NewRequest("GET", u, opt, options)
678 if err != nil {
679 return nil, nil, err
680 }
681
682 var v []*MergeRequestDiffVersion
683 resp, err := s.client.Do(req, &v)
684 if err != nil {
685 return nil, resp, err
686 }
687
688 return v, resp, err
689}
690
691// GetSingleMergeRequestDiffVersion get a single MR diff version
692//
693// GitLab API docs:
694// https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version
695func (s *MergeRequestsService) GetSingleMergeRequestDiffVersion(pid interface{}, mergeRequest, version int, options ...OptionFunc) (*MergeRequestDiffVersion, *Response, error) {
696 project, err := parseID(pid)
697 if err != nil {
698 return nil, nil, err
699 }
700 u := fmt.Sprintf("projects/%s/merge_requests/%d/versions/%d", pathEscape(project), mergeRequest, version)
701
702 req, err := s.client.NewRequest("GET", u, nil, options)
703 if err != nil {
704 return nil, nil, err
705 }
706
707 var v = new(MergeRequestDiffVersion)
708 resp, err := s.client.Do(req, v)
709 if err != nil {
710 return nil, resp, err
711 }
712
713 return v, resp, err
714}
715
716// SubscribeToMergeRequest subscribes the authenticated user to the given merge
717// request to receive notifications. If the user is already subscribed to the
718// merge request, the status code 304 is returned.
719//
720// GitLab API docs:
721// https://docs.gitlab.com/ce/api/merge_requests.html#subscribe-to-a-merge-request
722func (s *MergeRequestsService) SubscribeToMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) {
723 project, err := parseID(pid)
724 if err != nil {
725 return nil, nil, err
726 }
727 u := fmt.Sprintf("projects/%s/merge_requests/%d/subscribe", pathEscape(project), mergeRequest)
728
729 req, err := s.client.NewRequest("POST", u, nil, options)
730 if err != nil {
731 return nil, nil, err
732 }
733
734 m := new(MergeRequest)
735 resp, err := s.client.Do(req, m)
736 if err != nil {
737 return nil, resp, err
738 }
739
740 return m, resp, err
741}
742
743// UnsubscribeFromMergeRequest unsubscribes the authenticated user from the
744// given merge request to not receive notifications from that merge request.
745// If the user is not subscribed to the merge request, status code 304 is
746// returned.
747//
748// GitLab API docs:
749// https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request
750func (s *MergeRequestsService) UnsubscribeFromMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) {
751 project, err := parseID(pid)
752 if err != nil {
753 return nil, nil, err
754 }
755 u := fmt.Sprintf("projects/%s/merge_requests/%d/unsubscribe", pathEscape(project), mergeRequest)
756
757 req, err := s.client.NewRequest("POST", u, nil, options)
758 if err != nil {
759 return nil, nil, err
760 }
761
762 m := new(MergeRequest)
763 resp, err := s.client.Do(req, m)
764 if err != nil {
765 return nil, resp, err
766 }
767
768 return m, resp, err
769}
770
771// CreateTodo manually creates a todo for the current user on a merge request.
772// If there already exists a todo for the user on that merge request,
773// status code 304 is returned.
774//
775// GitLab API docs:
776// https://docs.gitlab.com/ce/api/merge_requests.html#create-a-todo
777func (s *MergeRequestsService) CreateTodo(pid interface{}, mergeRequest int, options ...OptionFunc) (*Todo, *Response, error) {
778 project, err := parseID(pid)
779 if err != nil {
780 return nil, nil, err
781 }
782 u := fmt.Sprintf("projects/%s/merge_requests/%d/todo", pathEscape(project), mergeRequest)
783
784 req, err := s.client.NewRequest("POST", u, nil, options)
785 if err != nil {
786 return nil, nil, err
787 }
788
789 t := new(Todo)
790 resp, err := s.client.Do(req, t)
791 if err != nil {
792 return nil, resp, err
793 }
794
795 return t, resp, err
796}
797
798// SetTimeEstimate sets the time estimate for a single project merge request.
799//
800// GitLab API docs:
801// https://docs.gitlab.com/ce/api/merge_requests.html#set-a-time-estimate-for-a-merge-request
802func (s *MergeRequestsService) SetTimeEstimate(pid interface{}, mergeRequest int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) {
803 return s.timeStats.setTimeEstimate(pid, "merge_requests", mergeRequest, opt, options...)
804}
805
806// ResetTimeEstimate resets the time estimate for a single project merge request.
807//
808// GitLab API docs:
809// https://docs.gitlab.com/ce/api/merge_requests.html#reset-the-time-estimate-for-a-merge-request
810func (s *MergeRequestsService) ResetTimeEstimate(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) {
811 return s.timeStats.resetTimeEstimate(pid, "merge_requests", mergeRequest, options...)
812}
813
814// AddSpentTime adds spent time for a single project merge request.
815//
816// GitLab API docs:
817// https://docs.gitlab.com/ce/api/merge_requests.html#add-spent-time-for-a-merge-request
818func (s *MergeRequestsService) AddSpentTime(pid interface{}, mergeRequest int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) {
819 return s.timeStats.addSpentTime(pid, "merge_requests", mergeRequest, opt, options...)
820}
821
822// ResetSpentTime resets the spent time for a single project merge request.
823//
824// GitLab API docs:
825// https://docs.gitlab.com/ce/api/merge_requests.html#reset-spent-time-for-a-merge-request
826func (s *MergeRequestsService) ResetSpentTime(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) {
827 return s.timeStats.resetSpentTime(pid, "merge_requests", mergeRequest, options...)
828}
829
830// GetTimeSpent gets the spent time for a single project merge request.
831//
832// GitLab API docs:
833// https://docs.gitlab.com/ce/api/merge_requests.html#get-time-tracking-stats
834func (s *MergeRequestsService) GetTimeSpent(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) {
835 return s.timeStats.getTimeSpent(pid, "merge_requests", mergeRequest, options...)
836}