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