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 "net/url"
23 "strconv"
24)
25
26// RepositoryFilesService handles communication with the repository files
27// related methods of the GitLab API.
28//
29// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html
30type RepositoryFilesService struct {
31 client *Client
32}
33
34// File represents a GitLab repository file.
35//
36// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html
37type File struct {
38 FileName string `json:"file_name"`
39 FilePath string `json:"file_path"`
40 Size int `json:"size"`
41 Encoding string `json:"encoding"`
42 Content string `json:"content"`
43 Ref string `json:"ref"`
44 BlobID string `json:"blob_id"`
45 CommitID string `json:"commit_id"`
46}
47
48func (r File) String() string {
49 return Stringify(r)
50}
51
52// GetFileOptions represents the available GetFile() options.
53//
54// GitLab API docs:
55// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository
56type GetFileOptions struct {
57 Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
58}
59
60// GetFile allows you to receive information about a file in repository like
61// name, size, content. Note that file content is Base64 encoded.
62//
63// GitLab API docs:
64// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository
65func (s *RepositoryFilesService) GetFile(pid interface{}, fileName string, opt *GetFileOptions, options ...OptionFunc) (*File, *Response, error) {
66 project, err := parseID(pid)
67 if err != nil {
68 return nil, nil, err
69 }
70 u := fmt.Sprintf(
71 "projects/%s/repository/files/%s",
72 pathEscape(project),
73 url.PathEscape(fileName),
74 )
75
76 req, err := s.client.NewRequest("GET", u, opt, options)
77 if err != nil {
78 return nil, nil, err
79 }
80
81 f := new(File)
82 resp, err := s.client.Do(req, f)
83 if err != nil {
84 return nil, resp, err
85 }
86
87 return f, resp, err
88}
89
90// GetFileMetaDataOptions represents the available GetFileMetaData() options.
91//
92// GitLab API docs:
93// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository
94type GetFileMetaDataOptions struct {
95 Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
96}
97
98// GetFileMetaData allows you to receive meta information about a file in
99// repository like name, size.
100//
101// GitLab API docs:
102// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository
103func (s *RepositoryFilesService) GetFileMetaData(pid interface{}, fileName string, opt *GetFileMetaDataOptions, options ...OptionFunc) (*File, *Response, error) {
104 project, err := parseID(pid)
105 if err != nil {
106 return nil, nil, err
107 }
108 u := fmt.Sprintf(
109 "projects/%s/repository/files/%s",
110 pathEscape(project),
111 url.PathEscape(fileName),
112 )
113
114 req, err := s.client.NewRequest("HEAD", u, opt, options)
115 if err != nil {
116 return nil, nil, err
117 }
118
119 resp, err := s.client.Do(req, nil)
120 if err != nil {
121 return nil, resp, err
122 }
123
124 f := &File{
125 BlobID: resp.Header.Get("X-Gitlab-Blob-Id"),
126 CommitID: resp.Header.Get("X-Gitlab-Last-Commit-Id"),
127 Encoding: resp.Header.Get("X-Gitlab-Encoding"),
128 FileName: resp.Header.Get("X-Gitlab-File-Name"),
129 FilePath: resp.Header.Get("X-Gitlab-File-Path"),
130 Ref: resp.Header.Get("X-Gitlab-Ref"),
131 }
132
133 if sizeString := resp.Header.Get("X-Gitlab-Size"); sizeString != "" {
134 f.Size, err = strconv.Atoi(sizeString)
135 if err != nil {
136 return nil, resp, err
137 }
138 }
139
140 return f, resp, err
141}
142
143// GetRawFileOptions represents the available GetRawFile() options.
144//
145// GitLab API docs:
146// https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository
147type GetRawFileOptions struct {
148 Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
149}
150
151// GetRawFile allows you to receive the raw file in repository.
152//
153// GitLab API docs:
154// https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository
155func (s *RepositoryFilesService) GetRawFile(pid interface{}, fileName string, opt *GetRawFileOptions, options ...OptionFunc) ([]byte, *Response, error) {
156 project, err := parseID(pid)
157 if err != nil {
158 return nil, nil, err
159 }
160 u := fmt.Sprintf(
161 "projects/%s/repository/files/%s/raw",
162 pathEscape(project),
163 url.PathEscape(fileName),
164 )
165
166 req, err := s.client.NewRequest("GET", u, opt, options)
167 if err != nil {
168 return nil, nil, err
169 }
170
171 var f bytes.Buffer
172 resp, err := s.client.Do(req, &f)
173 if err != nil {
174 return nil, resp, err
175 }
176
177 return f.Bytes(), resp, err
178}
179
180// FileInfo represents file details of a GitLab repository file.
181//
182// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html
183type FileInfo struct {
184 FilePath string `json:"file_path"`
185 Branch string `json:"branch"`
186}
187
188func (r FileInfo) String() string {
189 return Stringify(r)
190}
191
192// CreateFileOptions represents the available CreateFile() options.
193//
194// GitLab API docs:
195// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository
196type CreateFileOptions struct {
197 Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
198 Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"`
199 AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"`
200 AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"`
201 Content *string `url:"content,omitempty" json:"content,omitempty"`
202 CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
203}
204
205// CreateFile creates a new file in a repository.
206//
207// GitLab API docs:
208// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository
209func (s *RepositoryFilesService) CreateFile(pid interface{}, fileName string, opt *CreateFileOptions, options ...OptionFunc) (*FileInfo, *Response, error) {
210 project, err := parseID(pid)
211 if err != nil {
212 return nil, nil, err
213 }
214 u := fmt.Sprintf(
215 "projects/%s/repository/files/%s",
216 pathEscape(project),
217 url.PathEscape(fileName),
218 )
219
220 req, err := s.client.NewRequest("POST", u, opt, options)
221 if err != nil {
222 return nil, nil, err
223 }
224
225 f := new(FileInfo)
226 resp, err := s.client.Do(req, f)
227 if err != nil {
228 return nil, resp, err
229 }
230
231 return f, resp, err
232}
233
234// UpdateFileOptions represents the available UpdateFile() options.
235//
236// GitLab API docs:
237// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository
238type UpdateFileOptions struct {
239 Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
240 Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"`
241 AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"`
242 AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"`
243 Content *string `url:"content,omitempty" json:"content,omitempty"`
244 CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
245 LastCommitID *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"`
246}
247
248// UpdateFile updates an existing file in a repository
249//
250// GitLab API docs:
251// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository
252func (s *RepositoryFilesService) UpdateFile(pid interface{}, fileName string, opt *UpdateFileOptions, options ...OptionFunc) (*FileInfo, *Response, error) {
253 project, err := parseID(pid)
254 if err != nil {
255 return nil, nil, err
256 }
257 u := fmt.Sprintf(
258 "projects/%s/repository/files/%s",
259 pathEscape(project),
260 url.PathEscape(fileName),
261 )
262
263 req, err := s.client.NewRequest("PUT", u, opt, options)
264 if err != nil {
265 return nil, nil, err
266 }
267
268 f := new(FileInfo)
269 resp, err := s.client.Do(req, f)
270 if err != nil {
271 return nil, resp, err
272 }
273
274 return f, resp, err
275}
276
277// DeleteFileOptions represents the available DeleteFile() options.
278//
279// GitLab API docs:
280// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository
281type DeleteFileOptions struct {
282 Branch *string `url:"branch,omitempty" json:"branch,omitempty"`
283 AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"`
284 AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"`
285 CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
286}
287
288// DeleteFile deletes an existing file in a repository
289//
290// GitLab API docs:
291// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository
292func (s *RepositoryFilesService) DeleteFile(pid interface{}, fileName string, opt *DeleteFileOptions, options ...OptionFunc) (*Response, error) {
293 project, err := parseID(pid)
294 if err != nil {
295 return nil, err
296 }
297 u := fmt.Sprintf(
298 "projects/%s/repository/files/%s",
299 pathEscape(project),
300 url.PathEscape(fileName),
301 )
302
303 req, err := s.client.NewRequest("DELETE", u, opt, options)
304 if err != nil {
305 return nil, err
306 }
307
308 return s.client.Do(req, nil)
309}