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 "net/url"
22)
23
24// BranchesService handles communication with the branch related methods
25// of the GitLab API.
26//
27// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html
28type BranchesService struct {
29 client *Client
30}
31
32// Branch represents a GitLab branch.
33//
34// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html
35type Branch struct {
36 Commit *Commit `json:"commit"`
37 Name string `json:"name"`
38 Protected bool `json:"protected"`
39 Merged bool `json:"merged"`
40 Default bool `json:"default"`
41 DevelopersCanPush bool `json:"developers_can_push"`
42 DevelopersCanMerge bool `json:"developers_can_merge"`
43}
44
45func (b Branch) String() string {
46 return Stringify(b)
47}
48
49// ListBranchesOptions represents the available ListBranches() options.
50//
51// GitLab API docs:
52// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches
53type ListBranchesOptions struct {
54 ListOptions
55 Search *string `url:"search,omitempty" json:"search,omitempty"`
56}
57
58// ListBranches gets a list of repository branches from a project, sorted by
59// name alphabetically.
60//
61// GitLab API docs:
62// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches
63func (s *BranchesService) ListBranches(pid interface{}, opts *ListBranchesOptions, options ...OptionFunc) ([]*Branch, *Response, error) {
64 project, err := parseID(pid)
65 if err != nil {
66 return nil, nil, err
67 }
68 u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project))
69
70 req, err := s.client.NewRequest("GET", u, opts, options)
71 if err != nil {
72 return nil, nil, err
73 }
74
75 var b []*Branch
76 resp, err := s.client.Do(req, &b)
77 if err != nil {
78 return nil, resp, err
79 }
80
81 return b, resp, err
82}
83
84// GetBranch gets a single project repository branch.
85//
86// GitLab API docs:
87// https://docs.gitlab.com/ce/api/branches.html#get-single-repository-branch
88func (s *BranchesService) GetBranch(pid interface{}, branch string, options ...OptionFunc) (*Branch, *Response, error) {
89 project, err := parseID(pid)
90 if err != nil {
91 return nil, nil, err
92 }
93 u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch))
94
95 req, err := s.client.NewRequest("GET", u, nil, options)
96 if err != nil {
97 return nil, nil, err
98 }
99
100 b := new(Branch)
101 resp, err := s.client.Do(req, b)
102 if err != nil {
103 return nil, resp, err
104 }
105
106 return b, resp, err
107}
108
109// ProtectBranchOptions represents the available ProtectBranch() options.
110//
111// GitLab API docs:
112// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch
113type ProtectBranchOptions struct {
114 DevelopersCanPush *bool `url:"developers_can_push,omitempty" json:"developers_can_push,omitempty"`
115 DevelopersCanMerge *bool `url:"developers_can_merge,omitempty" json:"developers_can_merge,omitempty"`
116}
117
118// ProtectBranch protects a single project repository branch. This is an
119// idempotent function, protecting an already protected repository branch
120// still returns a 200 OK status code.
121//
122// GitLab API docs:
123// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch
124func (s *BranchesService) ProtectBranch(pid interface{}, branch string, opts *ProtectBranchOptions, options ...OptionFunc) (*Branch, *Response, error) {
125 project, err := parseID(pid)
126 if err != nil {
127 return nil, nil, err
128 }
129 u := fmt.Sprintf("projects/%s/repository/branches/%s/protect", pathEscape(project), url.PathEscape(branch))
130
131 req, err := s.client.NewRequest("PUT", u, opts, options)
132 if err != nil {
133 return nil, nil, err
134 }
135
136 b := new(Branch)
137 resp, err := s.client.Do(req, b)
138 if err != nil {
139 return nil, resp, err
140 }
141
142 return b, resp, err
143}
144
145// UnprotectBranch unprotects a single project repository branch. This is an
146// idempotent function, unprotecting an already unprotected repository branch
147// still returns a 200 OK status code.
148//
149// GitLab API docs:
150// https://docs.gitlab.com/ce/api/branches.html#unprotect-repository-branch
151func (s *BranchesService) UnprotectBranch(pid interface{}, branch string, options ...OptionFunc) (*Branch, *Response, error) {
152 project, err := parseID(pid)
153 if err != nil {
154 return nil, nil, err
155 }
156 u := fmt.Sprintf("projects/%s/repository/branches/%s/unprotect", pathEscape(project), url.PathEscape(branch))
157
158 req, err := s.client.NewRequest("PUT", u, nil, options)
159 if err != nil {
160 return nil, nil, err
161 }
162
163 b := new(Branch)
164 resp, err := s.client.Do(req, b)
165 if err != nil {
166 return nil, resp, err
167 }
168
169 return b, resp, err
170}
171
172// CreateBranchOptions represents the available CreateBranch() options.
173//
174// GitLab API docs:
175// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch
176type CreateBranchOptions struct {
177 Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
178 Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
179}
180
181// CreateBranch creates branch from commit SHA or existing branch.
182//
183// GitLab API docs:
184// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch
185func (s *BranchesService) CreateBranch(pid interface{}, opt *CreateBranchOptions, options ...OptionFunc) (*Branch, *Response, error) {
186 project, err := parseID(pid)
187 if err != nil {
188 return nil, nil, err
189 }
190 u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project))
191
192 req, err := s.client.NewRequest("POST", u, opt, options)
193 if err != nil {
194 return nil, nil, err
195 }
196
197 b := new(Branch)
198 resp, err := s.client.Do(req, b)
199 if err != nil {
200 return nil, resp, err
201 }
202
203 return b, resp, err
204}
205
206// DeleteBranch deletes an existing branch.
207//
208// GitLab API docs:
209// https://docs.gitlab.com/ce/api/branches.html#delete-repository-branch
210func (s *BranchesService) DeleteBranch(pid interface{}, branch string, options ...OptionFunc) (*Response, error) {
211 project, err := parseID(pid)
212 if err != nil {
213 return nil, err
214 }
215 u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch))
216
217 req, err := s.client.NewRequest("DELETE", u, nil, options)
218 if err != nil {
219 return nil, err
220 }
221
222 return s.client.Do(req, nil)
223}
224
225// DeleteMergedBranches deletes all branches that are merged into the project's default branch.
226//
227// GitLab API docs:
228// https://docs.gitlab.com/ce/api/branches.html#delete-merged-branches
229func (s *BranchesService) DeleteMergedBranches(pid interface{}, options ...OptionFunc) (*Response, error) {
230 project, err := parseID(pid)
231 if err != nil {
232 return nil, err
233 }
234 u := fmt.Sprintf("projects/%s/repository/merged_branches", pathEscape(project))
235
236 req, err := s.client.NewRequest("DELETE", u, nil, options)
237 if err != nil {
238 return nil, err
239 }
240
241 return s.client.Do(req, nil)
242}