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 "io/ioutil"
24 "mime/multipart"
25 "os"
26 "time"
27)
28
29// ProjectsService handles communication with the repositories related methods
30// of the GitLab API.
31//
32// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html
33type ProjectsService struct {
34 client *Client
35}
36
37// Project represents a GitLab project.
38//
39// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html
40type Project struct {
41 ID int `json:"id"`
42 Description string `json:"description"`
43 DefaultBranch string `json:"default_branch"`
44 Public bool `json:"public"`
45 Visibility VisibilityValue `json:"visibility"`
46 SSHURLToRepo string `json:"ssh_url_to_repo"`
47 HTTPURLToRepo string `json:"http_url_to_repo"`
48 WebURL string `json:"web_url"`
49 ReadmeURL string `json:"readme_url"`
50 TagList []string `json:"tag_list"`
51 Owner *User `json:"owner"`
52 Name string `json:"name"`
53 NameWithNamespace string `json:"name_with_namespace"`
54 Path string `json:"path"`
55 PathWithNamespace string `json:"path_with_namespace"`
56 IssuesEnabled bool `json:"issues_enabled"`
57 OpenIssuesCount int `json:"open_issues_count"`
58 MergeRequestsEnabled bool `json:"merge_requests_enabled"`
59 ApprovalsBeforeMerge int `json:"approvals_before_merge"`
60 JobsEnabled bool `json:"jobs_enabled"`
61 WikiEnabled bool `json:"wiki_enabled"`
62 SnippetsEnabled bool `json:"snippets_enabled"`
63 ResolveOutdatedDiffDiscussions bool `json:"resolve_outdated_diff_discussions"`
64 ContainerRegistryEnabled bool `json:"container_registry_enabled"`
65 CreatedAt *time.Time `json:"created_at,omitempty"`
66 LastActivityAt *time.Time `json:"last_activity_at,omitempty"`
67 CreatorID int `json:"creator_id"`
68 Namespace *ProjectNamespace `json:"namespace"`
69 ImportStatus string `json:"import_status"`
70 ImportError string `json:"import_error"`
71 Permissions *Permissions `json:"permissions"`
72 Archived bool `json:"archived"`
73 AvatarURL string `json:"avatar_url"`
74 SharedRunnersEnabled bool `json:"shared_runners_enabled"`
75 ForksCount int `json:"forks_count"`
76 StarCount int `json:"star_count"`
77 RunnersToken string `json:"runners_token"`
78 PublicBuilds bool `json:"public_builds"`
79 OnlyAllowMergeIfPipelineSucceeds bool `json:"only_allow_merge_if_pipeline_succeeds"`
80 OnlyAllowMergeIfAllDiscussionsAreResolved bool `json:"only_allow_merge_if_all_discussions_are_resolved"`
81 LFSEnabled bool `json:"lfs_enabled"`
82 RequestAccessEnabled bool `json:"request_access_enabled"`
83 MergeMethod MergeMethodValue `json:"merge_method"`
84 ForkedFromProject *ForkParent `json:"forked_from_project"`
85 Mirror bool `json:"mirror"`
86 MirrorUserID int `json:"mirror_user_id"`
87 MirrorTriggerBuilds bool `json:"mirror_trigger_builds"`
88 OnlyMirrorProtectedBranches bool `json:"only_mirror_protected_branches"`
89 MirrorOverwritesDivergedBranches bool `json:"mirror_overwrites_diverged_branches"`
90 SharedWithGroups []struct {
91 GroupID int `json:"group_id"`
92 GroupName string `json:"group_name"`
93 GroupAccessLevel int `json:"group_access_level"`
94 } `json:"shared_with_groups"`
95 Statistics *ProjectStatistics `json:"statistics"`
96 Links *Links `json:"_links,omitempty"`
97 CIConfigPath *string `json:"ci_config_path"`
98 CustomAttributes []*CustomAttribute `json:"custom_attributes"`
99}
100
101// Repository represents a repository.
102type Repository struct {
103 Name string `json:"name"`
104 Description string `json:"description"`
105 WebURL string `json:"web_url"`
106 AvatarURL string `json:"avatar_url"`
107 GitSSHURL string `json:"git_ssh_url"`
108 GitHTTPURL string `json:"git_http_url"`
109 Namespace string `json:"namespace"`
110 Visibility VisibilityValue `json:"visibility"`
111 PathWithNamespace string `json:"path_with_namespace"`
112 DefaultBranch string `json:"default_branch"`
113 Homepage string `json:"homepage"`
114 URL string `json:"url"`
115 SSHURL string `json:"ssh_url"`
116 HTTPURL string `json:"http_url"`
117}
118
119// ProjectNamespace represents a project namespace.
120type ProjectNamespace struct {
121 ID int `json:"id"`
122 Name string `json:"name"`
123 Path string `json:"path"`
124 Kind string `json:"kind"`
125 FullPath string `json:"full_path"`
126}
127
128// StorageStatistics represents a statistics record for a group or project.
129type StorageStatistics struct {
130 StorageSize int64 `json:"storage_size"`
131 RepositorySize int64 `json:"repository_size"`
132 LfsObjectsSize int64 `json:"lfs_objects_size"`
133 JobArtifactsSize int64 `json:"job_artifacts_size"`
134}
135
136// ProjectStatistics represents a statistics record for a project.
137type ProjectStatistics struct {
138 StorageStatistics
139 CommitCount int `json:"commit_count"`
140}
141
142// Permissions represents permissions.
143type Permissions struct {
144 ProjectAccess *ProjectAccess `json:"project_access"`
145 GroupAccess *GroupAccess `json:"group_access"`
146}
147
148// ProjectAccess represents project access.
149type ProjectAccess struct {
150 AccessLevel AccessLevelValue `json:"access_level"`
151 NotificationLevel NotificationLevelValue `json:"notification_level"`
152}
153
154// GroupAccess represents group access.
155type GroupAccess struct {
156 AccessLevel AccessLevelValue `json:"access_level"`
157 NotificationLevel NotificationLevelValue `json:"notification_level"`
158}
159
160// ForkParent represents the parent project when this is a fork.
161type ForkParent struct {
162 HTTPURLToRepo string `json:"http_url_to_repo"`
163 ID int `json:"id"`
164 Name string `json:"name"`
165 NameWithNamespace string `json:"name_with_namespace"`
166 Path string `json:"path"`
167 PathWithNamespace string `json:"path_with_namespace"`
168 WebURL string `json:"web_url"`
169}
170
171// Links represents a project web links for self, issues, merge_requests,
172// repo_branches, labels, events, members.
173type Links struct {
174 Self string `json:"self"`
175 Issues string `json:"issues"`
176 MergeRequests string `json:"merge_requests"`
177 RepoBranches string `json:"repo_branches"`
178 Labels string `json:"labels"`
179 Events string `json:"events"`
180 Members string `json:"members"`
181}
182
183func (s Project) String() string {
184 return Stringify(s)
185}
186
187// ListProjectsOptions represents the available ListProjects() options.
188//
189// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects
190type ListProjectsOptions struct {
191 ListOptions
192 Archived *bool `url:"archived,omitempty" json:"archived,omitempty"`
193 OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
194 Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
195 Search *string `url:"search,omitempty" json:"search,omitempty"`
196 Simple *bool `url:"simple,omitempty" json:"simple,omitempty"`
197 Owned *bool `url:"owned,omitempty" json:"owned,omitempty"`
198 Membership *bool `url:"membership,omitempty" json:"membership,omitempty"`
199 Starred *bool `url:"starred,omitempty" json:"starred,omitempty"`
200 Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"`
201 Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
202 WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"`
203 WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"`
204 MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"`
205 WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
206}
207
208// ListProjects gets a list of projects accessible by the authenticated user.
209//
210// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects
211func (s *ProjectsService) ListProjects(opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) {
212 req, err := s.client.NewRequest("GET", "projects", opt, options)
213 if err != nil {
214 return nil, nil, err
215 }
216
217 var p []*Project
218 resp, err := s.client.Do(req, &p)
219 if err != nil {
220 return nil, resp, err
221 }
222
223 return p, resp, err
224}
225
226// ListUserProjects gets a list of projects for the given user.
227//
228// GitLab API docs:
229// https://docs.gitlab.com/ce/api/projects.html#list-user-projects
230func (s *ProjectsService) ListUserProjects(uid interface{}, opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) {
231 user, err := parseID(uid)
232 if err != nil {
233 return nil, nil, err
234 }
235 u := fmt.Sprintf("users/%s/projects", user)
236
237 req, err := s.client.NewRequest("GET", u, opt, options)
238 if err != nil {
239 return nil, nil, err
240 }
241
242 var p []*Project
243 resp, err := s.client.Do(req, &p)
244 if err != nil {
245 return nil, resp, err
246 }
247
248 return p, resp, err
249}
250
251// ProjectUser represents a GitLab project user.
252type ProjectUser struct {
253 ID int `json:"id"`
254 Name string `json:"name"`
255 Username string `json:"username"`
256 State string `json:"state"`
257 AvatarURL string `json:"avatar_url"`
258 WebURL string `json:"web_url"`
259}
260
261// ListProjectUserOptions represents the available ListProjectsUsers() options.
262//
263// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#get-project-users
264type ListProjectUserOptions struct {
265 ListOptions
266 Search *string `url:"search,omitempty" json:"search,omitempty"`
267}
268
269// ListProjectsUsers gets a list of users for the given project.
270//
271// GitLab API docs:
272// https://docs.gitlab.com/ce/api/projects.html#get-project-users
273func (s *ProjectsService) ListProjectsUsers(pid interface{}, opt *ListProjectUserOptions, options ...OptionFunc) ([]*ProjectUser, *Response, error) {
274 project, err := parseID(pid)
275 if err != nil {
276 return nil, nil, err
277 }
278 u := fmt.Sprintf("projects/%s/users", 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 p []*ProjectUser
286 resp, err := s.client.Do(req, &p)
287 if err != nil {
288 return nil, resp, err
289 }
290
291 return p, resp, err
292}
293
294// ProjectLanguages is a map of strings because the response is arbitrary
295//
296// Gitlab API docs: https://docs.gitlab.com/ce/api/projects.html#languages
297type ProjectLanguages map[string]float32
298
299// GetProjectLanguages gets a list of languages used by the project
300//
301// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#languages
302func (s *ProjectsService) GetProjectLanguages(pid interface{}, options ...OptionFunc) (*ProjectLanguages, *Response, error) {
303 project, err := parseID(pid)
304 if err != nil {
305 return nil, nil, err
306 }
307 u := fmt.Sprintf("projects/%s/languages", pathEscape(project))
308
309 req, err := s.client.NewRequest("GET", u, nil, options)
310 if err != nil {
311 return nil, nil, err
312 }
313
314 p := new(ProjectLanguages)
315 resp, err := s.client.Do(req, p)
316 if err != nil {
317 return nil, resp, err
318 }
319
320 return p, resp, err
321}
322
323// GetProjectOptions represents the available GetProject() options.
324//
325// GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#get-single-project
326type GetProjectOptions struct {
327 Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"`
328 License *bool `url:"license,omitempty" json:"license,omitempty"`
329 WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
330}
331
332// GetProject gets a specific project, identified by project ID or
333// NAMESPACE/PROJECT_NAME, which is owned by the authenticated user.
334//
335// GitLab API docs:
336// https://docs.gitlab.com/ce/api/projects.html#get-single-project
337func (s *ProjectsService) GetProject(pid interface{}, opt *GetProjectOptions, options ...OptionFunc) (*Project, *Response, error) {
338 project, err := parseID(pid)
339 if err != nil {
340 return nil, nil, err
341 }
342 u := fmt.Sprintf("projects/%s", pathEscape(project))
343
344 req, err := s.client.NewRequest("GET", u, opt, options)
345 if err != nil {
346 return nil, nil, err
347 }
348
349 p := new(Project)
350 resp, err := s.client.Do(req, p)
351 if err != nil {
352 return nil, resp, err
353 }
354
355 return p, resp, err
356}
357
358// ProjectEvent represents a GitLab project event.
359//
360// GitLab API docs:
361// https://docs.gitlab.com/ce/api/projects.html#get-project-events
362type ProjectEvent struct {
363 Title interface{} `json:"title"`
364 ProjectID int `json:"project_id"`
365 ActionName string `json:"action_name"`
366 TargetID interface{} `json:"target_id"`
367 TargetType interface{} `json:"target_type"`
368 AuthorID int `json:"author_id"`
369 AuthorUsername string `json:"author_username"`
370 Data struct {
371 Before string `json:"before"`
372 After string `json:"after"`
373 Ref string `json:"ref"`
374 UserID int `json:"user_id"`
375 UserName string `json:"user_name"`
376 Repository *Repository `json:"repository"`
377 Commits []*Commit `json:"commits"`
378 TotalCommitsCount int `json:"total_commits_count"`
379 } `json:"data"`
380 TargetTitle interface{} `json:"target_title"`
381}
382
383func (s ProjectEvent) String() string {
384 return Stringify(s)
385}
386
387// GetProjectEventsOptions represents the available GetProjectEvents() options.
388//
389// GitLab API docs:
390// https://docs.gitlab.com/ce/api/projects.html#get-project-events
391type GetProjectEventsOptions ListOptions
392
393// GetProjectEvents gets the events for the specified project. Sorted from
394// newest to latest.
395//
396// GitLab API docs:
397// https://docs.gitlab.com/ce/api/projects.html#get-project-events
398func (s *ProjectsService) GetProjectEvents(pid interface{}, opt *GetProjectEventsOptions, options ...OptionFunc) ([]*ProjectEvent, *Response, error) {
399 project, err := parseID(pid)
400 if err != nil {
401 return nil, nil, err
402 }
403 u := fmt.Sprintf("projects/%s/events", pathEscape(project))
404
405 req, err := s.client.NewRequest("GET", u, opt, options)
406 if err != nil {
407 return nil, nil, err
408 }
409
410 var p []*ProjectEvent
411 resp, err := s.client.Do(req, &p)
412 if err != nil {
413 return nil, resp, err
414 }
415
416 return p, resp, err
417}
418
419// CreateProjectOptions represents the available CreateProject() options.
420//
421// GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#create-project
422type CreateProjectOptions struct {
423 Name *string `url:"name,omitempty" json:"name,omitempty"`
424 Path *string `url:"path,omitempty" json:"path,omitempty"`
425 DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"`
426 NamespaceID *int `url:"namespace_id,omitempty" json:"namespace_id,omitempty"`
427 Description *string `url:"description,omitempty" json:"description,omitempty"`
428 IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"`
429 MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"`
430 JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"`
431 WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"`
432 SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"`
433 ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"`
434 ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"`
435 SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"`
436 Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
437 ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"`
438 PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"`
439 OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"`
440 OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"`
441 MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"`
442 LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
443 RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
444 TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"`
445 PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"`
446 CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"`
447 ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"`
448 Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"`
449 MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"`
450 InitializeWithReadme *bool `url:"initialize_with_readme,omitempty" json:"initialize_with_readme,omitempty"`
451}
452
453// CreateProject creates a new project owned by the authenticated user.
454//
455// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project
456func (s *ProjectsService) CreateProject(opt *CreateProjectOptions, options ...OptionFunc) (*Project, *Response, error) {
457 req, err := s.client.NewRequest("POST", "projects", opt, options)
458 if err != nil {
459 return nil, nil, err
460 }
461
462 p := new(Project)
463 resp, err := s.client.Do(req, p)
464 if err != nil {
465 return nil, resp, err
466 }
467
468 return p, resp, err
469}
470
471// CreateProjectForUserOptions represents the available CreateProjectForUser()
472// options.
473//
474// GitLab API docs:
475// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user
476type CreateProjectForUserOptions CreateProjectOptions
477
478// CreateProjectForUser creates a new project owned by the specified user.
479// Available only for admins.
480//
481// GitLab API docs:
482// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user
483func (s *ProjectsService) CreateProjectForUser(user int, opt *CreateProjectForUserOptions, options ...OptionFunc) (*Project, *Response, error) {
484 u := fmt.Sprintf("projects/user/%d", user)
485
486 req, err := s.client.NewRequest("POST", u, opt, options)
487 if err != nil {
488 return nil, nil, err
489 }
490
491 p := new(Project)
492 resp, err := s.client.Do(req, p)
493 if err != nil {
494 return nil, resp, err
495 }
496
497 return p, resp, err
498}
499
500// EditProjectOptions represents the available EditProject() options.
501//
502// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project
503type EditProjectOptions struct {
504 Name *string `url:"name,omitempty" json:"name,omitempty"`
505 Path *string `url:"path,omitempty" json:"path,omitempty"`
506 DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"`
507 Description *string `url:"description,omitempty" json:"description,omitempty"`
508 IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"`
509 MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"`
510 JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"`
511 WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"`
512 SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"`
513 ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"`
514 ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"`
515 SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"`
516 Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
517 ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"`
518 PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"`
519 OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"`
520 OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"`
521 MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"`
522 LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
523 RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
524 TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"`
525 CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"`
526 ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"`
527 ExternalAuthorizationClassificationLabel *string `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"`
528 Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"`
529 MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"`
530 MirrorUserID *int `url:"mirror_user_id,omitempty" json:"mirror_user_id,omitempty"`
531 OnlyMirrorProtectedBranches *bool `url:"only_mirror_protected_branches,omitempty" json:"only_mirror_protected_branches,omitempty"`
532 MirrorOverwritesDivergedBranches *bool `url:"mirror_overwrites_diverged_branches,omitempty" json:"mirror_overwrites_diverged_branches,omitempty"`
533 PackagesEnabled *bool `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"`
534}
535
536// EditProject updates an existing project.
537//
538// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project
539func (s *ProjectsService) EditProject(pid interface{}, opt *EditProjectOptions, options ...OptionFunc) (*Project, *Response, error) {
540 project, err := parseID(pid)
541 if err != nil {
542 return nil, nil, err
543 }
544 u := fmt.Sprintf("projects/%s", pathEscape(project))
545
546 req, err := s.client.NewRequest("PUT", u, opt, options)
547 if err != nil {
548 return nil, nil, err
549 }
550
551 p := new(Project)
552 resp, err := s.client.Do(req, p)
553 if err != nil {
554 return nil, resp, err
555 }
556
557 return p, resp, err
558}
559
560// ForkProjectOptions represents the available ForkProject() options.
561//
562// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project
563type ForkProjectOptions struct {
564 Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"`
565 Name *string `url:"name,omitempty" json:"name,omitempty" `
566 Path *string `url:"path,omitempty" json:"path,omitempty"`
567}
568
569// ForkProject forks a project into the user namespace of the authenticated
570// user.
571//
572// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project
573func (s *ProjectsService) ForkProject(pid interface{}, opt *ForkProjectOptions, options ...OptionFunc) (*Project, *Response, error) {
574 project, err := parseID(pid)
575 if err != nil {
576 return nil, nil, err
577 }
578 u := fmt.Sprintf("projects/%s/fork", pathEscape(project))
579
580 req, err := s.client.NewRequest("POST", u, opt, options)
581 if err != nil {
582 return nil, nil, err
583 }
584
585 p := new(Project)
586 resp, err := s.client.Do(req, p)
587 if err != nil {
588 return nil, resp, err
589 }
590
591 return p, resp, err
592}
593
594// StarProject stars a given the project.
595//
596// GitLab API docs:
597// https://docs.gitlab.com/ce/api/projects.html#star-a-project
598func (s *ProjectsService) StarProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) {
599 project, err := parseID(pid)
600 if err != nil {
601 return nil, nil, err
602 }
603 u := fmt.Sprintf("projects/%s/star", pathEscape(project))
604
605 req, err := s.client.NewRequest("POST", u, nil, options)
606 if err != nil {
607 return nil, nil, err
608 }
609
610 p := new(Project)
611 resp, err := s.client.Do(req, p)
612 if err != nil {
613 return nil, resp, err
614 }
615
616 return p, resp, err
617}
618
619// UnstarProject unstars a given project.
620//
621// GitLab API docs:
622// https://docs.gitlab.com/ce/api/projects.html#unstar-a-project
623func (s *ProjectsService) UnstarProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) {
624 project, err := parseID(pid)
625 if err != nil {
626 return nil, nil, err
627 }
628 u := fmt.Sprintf("projects/%s/unstar", pathEscape(project))
629
630 req, err := s.client.NewRequest("POST", u, nil, options)
631 if err != nil {
632 return nil, nil, err
633 }
634
635 p := new(Project)
636 resp, err := s.client.Do(req, p)
637 if err != nil {
638 return nil, resp, err
639 }
640
641 return p, resp, err
642}
643
644// ArchiveProject archives the project if the user is either admin or the
645// project owner of this project.
646//
647// GitLab API docs:
648// https://docs.gitlab.com/ce/api/projects.html#archive-a-project
649func (s *ProjectsService) ArchiveProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) {
650 project, err := parseID(pid)
651 if err != nil {
652 return nil, nil, err
653 }
654 u := fmt.Sprintf("projects/%s/archive", pathEscape(project))
655
656 req, err := s.client.NewRequest("POST", u, nil, options)
657 if err != nil {
658 return nil, nil, err
659 }
660
661 p := new(Project)
662 resp, err := s.client.Do(req, p)
663 if err != nil {
664 return nil, resp, err
665 }
666
667 return p, resp, err
668}
669
670// UnarchiveProject unarchives the project if the user is either admin or
671// the project owner of this project.
672//
673// GitLab API docs:
674// https://docs.gitlab.com/ce/api/projects.html#unarchive-a-project
675func (s *ProjectsService) UnarchiveProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) {
676 project, err := parseID(pid)
677 if err != nil {
678 return nil, nil, err
679 }
680 u := fmt.Sprintf("projects/%s/unarchive", pathEscape(project))
681
682 req, err := s.client.NewRequest("POST", u, nil, options)
683 if err != nil {
684 return nil, nil, err
685 }
686
687 p := new(Project)
688 resp, err := s.client.Do(req, p)
689 if err != nil {
690 return nil, resp, err
691 }
692
693 return p, resp, err
694}
695
696// DeleteProject removes a project including all associated resources
697// (issues, merge requests etc.)
698//
699// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#remove-project
700func (s *ProjectsService) DeleteProject(pid interface{}, options ...OptionFunc) (*Response, error) {
701 project, err := parseID(pid)
702 if err != nil {
703 return nil, err
704 }
705 u := fmt.Sprintf("projects/%s", pathEscape(project))
706
707 req, err := s.client.NewRequest("DELETE", u, nil, options)
708 if err != nil {
709 return nil, err
710 }
711
712 return s.client.Do(req, nil)
713}
714
715// ShareWithGroupOptions represents options to share project with groups
716//
717// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group
718type ShareWithGroupOptions struct {
719 GroupID *int `url:"group_id" json:"group_id"`
720 GroupAccess *AccessLevelValue `url:"group_access" json:"group_access"`
721 ExpiresAt *string `url:"expires_at" json:"expires_at"`
722}
723
724// ShareProjectWithGroup allows to share a project with a group.
725//
726// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group
727func (s *ProjectsService) ShareProjectWithGroup(pid interface{}, opt *ShareWithGroupOptions, options ...OptionFunc) (*Response, error) {
728 project, err := parseID(pid)
729 if err != nil {
730 return nil, err
731 }
732 u := fmt.Sprintf("projects/%s/share", pathEscape(project))
733
734 req, err := s.client.NewRequest("POST", u, opt, options)
735 if err != nil {
736 return nil, err
737 }
738
739 return s.client.Do(req, nil)
740}
741
742// DeleteSharedProjectFromGroup allows to unshare a project from a group.
743//
744// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#delete-a-shared-project-link-within-a-group
745func (s *ProjectsService) DeleteSharedProjectFromGroup(pid interface{}, groupID int, options ...OptionFunc) (*Response, error) {
746 project, err := parseID(pid)
747 if err != nil {
748 return nil, err
749 }
750 u := fmt.Sprintf("projects/%s/share/%d", pathEscape(project), groupID)
751
752 req, err := s.client.NewRequest("DELETE", u, nil, options)
753 if err != nil {
754 return nil, err
755 }
756
757 return s.client.Do(req, nil)
758}
759
760// ProjectMember represents a project member.
761//
762// GitLab API docs:
763// https://docs.gitlab.com/ce/api/projects.html#list-project-team-members
764type ProjectMember struct {
765 ID int `json:"id"`
766 Username string `json:"username"`
767 Email string `json:"email"`
768 Name string `json:"name"`
769 State string `json:"state"`
770 CreatedAt *time.Time `json:"created_at"`
771 AccessLevel AccessLevelValue `json:"access_level"`
772}
773
774// ProjectHook represents a project hook.
775//
776// GitLab API docs:
777// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks
778type ProjectHook struct {
779 ID int `json:"id"`
780 URL string `json:"url"`
781 ProjectID int `json:"project_id"`
782 PushEvents bool `json:"push_events"`
783 IssuesEvents bool `json:"issues_events"`
784 ConfidentialIssuesEvents bool `json:"confidential_issues_events"`
785 MergeRequestsEvents bool `json:"merge_requests_events"`
786 TagPushEvents bool `json:"tag_push_events"`
787 NoteEvents bool `json:"note_events"`
788 JobEvents bool `json:"job_events"`
789 PipelineEvents bool `json:"pipeline_events"`
790 WikiPageEvents bool `json:"wiki_page_events"`
791 EnableSSLVerification bool `json:"enable_ssl_verification"`
792 CreatedAt *time.Time `json:"created_at"`
793}
794
795// ListProjectHooksOptions represents the available ListProjectHooks() options.
796//
797// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-project-hooks
798type ListProjectHooksOptions ListOptions
799
800// ListProjectHooks gets a list of project hooks.
801//
802// GitLab API docs:
803// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks
804func (s *ProjectsService) ListProjectHooks(pid interface{}, opt *ListProjectHooksOptions, options ...OptionFunc) ([]*ProjectHook, *Response, error) {
805 project, err := parseID(pid)
806 if err != nil {
807 return nil, nil, err
808 }
809 u := fmt.Sprintf("projects/%s/hooks", pathEscape(project))
810
811 req, err := s.client.NewRequest("GET", u, opt, options)
812 if err != nil {
813 return nil, nil, err
814 }
815
816 var ph []*ProjectHook
817 resp, err := s.client.Do(req, &ph)
818 if err != nil {
819 return nil, resp, err
820 }
821
822 return ph, resp, err
823}
824
825// GetProjectHook gets a specific hook for a project.
826//
827// GitLab API docs:
828// https://docs.gitlab.com/ce/api/projects.html#get-project-hook
829func (s *ProjectsService) GetProjectHook(pid interface{}, hook int, options ...OptionFunc) (*ProjectHook, *Response, error) {
830 project, err := parseID(pid)
831 if err != nil {
832 return nil, nil, err
833 }
834 u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook)
835
836 req, err := s.client.NewRequest("GET", u, nil, options)
837 if err != nil {
838 return nil, nil, err
839 }
840
841 ph := new(ProjectHook)
842 resp, err := s.client.Do(req, ph)
843 if err != nil {
844 return nil, resp, err
845 }
846
847 return ph, resp, err
848}
849
850// AddProjectHookOptions represents the available AddProjectHook() options.
851//
852// GitLab API docs:
853// https://docs.gitlab.com/ce/api/projects.html#add-project-hook
854type AddProjectHookOptions struct {
855 URL *string `url:"url,omitempty" json:"url,omitempty"`
856 PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"`
857 IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"`
858 ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
859 MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
860 TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
861 NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"`
862 JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"`
863 PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
864 WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
865 EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
866 Token *string `url:"token,omitempty" json:"token,omitempty"`
867}
868
869// AddProjectHook adds a hook to a specified project.
870//
871// GitLab API docs:
872// https://docs.gitlab.com/ce/api/projects.html#add-project-hook
873func (s *ProjectsService) AddProjectHook(pid interface{}, opt *AddProjectHookOptions, options ...OptionFunc) (*ProjectHook, *Response, error) {
874 project, err := parseID(pid)
875 if err != nil {
876 return nil, nil, err
877 }
878 u := fmt.Sprintf("projects/%s/hooks", pathEscape(project))
879
880 req, err := s.client.NewRequest("POST", u, opt, options)
881 if err != nil {
882 return nil, nil, err
883 }
884
885 ph := new(ProjectHook)
886 resp, err := s.client.Do(req, ph)
887 if err != nil {
888 return nil, resp, err
889 }
890
891 return ph, resp, err
892}
893
894// EditProjectHookOptions represents the available EditProjectHook() options.
895//
896// GitLab API docs:
897// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook
898type EditProjectHookOptions struct {
899 URL *string `url:"url,omitempty" json:"url,omitempty"`
900 PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"`
901 IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"`
902 ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
903 MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
904 TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
905 NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"`
906 JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"`
907 PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
908 WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
909 EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
910 Token *string `url:"token,omitempty" json:"token,omitempty"`
911}
912
913// EditProjectHook edits a hook for a specified project.
914//
915// GitLab API docs:
916// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook
917func (s *ProjectsService) EditProjectHook(pid interface{}, hook int, opt *EditProjectHookOptions, options ...OptionFunc) (*ProjectHook, *Response, error) {
918 project, err := parseID(pid)
919 if err != nil {
920 return nil, nil, err
921 }
922 u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook)
923
924 req, err := s.client.NewRequest("PUT", u, opt, options)
925 if err != nil {
926 return nil, nil, err
927 }
928
929 ph := new(ProjectHook)
930 resp, err := s.client.Do(req, ph)
931 if err != nil {
932 return nil, resp, err
933 }
934
935 return ph, resp, err
936}
937
938// DeleteProjectHook removes a hook from a project. This is an idempotent
939// method and can be called multiple times. Either the hook is available or not.
940//
941// GitLab API docs:
942// https://docs.gitlab.com/ce/api/projects.html#delete-project-hook
943func (s *ProjectsService) DeleteProjectHook(pid interface{}, hook int, options ...OptionFunc) (*Response, error) {
944 project, err := parseID(pid)
945 if err != nil {
946 return nil, err
947 }
948 u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook)
949
950 req, err := s.client.NewRequest("DELETE", u, nil, options)
951 if err != nil {
952 return nil, err
953 }
954
955 return s.client.Do(req, nil)
956}
957
958// ProjectForkRelation represents a project fork relationship.
959//
960// GitLab API docs:
961// https://docs.gitlab.com/ce/api/projects.html#admin-fork-relation
962type ProjectForkRelation struct {
963 ID int `json:"id"`
964 ForkedToProjectID int `json:"forked_to_project_id"`
965 ForkedFromProjectID int `json:"forked_from_project_id"`
966 CreatedAt *time.Time `json:"created_at"`
967 UpdatedAt *time.Time `json:"updated_at"`
968}
969
970// CreateProjectForkRelation creates a forked from/to relation between
971// existing projects.
972//
973// GitLab API docs:
974// https://docs.gitlab.com/ce/api/projects.html#create-a-forked-fromto-relation-between-existing-projects.
975func (s *ProjectsService) CreateProjectForkRelation(pid int, fork int, options ...OptionFunc) (*ProjectForkRelation, *Response, error) {
976 u := fmt.Sprintf("projects/%d/fork/%d", pid, fork)
977
978 req, err := s.client.NewRequest("POST", u, nil, options)
979 if err != nil {
980 return nil, nil, err
981 }
982
983 pfr := new(ProjectForkRelation)
984 resp, err := s.client.Do(req, pfr)
985 if err != nil {
986 return nil, resp, err
987 }
988
989 return pfr, resp, err
990}
991
992// DeleteProjectForkRelation deletes an existing forked from relationship.
993//
994// GitLab API docs:
995// https://docs.gitlab.com/ce/api/projects.html#delete-an-existing-forked-from-relationship
996func (s *ProjectsService) DeleteProjectForkRelation(pid int, options ...OptionFunc) (*Response, error) {
997 u := fmt.Sprintf("projects/%d/fork", pid)
998
999 req, err := s.client.NewRequest("DELETE", u, nil, options)
1000 if err != nil {
1001 return nil, err
1002 }
1003
1004 return s.client.Do(req, nil)
1005}
1006
1007// ProjectFile represents an uploaded project file
1008//
1009// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file
1010type ProjectFile struct {
1011 Alt string `json:"alt"`
1012 URL string `json:"url"`
1013 Markdown string `json:"markdown"`
1014}
1015
1016// UploadFile upload a file from disk
1017//
1018// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file
1019func (s *ProjectsService) UploadFile(pid interface{}, file string, options ...OptionFunc) (*ProjectFile, *Response, error) {
1020 project, err := parseID(pid)
1021 if err != nil {
1022 return nil, nil, err
1023 }
1024 u := fmt.Sprintf("projects/%s/uploads", pathEscape(project))
1025
1026 f, err := os.Open(file)
1027 if err != nil {
1028 return nil, nil, err
1029 }
1030 defer f.Close()
1031
1032 b := &bytes.Buffer{}
1033 w := multipart.NewWriter(b)
1034
1035 fw, err := w.CreateFormFile("file", file)
1036 if err != nil {
1037 return nil, nil, err
1038 }
1039
1040 _, err = io.Copy(fw, f)
1041 if err != nil {
1042 return nil, nil, err
1043 }
1044 w.Close()
1045
1046 req, err := s.client.NewRequest("", u, nil, options)
1047 if err != nil {
1048 return nil, nil, err
1049 }
1050
1051 req.Body = ioutil.NopCloser(b)
1052 req.ContentLength = int64(b.Len())
1053 req.Header.Set("Content-Type", w.FormDataContentType())
1054 req.Method = "POST"
1055
1056 uf := &ProjectFile{}
1057 resp, err := s.client.Do(req, uf)
1058 if err != nil {
1059 return nil, resp, err
1060 }
1061
1062 return uf, resp, nil
1063}
1064
1065// ListProjectForks gets a list of project forks.
1066//
1067// GitLab API docs:
1068// https://docs.gitlab.com/ce/api/projects.html#list-forks-of-a-project
1069func (s *ProjectsService) ListProjectForks(pid interface{}, opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) {
1070 project, err := parseID(pid)
1071 if err != nil {
1072 return nil, nil, err
1073 }
1074 u := fmt.Sprintf("projects/%s/forks", pathEscape(project))
1075
1076 req, err := s.client.NewRequest("GET", u, opt, options)
1077 if err != nil {
1078 return nil, nil, err
1079 }
1080
1081 var forks []*Project
1082 resp, err := s.client.Do(req, &forks)
1083 if err != nil {
1084 return nil, resp, err
1085 }
1086
1087 return forks, resp, err
1088}
1089
1090// ProjectPushRules represents a project push rule.
1091//
1092// GitLab API docs:
1093// https://docs.gitlab.com/ee/api/projects.html#push-rules
1094type ProjectPushRules struct {
1095 ID int `json:"id"`
1096 ProjectID int `json:"project_id"`
1097 CommitMessageRegex string `json:"commit_message_regex"`
1098 BranchNameRegex string `json:"branch_name_regex"`
1099 DenyDeleteTag bool `json:"deny_delete_tag"`
1100 CreatedAt *time.Time `json:"created_at"`
1101 MemberCheck bool `json:"member_check"`
1102 PreventSecrets bool `json:"prevent_secrets"`
1103 AuthorEmailRegex string `json:"author_email_regex"`
1104 FileNameRegex string `json:"file_name_regex"`
1105 MaxFileSize int `json:"max_file_size"`
1106}
1107
1108// GetProjectPushRules gets the push rules of a project.
1109//
1110// GitLab API docs:
1111// https://docs.gitlab.com/ee/api/projects.html#get-project-push-rules
1112func (s *ProjectsService) GetProjectPushRules(pid interface{}, options ...OptionFunc) (*ProjectPushRules, *Response, error) {
1113 project, err := parseID(pid)
1114 if err != nil {
1115 return nil, nil, err
1116 }
1117 u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project))
1118
1119 req, err := s.client.NewRequest("GET", u, nil, options)
1120 if err != nil {
1121 return nil, nil, err
1122 }
1123
1124 ppr := new(ProjectPushRules)
1125 resp, err := s.client.Do(req, ppr)
1126 if err != nil {
1127 return nil, resp, err
1128 }
1129
1130 return ppr, resp, err
1131}
1132
1133// AddProjectPushRuleOptions represents the available AddProjectPushRule()
1134// options.
1135//
1136// GitLab API docs:
1137// https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule
1138type AddProjectPushRuleOptions struct {
1139 DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
1140 MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"`
1141 PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
1142 CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
1143 BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
1144 AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
1145 FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
1146 MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
1147}
1148
1149// AddProjectPushRule adds a push rule to a specified project.
1150//
1151// GitLab API docs:
1152// https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule
1153func (s *ProjectsService) AddProjectPushRule(pid interface{}, opt *AddProjectPushRuleOptions, options ...OptionFunc) (*ProjectPushRules, *Response, error) {
1154 project, err := parseID(pid)
1155 if err != nil {
1156 return nil, nil, err
1157 }
1158 u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project))
1159
1160 req, err := s.client.NewRequest("POST", u, opt, options)
1161 if err != nil {
1162 return nil, nil, err
1163 }
1164
1165 ppr := new(ProjectPushRules)
1166 resp, err := s.client.Do(req, ppr)
1167 if err != nil {
1168 return nil, resp, err
1169 }
1170
1171 return ppr, resp, err
1172}
1173
1174// EditProjectPushRuleOptions represents the available EditProjectPushRule()
1175// options.
1176//
1177// GitLab API docs:
1178// https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule
1179type EditProjectPushRuleOptions struct {
1180 AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
1181 BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
1182 CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
1183 FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
1184 DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
1185 MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"`
1186 PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
1187 MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
1188}
1189
1190// EditProjectPushRule edits a push rule for a specified project.
1191//
1192// GitLab API docs:
1193// https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule
1194func (s *ProjectsService) EditProjectPushRule(pid interface{}, opt *EditProjectPushRuleOptions, options ...OptionFunc) (*ProjectPushRules, *Response, error) {
1195 project, err := parseID(pid)
1196 if err != nil {
1197 return nil, nil, err
1198 }
1199 u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project))
1200
1201 req, err := s.client.NewRequest("PUT", u, opt, options)
1202 if err != nil {
1203 return nil, nil, err
1204 }
1205
1206 ppr := new(ProjectPushRules)
1207 resp, err := s.client.Do(req, ppr)
1208 if err != nil {
1209 return nil, resp, err
1210 }
1211
1212 return ppr, resp, err
1213}
1214
1215// DeleteProjectPushRule removes a push rule from a project. This is an
1216// idempotent method and can be called multiple times. Either the push rule is
1217// available or not.
1218//
1219// GitLab API docs:
1220// https://docs.gitlab.com/ee/api/projects.html#delete-project-push-rule
1221func (s *ProjectsService) DeleteProjectPushRule(pid interface{}, options ...OptionFunc) (*Response, error) {
1222 project, err := parseID(pid)
1223 if err != nil {
1224 return nil, err
1225 }
1226 u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project))
1227
1228 req, err := s.client.NewRequest("DELETE", u, nil, options)
1229 if err != nil {
1230 return nil, err
1231 }
1232
1233 return s.client.Do(req, nil)
1234}
1235
1236// ProjectApprovals represents GitLab project level merge request approvals.
1237//
1238// GitLab API docs:
1239// https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals
1240type ProjectApprovals struct {
1241 Approvers []*MergeRequestApproverUser `json:"approvers"`
1242 ApproverGroups []*MergeRequestApproverGroup `json:"approver_groups"`
1243 ApprovalsBeforeMerge int `json:"approvals_before_merge"`
1244 ResetApprovalsOnPush bool `json:"reset_approvals_on_push"`
1245 DisableOverridingApproversPerMergeRequest bool `json:"disable_overriding_approvers_per_merge_request"`
1246 MergeRequestsAuthorApproval bool `json:"merge_requests_author_approval"`
1247}
1248
1249// GetApprovalConfiguration get the approval configuration for a project.
1250//
1251// GitLab API docs:
1252// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-configuration
1253func (s *ProjectsService) GetApprovalConfiguration(pid interface{}, options ...OptionFunc) (*ProjectApprovals, *Response, error) {
1254 project, err := parseID(pid)
1255 if err != nil {
1256 return nil, nil, err
1257 }
1258 u := fmt.Sprintf("projects/%s/approvals", pathEscape(project))
1259
1260 req, err := s.client.NewRequest("GET", u, nil, options)
1261 if err != nil {
1262 return nil, nil, err
1263 }
1264
1265 pa := new(ProjectApprovals)
1266 resp, err := s.client.Do(req, pa)
1267 if err != nil {
1268 return nil, resp, err
1269 }
1270
1271 return pa, resp, err
1272}
1273
1274// ChangeApprovalConfigurationOptions represents the available
1275// ApprovalConfiguration() options.
1276//
1277// GitLab API docs:
1278// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration
1279type ChangeApprovalConfigurationOptions struct {
1280 ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"`
1281 ResetApprovalsOnPush *bool `url:"reset_approvals_on_push,omitempty" json:"reset_approvals_on_push,omitempty"`
1282 DisableOverridingApproversPerMergeRequest *bool `url:"disable_overriding_approvers_per_merge_request,omitempty" json:"disable_overriding_approvers_per_merge_request,omitempty"`
1283 MergeRequestsAuthorApproval *bool `url:"merge_requests_author_approval,omitempty" json:"merge_requests_author_approval,omitempty"`
1284}
1285
1286// ChangeApprovalConfiguration updates the approval configuration for a project.
1287//
1288// GitLab API docs:
1289// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration
1290func (s *ProjectsService) ChangeApprovalConfiguration(pid interface{}, opt *ChangeApprovalConfigurationOptions, options ...OptionFunc) (*ProjectApprovals, *Response, error) {
1291 project, err := parseID(pid)
1292 if err != nil {
1293 return nil, nil, err
1294 }
1295 u := fmt.Sprintf("projects/%s/approvals", pathEscape(project))
1296
1297 req, err := s.client.NewRequest("POST", u, opt, options)
1298 if err != nil {
1299 return nil, nil, err
1300 }
1301
1302 pa := new(ProjectApprovals)
1303 resp, err := s.client.Do(req, pa)
1304 if err != nil {
1305 return nil, resp, err
1306 }
1307
1308 return pa, resp, err
1309}
1310
1311// ChangeAllowedApproversOptions represents the available ChangeAllowedApprovers()
1312// options.
1313//
1314// GitLab API docs:
1315// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers
1316type ChangeAllowedApproversOptions struct {
1317 ApproverIDs []*int `url:"approver_ids,omitempty" json:"approver_ids,omitempty"`
1318 ApproverGroupIDs []*int `url:"approver_group_ids,omitempty" json:"approver_group_ids,omitempty"`
1319}
1320
1321// ChangeAllowedApprovers updates the list of approvers and approver groups.
1322//
1323// GitLab API docs:
1324// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers
1325func (s *ProjectsService) ChangeAllowedApprovers(pid interface{}, opt *ChangeAllowedApproversOptions, options ...OptionFunc) (*ProjectApprovals, *Response, error) {
1326 project, err := parseID(pid)
1327 if err != nil {
1328 return nil, nil, err
1329 }
1330 u := fmt.Sprintf("projects/%s/approvers", pathEscape(project))
1331
1332 req, err := s.client.NewRequest("POST", u, opt, options)
1333 if err != nil {
1334 return nil, nil, err
1335 }
1336
1337 pa := new(ProjectApprovals)
1338 resp, err := s.client.Do(req, pa)
1339 if err != nil {
1340 return nil, resp, err
1341 }
1342
1343 return pa, resp, err
1344}