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 "bytes"
21 "fmt"
22 "io"
23)
24
25// RepositoriesService handles communication with the repositories related
26// methods of the GitLab API.
27//
28// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html
29type RepositoriesService struct {
30 client *Client
31}
32
33// TreeNode represents a GitLab repository file or directory.
34//
35// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html
36type TreeNode struct {
37 ID string `json:"id"`
38 Name string `json:"name"`
39 Type string `json:"type"`
40 Path string `json:"path"`
41 Mode string `json:"mode"`
42}
43
44func (t TreeNode) String() string {
45 return Stringify(t)
46}
47
48// ListTreeOptions represents the available ListTree() options.
49//
50// GitLab API docs:
51// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree
52type ListTreeOptions struct {
53 ListOptions
54 Path *string `url:"path,omitempty" json:"path,omitempty"`
55 Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
56 Recursive *bool `url:"recursive,omitempty" json:"recursive,omitempty"`
57}
58
59// ListTree gets a list of repository files and directories in a project.
60//
61// GitLab API docs:
62// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree
63func (s *RepositoriesService) ListTree(pid interface{}, opt *ListTreeOptions, options ...OptionFunc) ([]*TreeNode, *Response, error) {
64 project, err := parseID(pid)
65 if err != nil {
66 return nil, nil, err
67 }
68 u := fmt.Sprintf("projects/%s/repository/tree", pathEscape(project))
69
70 req, err := s.client.NewRequest("GET", u, opt, options)
71 if err != nil {
72 return nil, nil, err
73 }
74
75 var t []*TreeNode
76 resp, err := s.client.Do(req, &t)
77 if err != nil {
78 return nil, resp, err
79 }
80
81 return t, resp, err
82}
83
84// Blob gets information about blob in repository like size and content. Note
85// that blob content is Base64 encoded.
86//
87// GitLab API docs:
88// https://docs.gitlab.com/ce/api/repositories.html#get-a-blob-from-repository
89func (s *RepositoriesService) Blob(pid interface{}, sha string, options ...OptionFunc) ([]byte, *Response, error) {
90 project, err := parseID(pid)
91 if err != nil {
92 return nil, nil, err
93 }
94 u := fmt.Sprintf("projects/%s/repository/blobs/%s", pathEscape(project), sha)
95
96 req, err := s.client.NewRequest("GET", u, nil, options)
97 if err != nil {
98 return nil, nil, err
99 }
100
101 var b bytes.Buffer
102 resp, err := s.client.Do(req, &b)
103 if err != nil {
104 return nil, resp, err
105 }
106
107 return b.Bytes(), resp, err
108}
109
110// RawBlobContent gets the raw file contents for a blob by blob SHA.
111//
112// GitLab API docs:
113// https://docs.gitlab.com/ce/api/repositories.html#raw-blob-content
114func (s *RepositoriesService) RawBlobContent(pid interface{}, sha string, options ...OptionFunc) ([]byte, *Response, error) {
115 project, err := parseID(pid)
116 if err != nil {
117 return nil, nil, err
118 }
119 u := fmt.Sprintf("projects/%s/repository/blobs/%s/raw", pathEscape(project), sha)
120
121 req, err := s.client.NewRequest("GET", u, nil, options)
122 if err != nil {
123 return nil, nil, err
124 }
125
126 var b bytes.Buffer
127 resp, err := s.client.Do(req, &b)
128 if err != nil {
129 return nil, resp, err
130 }
131
132 return b.Bytes(), resp, err
133}
134
135// ArchiveOptions represents the available Archive() options.
136//
137// GitLab API docs:
138// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive
139type ArchiveOptions struct {
140 Format *string `url:"-" json:"-"`
141 SHA *string `url:"sha,omitempty" json:"sha,omitempty"`
142}
143
144// Archive gets an archive of the repository.
145//
146// GitLab API docs:
147// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive
148func (s *RepositoriesService) Archive(pid interface{}, opt *ArchiveOptions, options ...OptionFunc) ([]byte, *Response, error) {
149 project, err := parseID(pid)
150 if err != nil {
151 return nil, nil, err
152 }
153 u := fmt.Sprintf("projects/%s/repository/archive", pathEscape(project))
154
155 // Set an optional format for the archive.
156 if opt != nil && opt.Format != nil {
157 u = fmt.Sprintf("%s.%s", u, *opt.Format)
158 }
159
160 req, err := s.client.NewRequest("GET", u, opt, options)
161 if err != nil {
162 return nil, nil, err
163 }
164
165 var b bytes.Buffer
166 resp, err := s.client.Do(req, &b)
167 if err != nil {
168 return nil, resp, err
169 }
170
171 return b.Bytes(), resp, err
172}
173
174// StreamArchive streams an archive of the repository to the provided
175// io.Writer.
176//
177// GitLab API docs:
178// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive
179func (s *RepositoriesService) StreamArchive(pid interface{}, w io.Writer, opt *ArchiveOptions, options ...OptionFunc) (*Response, error) {
180 project, err := parseID(pid)
181 if err != nil {
182 return nil, err
183 }
184 u := fmt.Sprintf("projects/%s/repository/archive", pathEscape(project))
185
186 // Set an optional format for the archive.
187 if opt != nil && opt.Format != nil {
188 u = fmt.Sprintf("%s.%s", u, *opt.Format)
189 }
190
191 req, err := s.client.NewRequest("GET", u, opt, options)
192 if err != nil {
193 return nil, err
194 }
195
196 return s.client.Do(req, w)
197}
198
199// Compare represents the result of a comparison of branches, tags or commits.
200//
201// GitLab API docs:
202// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits
203type Compare struct {
204 Commit *Commit `json:"commit"`
205 Commits []*Commit `json:"commits"`
206 Diffs []*Diff `json:"diffs"`
207 CompareTimeout bool `json:"compare_timeout"`
208 CompareSameRef bool `json:"compare_same_ref"`
209}
210
211func (c Compare) String() string {
212 return Stringify(c)
213}
214
215// CompareOptions represents the available Compare() options.
216//
217// GitLab API docs:
218// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits
219type CompareOptions struct {
220 From *string `url:"from,omitempty" json:"from,omitempty"`
221 To *string `url:"to,omitempty" json:"to,omitempty"`
222 Straight *bool `url:"straight,omitempty" json:"straight,omitempty"`
223}
224
225// Compare compares branches, tags or commits.
226//
227// GitLab API docs:
228// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits
229func (s *RepositoriesService) Compare(pid interface{}, opt *CompareOptions, options ...OptionFunc) (*Compare, *Response, error) {
230 project, err := parseID(pid)
231 if err != nil {
232 return nil, nil, err
233 }
234 u := fmt.Sprintf("projects/%s/repository/compare", pathEscape(project))
235
236 req, err := s.client.NewRequest("GET", u, opt, options)
237 if err != nil {
238 return nil, nil, err
239 }
240
241 c := new(Compare)
242 resp, err := s.client.Do(req, c)
243 if err != nil {
244 return nil, resp, err
245 }
246
247 return c, resp, err
248}
249
250// Contributor represents a GitLap contributor.
251//
252// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors
253type Contributor struct {
254 Name string `json:"name"`
255 Email string `json:"email"`
256 Commits int `json:"commits"`
257 Additions int `json:"additions"`
258 Deletions int `json:"deletions"`
259}
260
261func (c Contributor) String() string {
262 return Stringify(c)
263}
264
265// ListContributorsOptions represents the available ListContributors() options.
266//
267// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors
268type ListContributorsOptions ListOptions
269
270// Contributors gets the repository contributors list.
271//
272// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors
273func (s *RepositoriesService) Contributors(pid interface{}, opt *ListContributorsOptions, options ...OptionFunc) ([]*Contributor, *Response, error) {
274 project, err := parseID(pid)
275 if err != nil {
276 return nil, nil, err
277 }
278 u := fmt.Sprintf("projects/%s/repository/contributors", pathEscape(project))
279
280 req, err := s.client.NewRequest("GET", u, opt, options)
281 if err != nil {
282 return nil, nil, err
283 }
284
285 var c []*Contributor
286 resp, err := s.client.Do(req, &c)
287 if err != nil {
288 return nil, resp, err
289 }
290
291 return c, resp, err
292}
293
294// MergeBaseOptions represents the available MergeBase() options.
295//
296// GitLab API docs:
297// https://docs.gitlab.com/ce/api/repositories.html#merge-base
298type MergeBaseOptions struct {
299 Ref []string `url:"refs[],omitempty" json:"refs,omitempty"`
300}
301
302// MergeBase gets the common ancestor for 2 refs (commit SHAs, branch
303// names or tags).
304//
305// GitLab API docs:
306// https://docs.gitlab.com/ce/api/repositories.html#merge-base
307func (s *RepositoriesService) MergeBase(pid interface{}, opt *MergeBaseOptions, options ...OptionFunc) (*Commit, *Response, error) {
308 project, err := parseID(pid)
309 if err != nil {
310 return nil, nil, err
311 }
312 u := fmt.Sprintf("projects/%s/repository/merge_base", pathEscape(project))
313
314 req, err := s.client.NewRequest("GET", u, opt, options)
315 if err != nil {
316 return nil, nil, err
317 }
318
319 c := new(Commit)
320 resp, err := s.client.Do(req, c)
321 if err != nil {
322 return nil, resp, err
323 }
324
325 return c, resp, err
326}