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