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