pax_global_header00006660000000000000000000000064135714041150014513gustar00rootroot0000000000000052 comment=f74501cbc643b2731fcdfb29ca53230bbb2b935a golang-github-xanzy-go-gitlab-0.22.2/000077500000000000000000000000001357140411500173375ustar00rootroot00000000000000golang-github-xanzy-go-gitlab-0.22.2/.gitignore000066400000000000000000000004701357140411500213300ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof # IDE specific files and folders .idea *.iml golang-github-xanzy-go-gitlab-0.22.2/.travis.yml000066400000000000000000000005531357140411500214530ustar00rootroot00000000000000language: go go: - 1.10.x - 1.11.x - 1.12.x - 1.13.x - master stages: - lint - test jobs: include: - stage: lint script: - go get golang.org/x/lint/golint - golint -set_exit_status - go vet -v - stage: test script: - go test -v matrix: allow_failures: - go: master fast_finish: true golang-github-xanzy-go-gitlab-0.22.2/CHANGELOG.md000066400000000000000000000014251357140411500211520ustar00rootroot00000000000000go-github CHANGELOG =================== 0.6.0 ----- - Add support for the V4 Gitlab API. This means the older V3 API is no longer fully supported with this version. If you still need that version, please use the `f-api-v3` branch. 0.4.0 ----- - Add support to use [`sudo`](https://docs.gitlab.com/ce/api/README.html#sudo) for all API calls. - Add support for the Notification Settings API. - Add support for the Time Tracking API. - Make sure that the error response correctly outputs any returned errors. - And a reasonable number of smaller enhanchements and bugfixes. 0.3.0 ----- - Moved the tags related API calls to their own service, following the Gitlab API structure. 0.2.0 ----- - Convert all Option structs to use pointers for their fields. 0.1.0 ----- - Initial release. golang-github-xanzy-go-gitlab-0.22.2/LICENSE000066400000000000000000000260751357140411500203560ustar00rootroot00000000000000Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-github-xanzy-go-gitlab-0.22.2/README.md000066400000000000000000000116711357140411500206240ustar00rootroot00000000000000# go-gitlab A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way [![Build Status](https://travis-ci.org/xanzy/go-gitlab.svg?branch=master)](https://travis-ci.org/xanzy/go-gitlab) [![GitHub license](https://img.shields.io/github/license/xanzy/go-gitlab.svg)](https://github.com/xanzy/go-gitlab/blob/master/LICENSE) [![Sourcegraph](https://sourcegraph.com/github.com/xanzy/go-gitlab/-/badge.svg)](https://sourcegraph.com/github.com/xanzy/go-gitlab?badge) [![GoDoc](https://godoc.org/github.com/xanzy/go-gitlab?status.svg)](https://godoc.org/github.com/xanzy/go-gitlab) [![Go Report Card](https://goreportcard.com/badge/github.com/xanzy/go-gitlab)](https://goreportcard.com/report/github.com/xanzy/go-gitlab) [![GitHub issues](https://img.shields.io/github/issues/xanzy/go-gitlab.svg)](https://github.com/xanzy/go-gitlab/issues) ## NOTE Release v0.6.0 (released on 25-08-2017) no longer supports the older V3 Gitlab API. If you need V3 support, please use the `f-api-v3` branch. This release contains some backwards incompatible changes that were needed to fully support the V4 Gitlab API. ## Coverage This API client package covers most of the existing Gitlab API calls and is updated regularly to add new and/or missing endpoints. Currently the following services are supported: - [x] Award Emojis - [x] Branches - [x] Broadcast Messages - [x] Commits - [x] Container Registry - [x] Custom Attributes - [x] Deploy Keys - [x] Deployments - [ ] Discussions (threaded comments) - [x] Environments - [ ] Epic Issues - [ ] Epics - [x] Events - [x] Feature Flags - [ ] Geo Nodes - [x] GitLab CI Config Templates - [x] Gitignores Templates - [x] Group Access Requests - [x] Group Issue Boards - [x] Group Members - [x] Group Milestones - [x] Group-Level Variables - [x] Groups - [x] Issue Boards - [x] Issues - [x] Jobs - [x] Keys - [x] Labels - [x] License - [x] Merge Request Approvals - [x] Merge Requests - [x] Namespaces - [x] Notes (comments) - [x] Notification Settings - [x] Open Source License Templates - [x] Pages Domains - [x] Pipeline Schedules - [x] Pipeline Triggers - [x] Pipelines - [x] Project Access Requests - [x] Project Badges - [x] Project Clusters - [x] Project Import/export - [x] Project Members - [x] Project Milestones - [x] Project Snippets - [x] Project-Level Variables - [x] Projects (including setting Webhooks) - [x] Protected Branches - [x] Protected Tags - [x] Repositories - [x] Repository Files - [x] Runners - [x] Search - [x] Services - [x] Settings - [x] Sidekiq Metrics - [x] System Hooks - [x] Tags - [x] Todos - [x] Users - [x] Validate CI Configuration - [x] Version - [x] Wikis ## Usage ```go import "github.com/xanzy/go-gitlab" ``` Construct a new GitLab client, then use the various services on the client to access different parts of the GitLab API. For example, to list all users: ```go git := gitlab.NewClient(nil, "yourtokengoeshere") //git.SetBaseURL("https://git.mydomain.com/api/v4") users, _, err := git.Users.ListUsers(&gitlab.ListUsersOptions{}) ``` Some API methods have optional parameters that can be passed. For example, to list all projects for user "svanharmelen": ```go git := gitlab.NewClient(nil) opt := &ListProjectsOptions{Search: gitlab.String("svanharmelen")} projects, _, err := git.Projects.ListProjects(opt) ``` ### Examples The [examples](https://github.com/xanzy/go-gitlab/tree/master/examples) directory contains a couple for clear examples, of which one is partially listed here as well: ```go package main import ( "log" "github.com/xanzy/go-gitlab" ) func main() { git := gitlab.NewClient(nil, "yourtokengoeshere") // Create new project p := &gitlab.CreateProjectOptions{ Name: gitlab.String("My Project"), Description: gitlab.String("Just a test project to play with"), MergeRequestsEnabled: gitlab.Bool(true), SnippetsEnabled: gitlab.Bool(true), Visibility: gitlab.Visibility(gitlab.PublicVisibility), } project, _, err := git.Projects.CreateProject(p) if err != nil { log.Fatal(err) } // Add a new snippet s := &gitlab.CreateProjectSnippetOptions{ Title: gitlab.String("Dummy Snippet"), FileName: gitlab.String("snippet.go"), Code: gitlab.String("package main...."), Visibility: gitlab.Visibility(gitlab.PublicVisibility), } _, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s) if err != nil { log.Fatal(err) } } ``` For complete usage of go-gitlab, see the full [package docs](https://godoc.org/github.com/xanzy/go-gitlab). ## ToDo - The biggest thing this package still needs is tests :disappointed: ## Issues - If you have an issue: report it on the [issue tracker](https://github.com/xanzy/go-gitlab/issues) ## Author Sander van Harmelen () ## License Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at golang-github-xanzy-go-gitlab-0.22.2/access_requests.go000066400000000000000000000156371357140411500230760ustar00rootroot00000000000000package gitlab import ( "fmt" "time" ) // AccessRequest represents a access request for a group or project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html type AccessRequest struct { ID int `json:"id"` Username string `json:"username"` Name string `json:"name"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` RequestedAt *time.Time `json:"requested_at"` AccessLevel AccessLevelValue `json:"access_level"` } // AccessRequestsService handles communication with the project/group // access requests related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/access_requests.html type AccessRequestsService struct { client *Client } // ListAccessRequestsOptions represents the available // ListProjectAccessRequests() or ListGroupAccessRequests() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project type ListAccessRequestsOptions ListOptions // ListProjectAccessRequests gets a list of access requests // viewable by the authenticated user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project func (s *AccessRequestsService) ListProjectAccessRequests(pid interface{}, opt *ListAccessRequestsOptions, options ...OptionFunc) ([]*AccessRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/access_requests", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ars []*AccessRequest resp, err := s.client.Do(req, &ars) if err != nil { return nil, resp, err } return ars, resp, err } // ListGroupAccessRequests gets a list of access requests // viewable by the authenticated user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project func (s *AccessRequestsService) ListGroupAccessRequests(gid interface{}, opt *ListAccessRequestsOptions, options ...OptionFunc) ([]*AccessRequest, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/access_requests", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ars []*AccessRequest resp, err := s.client.Do(req, &ars) if err != nil { return nil, resp, err } return ars, resp, err } // RequestProjectAccess requests access for the authenticated user // to a group or project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project func (s *AccessRequestsService) RequestProjectAccess(pid interface{}, options ...OptionFunc) (*AccessRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/access_requests", pathEscape(project)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } ar := new(AccessRequest) resp, err := s.client.Do(req, ar) if err != nil { return nil, resp, err } return ar, resp, err } // RequestGroupAccess requests access for the authenticated user // to a group or project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project func (s *AccessRequestsService) RequestGroupAccess(gid interface{}, options ...OptionFunc) (*AccessRequest, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/access_requests", pathEscape(group)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } ar := new(AccessRequest) resp, err := s.client.Do(req, ar) if err != nil { return nil, resp, err } return ar, resp, err } // ApproveAccessRequestOptions represents the available // ApproveProjectAccessRequest() and ApproveGroupAccessRequest() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request type ApproveAccessRequestOptions struct { AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` } // ApproveProjectAccessRequest approves an access request for the given user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request func (s *AccessRequestsService) ApproveProjectAccessRequest(pid interface{}, user int, opt *ApproveAccessRequestOptions, options ...OptionFunc) (*AccessRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/access_requests/%d/approve", pathEscape(project), user) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ar := new(AccessRequest) resp, err := s.client.Do(req, ar) if err != nil { return nil, resp, err } return ar, resp, err } // ApproveGroupAccessRequest approves an access request for the given user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request func (s *AccessRequestsService) ApproveGroupAccessRequest(gid interface{}, user int, opt *ApproveAccessRequestOptions, options ...OptionFunc) (*AccessRequest, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/access_requests/%d/approve", pathEscape(group), user) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ar := new(AccessRequest) resp, err := s.client.Do(req, ar) if err != nil { return nil, resp, err } return ar, resp, err } // DenyProjectAccessRequest denies an access request for the given user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request func (s *AccessRequestsService) DenyProjectAccessRequest(pid interface{}, user int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/access_requests/%d", pathEscape(project), user) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DenyGroupAccessRequest denies an access request for the given user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request func (s *AccessRequestsService) DenyGroupAccessRequest(gid interface{}, user int, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/access_requests/%d", pathEscape(group), user) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/access_requests_test.go000066400000000000000000000271371357140411500241330ustar00rootroot00000000000000package gitlab import ( "encoding/json" "fmt" "net/http" "testing" "time" "github.com/stretchr/testify/assert" ) func TestListProjectAccessRequests(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/access_requests", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprintf(w, `[ { "id": 1, "username": "raymond_smith", "name": "Raymond Smith", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z" }, { "id": 2, "username": "john_doe", "name": "John Doe", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z" } ]`) }) created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC) expected := []*AccessRequest{ &AccessRequest{ ID: 1, Username: "raymond_smith", Name: "Raymond Smith", State: "active", CreatedAt: &created, RequestedAt: &created, }, &AccessRequest{ ID: 2, Username: "john_doe", Name: "John Doe", State: "active", CreatedAt: &created, RequestedAt: &created, }, } requests, resp, err := client.AccessRequests.ListProjectAccessRequests(1, nil) assert.NoError(t, err) assert.Equal(t, expected, requests) requests, resp, err = client.AccessRequests.ListProjectAccessRequests(1.5, nil) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, requests) assert.Nil(t, resp) requests, resp, err = client.AccessRequests.ListProjectAccessRequests(2, nil) assert.Error(t, err) assert.Nil(t, requests) assert.Equal(t, http.StatusNotFound, resp.StatusCode) requests, resp, err = client.AccessRequests.ListProjectAccessRequests(1, nil, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, requests) assert.Nil(t, resp) } func TestListGroupAccessRequests(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/access_requests", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprintf(w, `[ { "id": 1, "username": "raymond_smith", "name": "Raymond Smith", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z" }, { "id": 2, "username": "john_doe", "name": "John Doe", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z" } ]`) }) created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC) expected := []*AccessRequest{ &AccessRequest{ ID: 1, Username: "raymond_smith", Name: "Raymond Smith", State: "active", CreatedAt: &created, RequestedAt: &created, }, &AccessRequest{ ID: 2, Username: "john_doe", Name: "John Doe", State: "active", CreatedAt: &created, RequestedAt: &created, }, } requests, resp, err := client.AccessRequests.ListGroupAccessRequests(1, nil) assert.NoError(t, err) assert.Equal(t, expected, requests) requests, resp, err = client.AccessRequests.ListGroupAccessRequests(1.5, nil) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, requests) assert.Nil(t, resp) requests, resp, err = client.AccessRequests.ListGroupAccessRequests(2, nil) assert.Error(t, err) assert.Nil(t, requests) assert.Equal(t, http.StatusNotFound, resp.StatusCode) requests, resp, err = client.AccessRequests.ListGroupAccessRequests(1, nil, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, requests) assert.Nil(t, resp) } func TestRequestProjectAccess(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/access_requests", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprintf(w, `{ "id": 1, "username": "raymond_smith", "name": "Raymond Smith", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z" }`) }) created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC) expected := &AccessRequest{ ID: 1, Username: "raymond_smith", Name: "Raymond Smith", State: "active", CreatedAt: &created, RequestedAt: &created, } accessRequest, resp, err := client.AccessRequests.RequestProjectAccess(1, nil) assert.NoError(t, err) assert.Equal(t, expected, accessRequest) accessRequest, resp, err = client.AccessRequests.RequestProjectAccess(1.5, nil) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, accessRequest) assert.Nil(t, resp) accessRequest, resp, err = client.AccessRequests.RequestProjectAccess(2, nil) assert.Error(t, err) assert.Nil(t, accessRequest) assert.Equal(t, http.StatusNotFound, resp.StatusCode) accessRequest, resp, err = client.AccessRequests.RequestProjectAccess(1, nil, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, accessRequest) assert.Nil(t, resp) } func TestRequestGroupAccess(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/access_requests", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprintf(w, `{ "id": 1, "username": "raymond_smith", "name": "Raymond Smith", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z" }`) }) created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC) expected := &AccessRequest{ ID: 1, Username: "raymond_smith", Name: "Raymond Smith", State: "active", CreatedAt: &created, RequestedAt: &created, } accessRequest, resp, err := client.AccessRequests.RequestGroupAccess(1, nil) assert.NoError(t, err) assert.Equal(t, expected, accessRequest) accessRequest, resp, err = client.AccessRequests.RequestGroupAccess(1.5, nil) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, accessRequest) assert.Nil(t, resp) accessRequest, resp, err = client.AccessRequests.RequestGroupAccess(2, nil) assert.Error(t, err) assert.Nil(t, accessRequest) assert.Equal(t, http.StatusNotFound, resp.StatusCode) accessRequest, resp, err = client.AccessRequests.RequestGroupAccess(1, nil, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, accessRequest) assert.Nil(t, resp) } func TestApproveProjectAccessRequest(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/access_requests/10/approve", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") var opt ApproveAccessRequestOptions err := json.NewDecoder(r.Body).Decode(&opt) assert.NoError(t, err) defer r.Body.Close() fmt.Fprintf(w, `{ "id": 10, "username": "raymond_smith", "name": "Raymond Smith", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z", "access_level": %d }`, *opt.AccessLevel) }) created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC) expected := &AccessRequest{ ID: 10, Username: "raymond_smith", Name: "Raymond Smith", State: "active", CreatedAt: &created, RequestedAt: &created, AccessLevel: DeveloperPermissions, } opt := &ApproveAccessRequestOptions{ AccessLevel: AccessLevel(DeveloperPermissions), } request, resp, err := client.AccessRequests.ApproveProjectAccessRequest(1, 10, opt) assert.NoError(t, err) assert.Equal(t, expected, request) request, resp, err = client.AccessRequests.ApproveProjectAccessRequest(1.5, 10, opt) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, request) assert.Nil(t, resp) request, resp, err = client.AccessRequests.ApproveProjectAccessRequest(2, 10, opt) assert.Error(t, err) assert.Nil(t, request) assert.Equal(t, http.StatusNotFound, resp.StatusCode) request, resp, err = client.AccessRequests.ApproveProjectAccessRequest(1, 10, opt, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, request) assert.Nil(t, resp) } func TestApproveGroupAccessRequest(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/access_requests/10/approve", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") var opt ApproveAccessRequestOptions err := json.NewDecoder(r.Body).Decode(&opt) assert.NoError(t, err) defer r.Body.Close() fmt.Fprintf(w, `{ "id": 10, "username": "raymond_smith", "name": "Raymond Smith", "state": "active", "created_at": "2012-10-22T14:13:35Z", "requested_at": "2012-10-22T14:13:35Z", "access_level": %d }`, *opt.AccessLevel) }) created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC) expected := &AccessRequest{ ID: 10, Username: "raymond_smith", Name: "Raymond Smith", State: "active", CreatedAt: &created, RequestedAt: &created, AccessLevel: DeveloperPermissions, } opt := &ApproveAccessRequestOptions{ AccessLevel: AccessLevel(DeveloperPermissions), } request, resp, err := client.AccessRequests.ApproveGroupAccessRequest(1, 10, opt) assert.NoError(t, err) assert.Equal(t, expected, request) request, resp, err = client.AccessRequests.ApproveGroupAccessRequest(1.5, 10, opt) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, request) assert.Nil(t, resp) request, resp, err = client.AccessRequests.ApproveGroupAccessRequest(2, 10, opt) assert.Error(t, err) assert.Nil(t, request) assert.Equal(t, http.StatusNotFound, resp.StatusCode) request, resp, err = client.AccessRequests.ApproveGroupAccessRequest(1, 10, opt, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, request) assert.Nil(t, resp) } func TestDenyProjectAccessRequest(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/access_requests/10", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) resp, err := client.AccessRequests.DenyProjectAccessRequest(1, 10) assert.NoError(t, err) resp, err = client.AccessRequests.DenyProjectAccessRequest(1.5, 10) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, resp) resp, err = client.AccessRequests.DenyProjectAccessRequest(2, 10) assert.Error(t, err) assert.Equal(t, http.StatusNotFound, resp.StatusCode) resp, err = client.AccessRequests.DenyProjectAccessRequest(1, 10, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, resp) } func TestDenyGroupAccessRequest(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/access_requests/10", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) resp, err := client.AccessRequests.DenyGroupAccessRequest(1, 10) assert.NoError(t, err) resp, err = client.AccessRequests.DenyGroupAccessRequest(1.5, 10) assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string") assert.Nil(t, resp) resp, err = client.AccessRequests.DenyGroupAccessRequest(2, 10) assert.Error(t, err) assert.Equal(t, http.StatusNotFound, resp.StatusCode) resp, err = client.AccessRequests.DenyGroupAccessRequest(1, 10, errorOption) assert.EqualError(t, err, "OptionFunc returns an error") assert.Nil(t, resp) } golang-github-xanzy-go-gitlab-0.22.2/award_emojis.go000066400000000000000000000415261357140411500223420ustar00rootroot00000000000000// // Copyright 2017, Arkbriar // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // AwardEmojiService handles communication with the emoji awards related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html type AwardEmojiService struct { client *Client } // AwardEmoji represents a GitLab Award Emoji. // // GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html type AwardEmoji struct { ID int `json:"id"` Name string `json:"name"` User struct { Name string `json:"name"` Username string `json:"username"` ID int `json:"id"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"user"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` AwardableID int `json:"awardable_id"` AwardableType string `json:"awardable_type"` } const ( awardMergeRequest = "merge_requests" awardIssue = "issues" awardSnippets = "snippets" ) // ListAwardEmojiOptions represents the available options for listing emoji // for each resources // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html type ListAwardEmojiOptions ListOptions // ListMergeRequestAwardEmoji gets a list of all award emoji on the merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji func (s *AwardEmojiService) ListMergeRequestAwardEmoji(pid interface{}, mergeRequestIID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { return s.listAwardEmoji(pid, awardMergeRequest, mergeRequestIID, opt, options...) } // ListIssueAwardEmoji gets a list of all award emoji on the issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji func (s *AwardEmojiService) ListIssueAwardEmoji(pid interface{}, issueIID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { return s.listAwardEmoji(pid, awardIssue, issueIID, opt, options...) } // ListSnippetAwardEmoji gets a list of all award emoji on the snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji func (s *AwardEmojiService) ListSnippetAwardEmoji(pid interface{}, snippetID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { return s.listAwardEmoji(pid, awardSnippets, snippetID, opt, options...) } func (s *AwardEmojiService) listAwardEmoji(pid interface{}, resource string, resourceID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/award_emoji", pathEscape(project), resource, resourceID, ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var as []*AwardEmoji resp, err := s.client.Do(req, &as) if err != nil { return nil, resp, err } return as, resp, err } // GetMergeRequestAwardEmoji get an award emoji from merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji func (s *AwardEmojiService) GetMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.getAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...) } // GetIssueAwardEmoji get an award emoji from issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji func (s *AwardEmojiService) GetIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.getAwardEmoji(pid, awardIssue, issueIID, awardID, options...) } // GetSnippetAwardEmoji get an award emoji from snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji func (s *AwardEmojiService) GetSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.getAwardEmoji(pid, awardSnippets, snippetID, awardID, options...) } func (s *AwardEmojiService) getAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", pathEscape(project), resource, resourceID, awardID, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } a := new(AwardEmoji) resp, err := s.client.Do(req, &a) if err != nil { return nil, resp, err } return a, resp, err } // CreateAwardEmojiOptions represents the available options for awarding emoji // for a resource // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji type CreateAwardEmojiOptions struct { Name string `json:"name"` } // CreateMergeRequestAwardEmoji get an award emoji from merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji func (s *AwardEmojiService) CreateMergeRequestAwardEmoji(pid interface{}, mergeRequestIID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.createAwardEmoji(pid, awardMergeRequest, mergeRequestIID, opt, options...) } // CreateIssueAwardEmoji get an award emoji from issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji func (s *AwardEmojiService) CreateIssueAwardEmoji(pid interface{}, issueIID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.createAwardEmoji(pid, awardIssue, issueIID, opt, options...) } // CreateSnippetAwardEmoji get an award emoji from snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji func (s *AwardEmojiService) CreateSnippetAwardEmoji(pid interface{}, snippetID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.createAwardEmoji(pid, awardSnippets, snippetID, opt, options...) } func (s *AwardEmojiService) createAwardEmoji(pid interface{}, resource string, resourceID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/award_emoji", pathEscape(project), resource, resourceID, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } a := new(AwardEmoji) resp, err := s.client.Do(req, &a) if err != nil { return nil, resp, err } return a, resp, err } // DeleteIssueAwardEmoji delete award emoji on an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note func (s *AwardEmojiService) DeleteIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...OptionFunc) (*Response, error) { return s.deleteAwardEmoji(pid, awardMergeRequest, issueIID, awardID, options...) } // DeleteMergeRequestAwardEmoji delete award emoji on a merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note func (s *AwardEmojiService) DeleteMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...OptionFunc) (*Response, error) { return s.deleteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...) } // DeleteSnippetAwardEmoji delete award emoji on a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note func (s *AwardEmojiService) DeleteSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...OptionFunc) (*Response, error) { return s.deleteAwardEmoji(pid, awardMergeRequest, snippetID, awardID, options...) } // DeleteAwardEmoji Delete an award emoji on the specified resource. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#delete-an-award-emoji func (s *AwardEmojiService) deleteAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", pathEscape(project), resource, resourceID, awardID) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListIssuesAwardEmojiOnNote gets a list of all award emoji on a note from the // issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) ListIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { return s.listAwardEmojiOnNote(pid, awardIssue, issueID, noteID, opt, options...) } // ListMergeRequestAwardEmojiOnNote gets a list of all award emoji on a note // from the merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) ListMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { return s.listAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, opt, options...) } // ListSnippetAwardEmojiOnNote gets a list of all award emoji on a note from the // snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) ListSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { return s.listAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, opt, options...) } func (s *AwardEmojiService) listAwardEmojiOnNote(pid interface{}, resources string, ressourceID, noteID int, opt *ListAwardEmojiOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji", pathEscape(project), resources, ressourceID, noteID) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var as []*AwardEmoji resp, err := s.client.Do(req, &as) if err != nil { return nil, resp, err } return as, resp, err } // GetIssuesAwardEmojiOnNote gets an award emoji on a note from an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) GetIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.getSingleNoteAwardEmoji(pid, awardIssue, issueID, noteID, awardID, options...) } // GetMergeRequestAwardEmojiOnNote gets an award emoji on a note from a // merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) GetMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.getSingleNoteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, noteID, awardID, options...) } // GetSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) GetSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.getSingleNoteAwardEmoji(pid, awardSnippets, snippetIID, noteID, awardID, options...) } func (s *AwardEmojiService) getSingleNoteAwardEmoji(pid interface{}, ressource string, resourceID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d", pathEscape(project), ressource, resourceID, noteID, awardID, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } a := new(AwardEmoji) resp, err := s.client.Do(req, &a) if err != nil { return nil, resp, err } return a, resp, err } // CreateIssuesAwardEmojiOnNote gets an award emoji on a note from an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) CreateIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.createAwardEmojiOnNote(pid, awardIssue, issueID, noteID, opt, options...) } // CreateMergeRequestAwardEmojiOnNote gets an award emoji on a note from a // merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) CreateMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.createAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, opt, options...) } // CreateSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) CreateSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { return s.createAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, opt, options...) } // CreateAwardEmojiOnNote award emoji on a note. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note func (s *AwardEmojiService) createAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID int, opt *CreateAwardEmojiOptions, options ...OptionFunc) (*AwardEmoji, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji", pathEscape(project), resource, resourceID, noteID, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } a := new(AwardEmoji) resp, err := s.client.Do(req, &a) if err != nil { return nil, resp, err } return a, resp, err } // DeleteIssuesAwardEmojiOnNote deletes an award emoji on a note from an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) DeleteIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...OptionFunc) (*Response, error) { return s.deleteAwardEmojiOnNote(pid, awardIssue, issueID, noteID, awardID, options...) } // DeleteMergeRequestAwardEmojiOnNote deletes an award emoji on a note from a // merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) DeleteMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...OptionFunc) (*Response, error) { return s.deleteAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, awardID, options...) } // DeleteSnippetAwardEmojiOnNote deletes an award emoji on a note from a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes func (s *AwardEmojiService) DeleteSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...OptionFunc) (*Response, error) { return s.deleteAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, awardID, options...) } func (s *AwardEmojiService) deleteAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID, awardID int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d", pathEscape(project), resource, resourceID, noteID, awardID, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/boards.go000066400000000000000000000232551357140411500211470ustar00rootroot00000000000000// // Copyright 2015, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // IssueBoardsService handles communication with the issue board related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html type IssueBoardsService struct { client *Client } // IssueBoard represents a GitLab issue board. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html type IssueBoard struct { ID int `json:"id"` Name string `json:"name"` Project *Project `json:"project"` Milestone *Milestone `json:"milestone"` Lists []*BoardList `json:"lists"` } func (b IssueBoard) String() string { return Stringify(b) } // BoardList represents a GitLab board list. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html type BoardList struct { ID int `json:"id"` Label *Label `json:"label"` Position int `json:"position"` } func (b BoardList) String() string { return Stringify(b) } // CreateIssueBoardOptions represents the available CreateIssueBoard() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter type CreateIssueBoardOptions struct { Name *string `url:"name" json:"name"` } // CreateIssueBoard creates a new issue board. // // GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter func (s *IssueBoardsService) CreateIssueBoard(pid interface{}, opt *CreateIssueBoardOptions, options ...OptionFunc) (*IssueBoard, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } board := new(IssueBoard) resp, err := s.client.Do(req, board) if err != nil { return nil, resp, err } return board, resp, err } // UpdateIssueBoardOptions represents the available UpdateIssueBoard() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#update-a-board-starter type UpdateIssueBoardOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` Labels Labels `url:"labels,omitempty" json:"labels,omitempty"` Weight *int `url:"weight,omitempty" json:"weight,omitempty"` } // UpdateIssueBoard update an issue board. // // GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter func (s *IssueBoardsService) UpdateIssueBoard(pid interface{}, board int, opt *UpdateIssueBoardOptions, options ...OptionFunc) (*IssueBoard, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } is := new(IssueBoard) resp, err := s.client.Do(req, is) if err != nil { return nil, resp, err } return is, resp, err } // DeleteIssueBoard deletes an issue board. // // GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#delete-a-board-starter func (s *IssueBoardsService) DeleteIssueBoard(pid interface{}, board int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListIssueBoardsOptions represents the available ListIssueBoards() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board type ListIssueBoardsOptions ListOptions // ListIssueBoards gets a list of all issue boards in a project. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board func (s *IssueBoardsService) ListIssueBoards(pid interface{}, opt *ListIssueBoardsOptions, options ...OptionFunc) ([]*IssueBoard, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var is []*IssueBoard resp, err := s.client.Do(req, &is) if err != nil { return nil, resp, err } return is, resp, err } // GetIssueBoard gets a single issue board of a project. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board func (s *IssueBoardsService) GetIssueBoard(pid interface{}, board int, options ...OptionFunc) (*IssueBoard, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ib := new(IssueBoard) resp, err := s.client.Do(req, ib) if err != nil { return nil, resp, err } return ib, resp, err } // GetIssueBoardListsOptions represents the available GetIssueBoardLists() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists type GetIssueBoardListsOptions ListOptions // GetIssueBoardLists gets a list of the issue board's lists. Does not include // backlog and closed lists. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists func (s *IssueBoardsService) GetIssueBoardLists(pid interface{}, board int, opt *GetIssueBoardListsOptions, options ...OptionFunc) ([]*BoardList, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards/%d/lists", pathEscape(project), board) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var bl []*BoardList resp, err := s.client.Do(req, &bl) if err != nil { return nil, resp, err } return bl, resp, err } // GetIssueBoardList gets a single issue board list. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board-list func (s *IssueBoardsService) GetIssueBoardList(pid interface{}, board, list int, options ...OptionFunc) (*BoardList, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", pathEscape(project), board, list, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } bl := new(BoardList) resp, err := s.client.Do(req, bl) if err != nil { return nil, resp, err } return bl, resp, err } // CreateIssueBoardListOptions represents the available CreateIssueBoardList() // options. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list type CreateIssueBoardListOptions struct { LabelID *int `url:"label_id" json:"label_id"` } // CreateIssueBoardList creates a new issue board list. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list func (s *IssueBoardsService) CreateIssueBoardList(pid interface{}, board int, opt *CreateIssueBoardListOptions, options ...OptionFunc) (*BoardList, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards/%d/lists", pathEscape(project), board) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } bl := new(BoardList) resp, err := s.client.Do(req, bl) if err != nil { return nil, resp, err } return bl, resp, err } // UpdateIssueBoardListOptions represents the available UpdateIssueBoardList() // options. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list type UpdateIssueBoardListOptions struct { Position *int `url:"position" json:"position"` } // UpdateIssueBoardList updates the position of an existing issue board list. // // GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list func (s *IssueBoardsService) UpdateIssueBoardList(pid interface{}, board, list int, opt *UpdateIssueBoardListOptions, options ...OptionFunc) (*BoardList, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", pathEscape(project), board, list, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } bl := new(BoardList) resp, err := s.client.Do(req, bl) if err != nil { return nil, resp, err } return bl, resp, err } // DeleteIssueBoardList soft deletes an issue board list. Only for admins and // project owners. // // GitLab API docs: // https://docs.gitlab.com/ce/api/boards.html#delete-a-board-list func (s *IssueBoardsService) DeleteIssueBoardList(pid interface{}, board, list int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", pathEscape(project), board, list, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/branches.go000066400000000000000000000161401357140411500214550ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/url" ) // BranchesService handles communication with the branch related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/branches.html type BranchesService struct { client *Client } // Branch represents a GitLab branch. // // GitLab API docs: https://docs.gitlab.com/ce/api/branches.html type Branch struct { Commit *Commit `json:"commit"` Name string `json:"name"` Protected bool `json:"protected"` Merged bool `json:"merged"` Default bool `json:"default"` DevelopersCanPush bool `json:"developers_can_push"` DevelopersCanMerge bool `json:"developers_can_merge"` } func (b Branch) String() string { return Stringify(b) } // ListBranchesOptions represents the available ListBranches() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#list-repository-branches type ListBranchesOptions struct { ListOptions Search *string `url:"search,omitempty" json:"search,omitempty"` } // ListBranches gets a list of repository branches from a project, sorted by // name alphabetically. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#list-repository-branches func (s *BranchesService) ListBranches(pid interface{}, opts *ListBranchesOptions, options ...OptionFunc) ([]*Branch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opts, options) if err != nil { return nil, nil, err } var b []*Branch resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b, resp, err } // GetBranch gets a single project repository branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#get-single-repository-branch func (s *BranchesService) GetBranch(pid interface{}, branch string, options ...OptionFunc) (*Branch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } b := new(Branch) resp, err := s.client.Do(req, b) if err != nil { return nil, resp, err } return b, resp, err } // ProtectBranchOptions represents the available ProtectBranch() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch type ProtectBranchOptions struct { DevelopersCanPush *bool `url:"developers_can_push,omitempty" json:"developers_can_push,omitempty"` DevelopersCanMerge *bool `url:"developers_can_merge,omitempty" json:"developers_can_merge,omitempty"` } // ProtectBranch protects a single project repository branch. This is an // idempotent function, protecting an already protected repository branch // still returns a 200 OK status code. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch func (s *BranchesService) ProtectBranch(pid interface{}, branch string, opts *ProtectBranchOptions, options ...OptionFunc) (*Branch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/branches/%s/protect", pathEscape(project), url.PathEscape(branch)) req, err := s.client.NewRequest("PUT", u, opts, options) if err != nil { return nil, nil, err } b := new(Branch) resp, err := s.client.Do(req, b) if err != nil { return nil, resp, err } return b, resp, err } // UnprotectBranch unprotects a single project repository branch. This is an // idempotent function, unprotecting an already unprotected repository branch // still returns a 200 OK status code. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#unprotect-repository-branch func (s *BranchesService) UnprotectBranch(pid interface{}, branch string, options ...OptionFunc) (*Branch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/branches/%s/unprotect", pathEscape(project), url.PathEscape(branch)) req, err := s.client.NewRequest("PUT", u, nil, options) if err != nil { return nil, nil, err } b := new(Branch) resp, err := s.client.Do(req, b) if err != nil { return nil, resp, err } return b, resp, err } // CreateBranchOptions represents the available CreateBranch() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#create-repository-branch type CreateBranchOptions struct { Branch *string `url:"branch,omitempty" json:"branch,omitempty"` Ref *string `url:"ref,omitempty" json:"ref,omitempty"` } // CreateBranch creates branch from commit SHA or existing branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#create-repository-branch func (s *BranchesService) CreateBranch(pid interface{}, opt *CreateBranchOptions, options ...OptionFunc) (*Branch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } b := new(Branch) resp, err := s.client.Do(req, b) if err != nil { return nil, resp, err } return b, resp, err } // DeleteBranch deletes an existing branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#delete-repository-branch func (s *BranchesService) DeleteBranch(pid interface{}, branch string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteMergedBranches deletes all branches that are merged into the project's default branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/branches.html#delete-merged-branches func (s *BranchesService) DeleteMergedBranches(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/repository/merged_branches", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/broadcast_messages.go000066400000000000000000000127671357140411500235340ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // BroadcastMessagesService handles communication with the broadcast // messages methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/broadcast_messages.html type BroadcastMessagesService struct { client *Client } // BroadcastMessage represents a GitLab issue board. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages type BroadcastMessage struct { Message string `json:"message"` StartsAt *time.Time `json:"starts_at"` EndsAt *time.Time `json:"ends_at"` Color string `json:"color"` Font string `json:"font"` ID int `json:"id"` Active bool `json:"active"` } // ListBroadcastMessagesOptions represents the available ListBroadcastMessages() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages type ListBroadcastMessagesOptions ListOptions // ListBroadcastMessages gets a list of all broadcasted messages. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages func (s *BroadcastMessagesService) ListBroadcastMessages(opt *ListBroadcastMessagesOptions, options ...OptionFunc) ([]*BroadcastMessage, *Response, error) { req, err := s.client.NewRequest("GET", "broadcast_messages", opt, options) if err != nil { return nil, nil, err } var bs []*BroadcastMessage resp, err := s.client.Do(req, &bs) if err != nil { return nil, resp, err } return bs, resp, err } // GetBroadcastMessage gets a single broadcast message. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#get-a-specific-broadcast-message func (s *BroadcastMessagesService) GetBroadcastMessage(broadcast int, options ...OptionFunc) (*BroadcastMessage, *Response, error) { u := fmt.Sprintf("broadcast_messages/%d", broadcast) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } b := new(BroadcastMessage) resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b, resp, err } // CreateBroadcastMessageOptions represents the available CreateBroadcastMessage() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message type CreateBroadcastMessageOptions struct { Message *string `url:"message" json:"message"` StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"` EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"` Color *string `url:"color,omitempty" json:"color,omitempty"` Font *string `url:"font,omitempty" json:"font,omitempty"` } // CreateBroadcastMessage creates a message to broadcast. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message func (s *BroadcastMessagesService) CreateBroadcastMessage(opt *CreateBroadcastMessageOptions, options ...OptionFunc) (*BroadcastMessage, *Response, error) { req, err := s.client.NewRequest("POST", "broadcast_messages", opt, options) if err != nil { return nil, nil, err } b := new(BroadcastMessage) resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b, resp, err } // UpdateBroadcastMessageOptions represents the available CreateBroadcastMessage() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message type UpdateBroadcastMessageOptions struct { Message *string `url:"message,omitempty" json:"message,omitempty"` StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"` EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"` Color *string `url:"color,omitempty" json:"color,omitempty"` Font *string `url:"font,omitempty" json:"font,omitempty"` } // UpdateBroadcastMessage update a broadcasted message. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message func (s *BroadcastMessagesService) UpdateBroadcastMessage(broadcast int, opt *UpdateBroadcastMessageOptions, options ...OptionFunc) (*BroadcastMessage, *Response, error) { u := fmt.Sprintf("broadcast_messages/%d", broadcast) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } b := new(BroadcastMessage) resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b, resp, err } // DeleteBroadcastMessage deletes a broadcasted message. // // GitLab API docs: // https://docs.gitlab.com/ce/api/broadcast_messages.html#delete-a-broadcast-message func (s *BroadcastMessagesService) DeleteBroadcastMessage(broadcast int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("broadcast_messages/%d", broadcast) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/broadcast_messages_test.go000066400000000000000000000131501357140411500245560ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" "time" ) func TestListBroadcastMessages(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/broadcast_messages", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprintf(w, `[{ "message": "Some Message", "starts_at": "2017-06-26T06:00:00.000Z", "ends_at": "2017-06-27T12:59:00.000Z", "color": "#E75E40", "font": "#FFFFFF", "id": 1, "active": false },{ "message": "SomeMessage2", "starts_at": "2015-04-27T06:43:00.000Z", "ends_at": "2015-04-28T20:43:00.000Z", "color": "#AA33EE", "font": "#224466", "id": 2, "active": true }]`) }) got, _, err := client.BroadcastMessage.ListBroadcastMessages(nil, nil) if err != nil { t.Errorf("ListBroadcastMessages returned error: %v", err) } wantedFirstStartsAt := time.Date(2017, 06, 26, 6, 0, 0, 0, time.UTC) wantedFirstEndsAt := time.Date(2017, 06, 27, 12, 59, 0, 0, time.UTC) wantedSecondStartsAt := time.Date(2015, 04, 27, 6, 43, 0, 0, time.UTC) wantedSecondEndsAt := time.Date(2015, 04, 28, 20, 43, 0, 0, time.UTC) want := []*BroadcastMessage{{ Message: "Some Message", StartsAt: &wantedFirstStartsAt, EndsAt: &wantedFirstEndsAt, Color: "#E75E40", Font: "#FFFFFF", ID: 1, Active: false, }, { Message: "SomeMessage2", StartsAt: &wantedSecondStartsAt, EndsAt: &wantedSecondEndsAt, Color: "#AA33EE", Font: "#224466", ID: 2, Active: true, }} if !reflect.DeepEqual(got, want) { t.Errorf("ListBroadcastMessages returned \ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want)) } } func TestGetBroadcastMessages(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/broadcast_messages/1/", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprintf(w, `{ "message": "Some Message", "starts_at": "2017-06-26T06:00:00.000Z", "ends_at": "2017-06-27T12:59:00.000Z", "color": "#E75E40", "font": "#FFFFFF", "id": 1, "active": false }`) }) got, _, err := client.BroadcastMessage.GetBroadcastMessage(1) if err != nil { t.Errorf("GetBroadcastMessage returned error: %v", err) } wantedStartsAt := time.Date(2017, time.June, 26, 6, 0, 0, 0, time.UTC) wantedEndsAt := time.Date(2017, time.June, 27, 12, 59, 0, 0, time.UTC) want := &BroadcastMessage{ Message: "Some Message", StartsAt: &wantedStartsAt, EndsAt: &wantedEndsAt, Color: "#E75E40", Font: "#FFFFFF", ID: 1, Active: false, } if !reflect.DeepEqual(got, want) { t.Errorf("GetBroadcastMessage returned \ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want)) } } func TestCreateBroadcastMessages(t *testing.T) { mux, server, client := setup() defer teardown(server) wantedStartsAt := time.Date(2017, time.June, 26, 6, 0, 0, 0, time.UTC) wantedEndsAt := time.Date(2017, time.June, 27, 12, 59, 0, 0, time.UTC) mux.HandleFunc("/api/v4/broadcast_messages", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprintf(w, `{ "message": "Some Message", "starts_at": "2017-06-26T06:00:00.000Z", "ends_at": "2017-06-27T12:59:00.000Z", "color": "#E75E40", "font": "#FFFFFF", "id": 42, "active": false }`) }) opt := &CreateBroadcastMessageOptions{ Message: String("Some Message"), StartsAt: &wantedStartsAt, EndsAt: &wantedEndsAt, Color: String("#E75E40"), Font: String("#FFFFFF"), } got, _, err := client.BroadcastMessage.CreateBroadcastMessage(opt) if err != nil { t.Errorf("CreateBroadcastMessage returned error: %v", err) } want := &BroadcastMessage{ Message: "Some Message", StartsAt: &wantedStartsAt, EndsAt: &wantedEndsAt, Color: "#E75E40", Font: "#FFFFFF", ID: 42, Active: false, } if !reflect.DeepEqual(got, want) { t.Errorf("CreateBroadcastMessage returned \ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want)) } } func TestUpdateBroadcastMessages(t *testing.T) { mux, server, client := setup() defer teardown(server) wantedStartsAt := time.Date(2017, time.June, 26, 6, 0, 0, 0, time.UTC) wantedEndsAt := time.Date(2017, time.June, 27, 12, 59, 0, 0, time.UTC) mux.HandleFunc("/api/v4/broadcast_messages/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprintf(w, `{ "message": "Some Message Updated", "starts_at": "2017-06-26T06:00:00.000Z", "ends_at": "2017-06-27T12:59:00.000Z", "color": "#E75E40", "font": "#FFFFFF", "id": 42, "active": false }`) }) opt := &UpdateBroadcastMessageOptions{ Message: String("Some Message Updated"), StartsAt: &wantedStartsAt, EndsAt: &wantedEndsAt, Color: String("#E75E40"), Font: String("#FFFFFF"), } got, _, err := client.BroadcastMessage.UpdateBroadcastMessage(1, opt) if err != nil { t.Errorf("UpdateBroadcastMessage returned error: %v", err) } want := &BroadcastMessage{ Message: "Some Message Updated", StartsAt: &wantedStartsAt, EndsAt: &wantedEndsAt, Color: "#E75E40", Font: "#FFFFFF", ID: 42, Active: false, } if !reflect.DeepEqual(got, want) { t.Errorf("UpdateBroadcastMessage returned \ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want)) } } func TestDeleteBroadcastMessages(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/broadcast_messages/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) _, err := client.BroadcastMessage.DeleteBroadcastMessage(1) if err != nil { t.Errorf("UpdateBroadcastMessage returned error: %v", err) } } golang-github-xanzy-go-gitlab-0.22.2/ci_yml_templates.go000066400000000000000000000035771357140411500232340ustar00rootroot00000000000000package gitlab import ( "fmt" ) // CIYMLTemplatesService handles communication with the gitlab // CI YML templates related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html type CIYMLTemplatesService struct { client *Client } // CIYMLTemplate represents a GitLab CI YML template. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html type CIYMLTemplate struct { Name string `json:"name"` Content string `json:"content"` } // ListCIYMLTemplatesOptions represents the available ListAllTemplates() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates type ListCIYMLTemplatesOptions ListOptions // ListAllTemplates get all GitLab CI YML templates. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#list-gitlab-ci-yml-templates func (s *CIYMLTemplatesService) ListAllTemplates(opt *ListCIYMLTemplatesOptions, options ...OptionFunc) ([]*CIYMLTemplate, *Response, error) { req, err := s.client.NewRequest("GET", "templates/gitlab_ci_ymls", opt, options) if err != nil { return nil, nil, err } var cts []*CIYMLTemplate resp, err := s.client.Do(req, &cts) if err != nil { return nil, resp, err } return cts, resp, err } // GetTemplate get a single GitLab CI YML template. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#single-gitlab-ci-yml-template func (s *CIYMLTemplatesService) GetTemplate(key string, options ...OptionFunc) (*CIYMLTemplate, *Response, error) { u := fmt.Sprintf("templates/gitlab_ci_ymls/%s", pathEscape(key)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ct := new(CIYMLTemplate) resp, err := s.client.Do(req, ct) if err != nil { return nil, resp, err } return ct, resp, err } golang-github-xanzy-go-gitlab-0.22.2/commits.go000066400000000000000000000460451357140411500213520ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/url" "time" ) // CommitsService handles communication with the commit related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html type CommitsService struct { client *Client } // Commit represents a GitLab commit. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html type Commit struct { ID string `json:"id"` ShortID string `json:"short_id"` Title string `json:"title"` AuthorName string `json:"author_name"` AuthorEmail string `json:"author_email"` AuthoredDate *time.Time `json:"authored_date"` CommitterName string `json:"committer_name"` CommitterEmail string `json:"committer_email"` CommittedDate *time.Time `json:"committed_date"` CreatedAt *time.Time `json:"created_at"` Message string `json:"message"` ParentIDs []string `json:"parent_ids"` Stats *CommitStats `json:"stats"` Status *BuildStateValue `json:"status"` LastPipeline *PipelineInfo `json:"last_pipeline"` ProjectID int `json:"project_id"` } // CommitStats represents the number of added and deleted files in a commit. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html type CommitStats struct { Additions int `json:"additions"` Deletions int `json:"deletions"` Total int `json:"total"` } func (c Commit) String() string { return Stringify(c) } // ListCommitsOptions represents the available ListCommits() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-repository-commits type ListCommitsOptions struct { ListOptions RefName *string `url:"ref_name,omitempty" json:"ref_name,omitempty"` Since *time.Time `url:"since,omitempty" json:"since,omitempty"` Until *time.Time `url:"until,omitempty" json:"until,omitempty"` Path *string `url:"path,omitempty" json:"path,omitempty"` All *bool `url:"all,omitempty" json:"all,omitempty"` WithStats *bool `url:"with_stats,omitempty" json:"with_stats,omitempty"` } // ListCommits gets a list of repository commits in a project. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-commits func (s *CommitsService) ListCommits(pid interface{}, opt *ListCommitsOptions, options ...OptionFunc) ([]*Commit, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var c []*Commit resp, err := s.client.Do(req, &c) if err != nil { return nil, resp, err } return c, resp, err } // FileAction represents the available actions that can be performed on a file. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions type FileAction string // The available file actions. const ( FileCreate FileAction = "create" FileDelete FileAction = "delete" FileMove FileAction = "move" FileUpdate FileAction = "update" ) // CommitAction represents a single file action within a commit. type CommitAction struct { Action FileAction `url:"action" json:"action"` FilePath string `url:"file_path" json:"file_path"` PreviousPath string `url:"previous_path,omitempty" json:"previous_path,omitempty"` Content string `url:"content,omitempty" json:"content,omitempty"` Encoding string `url:"encoding,omitempty" json:"encoding,omitempty"` } // CommitRef represents the reference of branches/tags in a commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to type CommitRef struct { Type string `json:"type"` Name string `json:"name"` } // GetCommitRefsOptions represents the available GetCommitRefs() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to type GetCommitRefsOptions struct { ListOptions Type *string `url:"type,omitempty" json:"type,omitempty"` } // GetCommitRefs gets all references (from branches or tags) a commit is pushed to // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to func (s *CommitsService) GetCommitRefs(pid interface{}, sha string, opt *GetCommitRefsOptions, options ...OptionFunc) ([]*CommitRef, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/refs", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var cs []*CommitRef resp, err := s.client.Do(req, &cs) if err != nil { return nil, resp, err } return cs, resp, err } // GetCommit gets a specific commit identified by the commit hash or name of a // branch or tag. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-a-single-commit func (s *CommitsService) GetCommit(pid interface{}, sha string, options ...OptionFunc) (*Commit, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } if sha == "" { return nil, nil, fmt.Errorf("SHA must be a non-empty string") } u := fmt.Sprintf("projects/%s/repository/commits/%s", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } c := new(Commit) resp, err := s.client.Do(req, c) if err != nil { return nil, resp, err } return c, resp, err } // CreateCommitOptions represents the available options for a new commit. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions type CreateCommitOptions struct { Branch *string `url:"branch" json:"branch"` CommitMessage *string `url:"commit_message" json:"commit_message"` StartBranch *string `url:"start_branch,omitempty" json:"start_branch,omitempty"` StartSHA *string `url:"start_sha,omitempty" json:"start_sha,omitempty"` StartProject *string `url:"start_project,omitempty" json:"start_project,omitempty"` Actions []*CommitAction `url:"actions" json:"actions"` AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` Stats *bool `url:"stats,omitempty" json:"stats,omitempty"` Force *bool `url:"force,omitempty" json:"force,omitempty"` } // CreateCommit creates a commit with multiple files and actions. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions func (s *CommitsService) CreateCommit(pid interface{}, opt *CreateCommitOptions, options ...OptionFunc) (*Commit, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } c := new(Commit) resp, err := s.client.Do(req, &c) if err != nil { return nil, resp, err } return c, resp, err } // Diff represents a GitLab diff. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html type Diff struct { Diff string `json:"diff"` NewPath string `json:"new_path"` OldPath string `json:"old_path"` AMode string `json:"a_mode"` BMode string `json:"b_mode"` NewFile bool `json:"new_file"` RenamedFile bool `json:"renamed_file"` DeletedFile bool `json:"deleted_file"` } func (d Diff) String() string { return Stringify(d) } // GetCommitDiffOptions represents the available GetCommitDiff() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit type GetCommitDiffOptions ListOptions // GetCommitDiff gets the diff of a commit in a project.. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit func (s *CommitsService) GetCommitDiff(pid interface{}, sha string, opt *GetCommitDiffOptions, options ...OptionFunc) ([]*Diff, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/diff", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var d []*Diff resp, err := s.client.Do(req, &d) if err != nil { return nil, resp, err } return d, resp, err } // CommitComment represents a GitLab commit comment. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html type CommitComment struct { Note string `json:"note"` Path string `json:"path"` Line int `json:"line"` LineType string `json:"line_type"` Author Author `json:"author"` } // Author represents a GitLab commit author type Author struct { ID int `json:"id"` Username string `json:"username"` Email string `json:"email"` Name string `json:"name"` State string `json:"state"` Blocked bool `json:"blocked"` CreatedAt *time.Time `json:"created_at"` } func (c CommitComment) String() string { return Stringify(c) } // GetCommitCommentsOptions represents the available GetCommitComments() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit type GetCommitCommentsOptions ListOptions // GetCommitComments gets the comments of a commit in a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit func (s *CommitsService) GetCommitComments(pid interface{}, sha string, opt *GetCommitCommentsOptions, options ...OptionFunc) ([]*CommitComment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var c []*CommitComment resp, err := s.client.Do(req, &c) if err != nil { return nil, resp, err } return c, resp, err } // PostCommitCommentOptions represents the available PostCommitComment() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit type PostCommitCommentOptions struct { Note *string `url:"note,omitempty" json:"note,omitempty"` Path *string `url:"path" json:"path"` Line *int `url:"line" json:"line"` LineType *string `url:"line_type" json:"line_type"` } // PostCommitComment adds a comment to a commit. Optionally you can post // comments on a specific line of a commit. Therefor both path, line_new and // line_old are required. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit func (s *CommitsService) PostCommitComment(pid interface{}, sha string, opt *PostCommitCommentOptions, options ...OptionFunc) (*CommitComment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } c := new(CommitComment) resp, err := s.client.Do(req, c) if err != nil { return nil, resp, err } return c, resp, err } // GetCommitStatusesOptions represents the available GetCommitStatuses() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit type GetCommitStatusesOptions struct { ListOptions Ref *string `url:"ref,omitempty" json:"ref,omitempty"` Stage *string `url:"stage,omitempty" json:"stage,omitempty"` Name *string `url:"name,omitempty" json:"name,omitempty"` All *bool `url:"all,omitempty" json:"all,omitempty"` } // CommitStatus represents a GitLab commit status. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit type CommitStatus struct { ID int `json:"id"` SHA string `json:"sha"` Ref string `json:"ref"` Status string `json:"status"` Name string `json:"name"` TargetURL string `json:"target_url"` Description string `json:"description"` CreatedAt *time.Time `json:"created_at"` StartedAt *time.Time `json:"started_at"` FinishedAt *time.Time `json:"finished_at"` Author Author `json:"author"` } // GetCommitStatuses gets the statuses of a commit in a project. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit func (s *CommitsService) GetCommitStatuses(pid interface{}, sha string, opt *GetCommitStatusesOptions, options ...OptionFunc) ([]*CommitStatus, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/statuses", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var cs []*CommitStatus resp, err := s.client.Do(req, &cs) if err != nil { return nil, resp, err } return cs, resp, err } // SetCommitStatusOptions represents the available SetCommitStatus() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit type SetCommitStatusOptions struct { State BuildStateValue `url:"state" json:"state"` Ref *string `url:"ref,omitempty" json:"ref,omitempty"` Name *string `url:"name,omitempty" json:"name,omitempty"` Context *string `url:"context,omitempty" json:"context,omitempty"` TargetURL *string `url:"target_url,omitempty" json:"target_url,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` } // SetCommitStatus sets the status of a commit in a project. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit func (s *CommitsService) SetCommitStatus(pid interface{}, sha string, opt *SetCommitStatusOptions, options ...OptionFunc) (*CommitStatus, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/statuses/%s", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } cs := new(CommitStatus) resp, err := s.client.Do(req, &cs) if err != nil { return nil, resp, err } return cs, resp, err } // GetMergeRequestsByCommit gets merge request associated with a commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/commits.html#list-merge-requests-associated-with-a-commit func (s *CommitsService) GetMergeRequestsByCommit(pid interface{}, sha string, options ...OptionFunc) ([]*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/merge_requests", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var mrs []*MergeRequest resp, err := s.client.Do(req, &mrs) if err != nil { return nil, resp, err } return mrs, resp, err } // CherryPickCommitOptions represents the available CherryPickCommit() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit type CherryPickCommitOptions struct { Branch *string `url:"branch,omitempty" json:"branch,omitempty"` } // CherryPickCommit cherry picks a commit to a given branch. // // GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit func (s *CommitsService) CherryPickCommit(pid interface{}, sha string, opt *CherryPickCommitOptions, options ...OptionFunc) (*Commit, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/cherry_pick", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } c := new(Commit) resp, err := s.client.Do(req, &c) if err != nil { return nil, resp, err } return c, resp, err } // RevertCommitOptions represents the available RevertCommit() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#revert-a-commit type RevertCommitOptions struct { Branch *string `url:"branch,omitempty" json:"branch,omitempty"` } // RevertCommit reverts a commit in a given branch. // // GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#revert-a-commit func (s *CommitsService) RevertCommit(pid interface{}, sha string, opt *RevertCommitOptions, options ...OptionFunc) (*Commit, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/revert", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } c := new(Commit) resp, err := s.client.Do(req, &c) if err != nil { return nil, resp, err } return c, resp, err } // GPGSignature represents a Gitlab commit's GPG Signature. // // GitLab API docs: // https://docs.gitlab.com/ee/api/commits.html#get-gpg-signature-of-a-commit type GPGSignature struct { KeyID int `json:"gpg_key_id"` KeyPrimaryKeyID string `json:"gpg_key_primary_keyid"` KeyUserName string `json:"gpg_key_user_name"` KeyUserEmail string `json:"gpg_key_user_email"` VerificationStatus string `json:"verification_status"` KeySubkeyID int `json:"gpg_key_subkey_id"` } // GetGPGSiganature gets a GPG signature of a commit. // // GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#get-gpg-signature-of-a-commit func (s *CommitsService) GetGPGSiganature(pid interface{}, sha string, options ...OptionFunc) (*GPGSignature, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/signature", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } sig := new(GPGSignature) resp, err := s.client.Do(req, &sig) if err != nil { return nil, resp, err } return sig, resp, err } golang-github-xanzy-go-gitlab-0.22.2/commits_test.go000066400000000000000000000164341357140411500224100ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" "time" "github.com/stretchr/testify/assert" ) var testRevertCommitTargetBranch = "release" func TestGetCommit(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/commits/b0b3a907f41409829b307a28b82fdbd552ee5a27", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/get_commit.json") }) commit, resp, err := client.Commits.GetCommit("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", nil) if err != nil { t.Fatalf("Commits.GetCommit returned error: %v, response: %v", err, resp) } updatedAt := time.Date(2019, 11, 4, 15, 39, 03, 935000000, time.UTC) createdAt := time.Date(2019, 11, 4, 15, 38, 53, 154000000, time.UTC) want := &Commit{ ID: "6104942438c14ec7bd21c6cd5bd995272b3faff6", ShortID: "6104942438c", Title: "Sanitize for network graph", AuthorName: "randx", AuthorEmail: "dmitriy.zaporozhets@gmail.com", CommitterName: "Dmitriy", CommitterEmail: "dmitriy.zaporozhets@gmail.com", Message: "Sanitize for network graph", ParentIDs: []string{"ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"}, Stats: &CommitStats{Additions: 15, Deletions: 10, Total: 25}, Status: BuildState(Running), LastPipeline: &PipelineInfo{ ID: 8, Ref: "master", SHA: "2dc6aa325a317eda67812f05600bdf0fcdc70ab0", Status: "created", WebURL: "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/54268416", UpdatedAt: &updatedAt, CreatedAt: &createdAt, }, ProjectID: 13083, } assert.Equal(t, want, commit) } func TestGetCommitStatuses(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/commits/b0b3a907f41409829b307a28b82fdbd552ee5a27/statuses", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1}]`) }) opt := &GetCommitStatusesOptions{Ref: String("master"), Stage: String("test"), Name: String("ci/jenkins"), All: Bool(true)} statuses, _, err := client.Commits.GetCommitStatuses("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", opt) if err != nil { t.Errorf("Commits.GetCommitStatuses returned error: %v", err) } want := []*CommitStatus{{ID: 1}} if !reflect.DeepEqual(want, statuses) { t.Errorf("Commits.GetCommitStatuses returned %+v, want %+v", statuses, want) } } func TestSetCommitStatus(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/statuses/b0b3a907f41409829b307a28b82fdbd552ee5a27", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1}`) }) opt := &SetCommitStatusOptions{State: Running, Ref: String("master"), Name: String("ci/jenkins"), Context: String(""), TargetURL: String("http://abc"), Description: String("build")} status, _, err := client.Commits.SetCommitStatus("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", opt) if err != nil { t.Errorf("Commits.SetCommitStatus returned error: %v", err) } want := &CommitStatus{ID: 1} if !reflect.DeepEqual(want, status) { t.Errorf("Commits.SetCommitStatus returned %+v, want %+v", status, want) } } func TestRevertCommit_NoOptions(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/commits/b0b3a907f41409829b307a28b82fdbd552ee5a27/revert", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") mustWriteHTTPResponse(t, w, "testdata/get_commit.json") }) commit, resp, err := client.Commits.RevertCommit("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", nil) if err != nil { t.Fatalf("Commits.RevertCommit returned error: %v, response: %v", err, resp) } updatedAt := time.Date(2019, 11, 4, 15, 39, 03, 935000000, time.UTC) createdAt := time.Date(2019, 11, 4, 15, 38, 53, 154000000, time.UTC) want := &Commit{ ID: "6104942438c14ec7bd21c6cd5bd995272b3faff6", ShortID: "6104942438c", Title: "Sanitize for network graph", AuthorName: "randx", AuthorEmail: "dmitriy.zaporozhets@gmail.com", CommitterName: "Dmitriy", CommitterEmail: "dmitriy.zaporozhets@gmail.com", Message: "Sanitize for network graph", ParentIDs: []string{"ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"}, Stats: &CommitStats{Additions: 15, Deletions: 10, Total: 25}, Status: BuildState(Running), LastPipeline: &PipelineInfo{ ID: 8, Ref: "master", SHA: "2dc6aa325a317eda67812f05600bdf0fcdc70ab0", Status: "created", WebURL: "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/54268416", UpdatedAt: &updatedAt, CreatedAt: &createdAt, }, ProjectID: 13083, } assert.Equal(t, want, commit) } func TestRevertCommit_WithOptions(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/commits/b0b3a907f41409829b307a28b82fdbd552ee5a27/revert", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") testBody(t, r, `{"branch":"release"}`) mustWriteHTTPResponse(t, w, "testdata/get_commit.json") }) commit, resp, err := client.Commits.RevertCommit("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", &RevertCommitOptions{ Branch: &testRevertCommitTargetBranch, }) if err != nil { t.Fatalf("Commits.RevertCommit returned error: %v, response: %v", err, resp) } updatedAt := time.Date(2019, 11, 4, 15, 39, 03, 935000000, time.UTC) createdAt := time.Date(2019, 11, 4, 15, 38, 53, 154000000, time.UTC) want := &Commit{ ID: "6104942438c14ec7bd21c6cd5bd995272b3faff6", ShortID: "6104942438c", Title: "Sanitize for network graph", AuthorName: "randx", AuthorEmail: "dmitriy.zaporozhets@gmail.com", CommitterName: "Dmitriy", CommitterEmail: "dmitriy.zaporozhets@gmail.com", Message: "Sanitize for network graph", ParentIDs: []string{"ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"}, Stats: &CommitStats{Additions: 15, Deletions: 10, Total: 25}, Status: BuildState(Running), LastPipeline: &PipelineInfo{ ID: 8, Ref: "master", SHA: "2dc6aa325a317eda67812f05600bdf0fcdc70ab0", Status: "created", WebURL: "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/54268416", UpdatedAt: &updatedAt, CreatedAt: &createdAt, }, ProjectID: 13083, } assert.Equal(t, want, commit) } func TestGetGPGSignature(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/commits/b0b3a907f41409829b307a28b82fdbd552ee5a27/signature", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/get_signature.json") }) sig, resp, err := client.Commits.GetGPGSiganature("1", "b0b3a907f41409829b307a28b82fdbd552ee5a27", nil) if err != nil { t.Fatalf("Commits.GetGPGSignature returned error: %v, response: %v", err, resp) } want := &GPGSignature{ KeyID: 7977, KeyPrimaryKeyID: "627C5F589F467F17", KeyUserName: "Dmitriy Zaporozhets", KeyUserEmail: "dmitriy.zaporozhets@gmail.com", VerificationStatus: "verified", KeySubkeyID: 0, } assert.Equal(t, want, sig) } golang-github-xanzy-go-gitlab-0.22.2/custom_attributes.go000066400000000000000000000153551357140411500234570ustar00rootroot00000000000000package gitlab import ( "fmt" ) // CustomAttributesService handles communication with the group, project and // user custom attributes related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html type CustomAttributesService struct { client *Client } // CustomAttribute struct is used to unmarshal response to api calls. // // GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html type CustomAttribute struct { Key string `json:"key"` Value string `json:"value"` } // ListCustomUserAttributes lists the custom attributes of the specified user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes func (s *CustomAttributesService) ListCustomUserAttributes(user int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) { return s.listCustomAttributes("users", user, options...) } // ListCustomGroupAttributes lists the custom attributes of the specified group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes func (s *CustomAttributesService) ListCustomGroupAttributes(group int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) { return s.listCustomAttributes("groups", group, options...) } // ListCustomProjectAttributes lists the custom attributes of the specified project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes func (s *CustomAttributesService) ListCustomProjectAttributes(project int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) { return s.listCustomAttributes("projects", project, options...) } func (s *CustomAttributesService) listCustomAttributes(resource string, id int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) { u := fmt.Sprintf("%s/%d/custom_attributes", resource, id) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var cas []*CustomAttribute resp, err := s.client.Do(req, &cas) if err != nil { return nil, resp, err } return cas, resp, err } // GetCustomUserAttribute returns the user attribute with a speciifc key. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute func (s *CustomAttributesService) GetCustomUserAttribute(user int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) { return s.getCustomAttribute("users", user, key, options...) } // GetCustomGroupAttribute returns the group attribute with a speciifc key. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute func (s *CustomAttributesService) GetCustomGroupAttribute(group int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) { return s.getCustomAttribute("groups", group, key, options...) } // GetCustomProjectAttribute returns the project attribute with a speciifc key. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute func (s *CustomAttributesService) GetCustomProjectAttribute(project int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) { return s.getCustomAttribute("projects", project, key, options...) } func (s *CustomAttributesService) getCustomAttribute(resource string, id int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) { u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var ca *CustomAttribute resp, err := s.client.Do(req, &ca) if err != nil { return nil, resp, err } return ca, resp, err } // SetCustomUserAttribute sets the custom attributes of the specified user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute func (s *CustomAttributesService) SetCustomUserAttribute(user int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) { return s.setCustomAttribute("users", user, c, options...) } // SetCustomGroupAttribute sets the custom attributes of the specified group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute func (s *CustomAttributesService) SetCustomGroupAttribute(group int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) { return s.setCustomAttribute("groups", group, c, options...) } // SetCustomProjectAttribute sets the custom attributes of the specified project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute func (s *CustomAttributesService) SetCustomProjectAttribute(project int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) { return s.setCustomAttribute("projects", project, c, options...) } func (s *CustomAttributesService) setCustomAttribute(resource string, id int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) { u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, c.Key) req, err := s.client.NewRequest("PUT", u, c, options) if err != nil { return nil, nil, err } ca := new(CustomAttribute) resp, err := s.client.Do(req, ca) if err != nil { return nil, resp, err } return ca, resp, err } // DeleteCustomUserAttribute removes the custom attribute of the specified user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute func (s *CustomAttributesService) DeleteCustomUserAttribute(user int, key string, options ...OptionFunc) (*Response, error) { return s.deleteCustomAttribute("users", user, key, options...) } // DeleteCustomGroupAttribute removes the custom attribute of the specified group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute func (s *CustomAttributesService) DeleteCustomGroupAttribute(group int, key string, options ...OptionFunc) (*Response, error) { return s.deleteCustomAttribute("groups", group, key, options...) } // DeleteCustomProjectAttribute removes the custom attribute of the specified project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute func (s *CustomAttributesService) DeleteCustomProjectAttribute(project int, key string, options ...OptionFunc) (*Response, error) { return s.deleteCustomAttribute("projects", project, key, options...) } func (s *CustomAttributesService) deleteCustomAttribute(resource string, id int, key string, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/custom_attributes_test.go000066400000000000000000000175661357140411500245240ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestListCustomUserAttributes(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/users/2/custom_attributes", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"key":"testkey1", "value":"testvalue1"}, {"key":"testkey2", "value":"testvalue2"}]`) }) customAttributes, _, err := client.CustomAttribute.ListCustomUserAttributes(2) if err != nil { t.Errorf("CustomAttribute.ListCustomUserAttributes returned error: %v", err) } want := []*CustomAttribute{{Key: "testkey1", Value: "testvalue1"}, {Key: "testkey2", Value: "testvalue2"}} if !reflect.DeepEqual(want, customAttributes) { t.Errorf("CustomAttribute.ListCustomUserAttributes returned %+v, want %+v", customAttributes, want) } } func TestListCustomGroupAttributes(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/2/custom_attributes", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"key":"testkey1", "value":"testvalue1"}, {"key":"testkey2", "value":"testvalue2"}]`) }) customAttributes, _, err := client.CustomAttribute.ListCustomGroupAttributes(2) if err != nil { t.Errorf("CustomAttribute.ListCustomGroupAttributes returned error: %v", err) } want := []*CustomAttribute{{Key: "testkey1", Value: "testvalue1"}, {Key: "testkey2", Value: "testvalue2"}} if !reflect.DeepEqual(want, customAttributes) { t.Errorf("CustomAttribute.ListCustomGroupAttributes returned %+v, want %+v", customAttributes, want) } } func TestListCustomProjectAttributes(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/2/custom_attributes", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"key":"testkey1", "value":"testvalue1"}, {"key":"testkey2", "value":"testvalue2"}]`) }) customAttributes, _, err := client.CustomAttribute.ListCustomProjectAttributes(2) if err != nil { t.Errorf("CustomAttribute.ListCustomProjectAttributes returned error: %v", err) } want := []*CustomAttribute{{Key: "testkey1", Value: "testvalue1"}, {Key: "testkey2", Value: "testvalue2"}} if !reflect.DeepEqual(want, customAttributes) { t.Errorf("CustomAttribute.ListCustomProjectAttributes returned %+v, want %+v", customAttributes, want) } } func TestGetCustomUserAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/users/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"key":"testkey1", "value":"testvalue1"}`) }) customAttribute, _, err := client.CustomAttribute.GetCustomUserAttribute(2, "testkey1") if err != nil { t.Errorf("CustomAttribute.GetCustomUserAttribute returned error: %v", err) } want := &CustomAttribute{Key: "testkey1", Value: "testvalue1"} if !reflect.DeepEqual(want, customAttribute) { t.Errorf("CustomAttribute.GetCustomUserAttribute returned %+v, want %+v", customAttribute, want) } } func TestGetCustomGropupAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"key":"testkey1", "value":"testvalue1"}`) }) customAttribute, _, err := client.CustomAttribute.GetCustomGroupAttribute(2, "testkey1") if err != nil { t.Errorf("CustomAttribute.GetCustomGroupAttribute returned error: %v", err) } want := &CustomAttribute{Key: "testkey1", Value: "testvalue1"} if !reflect.DeepEqual(want, customAttribute) { t.Errorf("CustomAttribute.GetCustomGroupAttribute returned %+v, want %+v", customAttribute, want) } } func TestGetCustomProjectAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"key":"testkey1", "value":"testvalue1"}`) }) customAttribute, _, err := client.CustomAttribute.GetCustomProjectAttribute(2, "testkey1") if err != nil { t.Errorf("CustomAttribute.GetCustomProjectAttribute returned error: %v", err) } want := &CustomAttribute{Key: "testkey1", Value: "testvalue1"} if !reflect.DeepEqual(want, customAttribute) { t.Errorf("CustomAttribute.GetCustomProjectAttribute returned %+v, want %+v", customAttribute, want) } } func TestSetCustomUserAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/users/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"key":"testkey1", "value":"testvalue1"}`) }) customAttribute, _, err := client.CustomAttribute.SetCustomUserAttribute(2, CustomAttribute{ Key: "testkey1", Value: "testvalue1", }) if err != nil { t.Errorf("CustomAttribute.SetCustomUserAttributes returned error: %v", err) } want := &CustomAttribute{Key: "testkey1", Value: "testvalue1"} if !reflect.DeepEqual(want, customAttribute) { t.Errorf("CustomAttribute.SetCustomUserAttributes returned %+v, want %+v", customAttribute, want) } } func TestSetCustomGroupAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"key":"testkey1", "value":"testvalue1"}`) }) customAttribute, _, err := client.CustomAttribute.SetCustomGroupAttribute(2, CustomAttribute{ Key: "testkey1", Value: "testvalue1", }) if err != nil { t.Errorf("CustomAttribute.SetCustomGroupAttributes returned error: %v", err) } want := &CustomAttribute{Key: "testkey1", Value: "testvalue1"} if !reflect.DeepEqual(want, customAttribute) { t.Errorf("CustomAttribute.SetCustomGroupAttributes returned %+v, want %+v", customAttribute, want) } } func TestDeleteCustomUserAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/users/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusAccepted) }) resp, err := client.CustomAttribute.DeleteCustomUserAttribute(2, "testkey1") if err != nil { t.Errorf("CustomAttribute.DeleteCustomUserAttribute returned error: %v", err) } want := http.StatusAccepted got := resp.StatusCode if got != want { t.Errorf("CustomAttribute.DeleteCustomUserAttribute returned %d, want %d", got, want) } } func TestDeleteCustomGroupAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusAccepted) }) resp, err := client.CustomAttribute.DeleteCustomGroupAttribute(2, "testkey1") if err != nil { t.Errorf("CustomAttribute.DeleteCustomGroupAttribute returned error: %v", err) } want := http.StatusAccepted got := resp.StatusCode if got != want { t.Errorf("CustomAttribute.DeleteCustomGroupAttribute returned %d, want %d", got, want) } } func TestDeleteCustomProjectAttribute(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/2/custom_attributes/testkey1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusAccepted) }) resp, err := client.CustomAttribute.DeleteCustomProjectAttribute(2, "testkey1") if err != nil { t.Errorf("CustomAttribute.DeleteCustomProjectAttribute returned error: %v", err) } want := http.StatusAccepted got := resp.StatusCode if got != want { t.Errorf("CustomAttribute.DeleteCustomProjectAttribute returned %d, want %d", got, want) } } golang-github-xanzy-go-gitlab-0.22.2/deploy_keys.go000066400000000000000000000130011357140411500222100ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // DeployKeysService handles communication with the keys related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/deploy_keys.html type DeployKeysService struct { client *Client } // DeployKey represents a GitLab deploy key. type DeployKey struct { ID int `json:"id"` Title string `json:"title"` Key string `json:"key"` CanPush *bool `json:"can_push"` CreatedAt *time.Time `json:"created_at"` } func (k DeployKey) String() string { return Stringify(k) } // ListAllDeployKeys gets a list of all deploy keys // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#list-all-deploy-keys func (s *DeployKeysService) ListAllDeployKeys(options ...OptionFunc) ([]*DeployKey, *Response, error) { req, err := s.client.NewRequest("GET", "deploy_keys", nil, options) if err != nil { return nil, nil, err } var ks []*DeployKey resp, err := s.client.Do(req, &ks) if err != nil { return nil, resp, err } return ks, resp, err } // ListProjectDeployKeysOptions represents the available ListProjectDeployKeys() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys type ListProjectDeployKeysOptions ListOptions // ListProjectDeployKeys gets a list of a project's deploy keys // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProjectDeployKeysOptions, options ...OptionFunc) ([]*DeployKey, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/deploy_keys", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ks []*DeployKey resp, err := s.client.Do(req, &ks) if err != nil { return nil, resp, err } return ks, resp, err } // GetDeployKey gets a single deploy key. // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#single-deploy-key func (s *DeployKeysService) GetDeployKey(pid interface{}, deployKey int, options ...OptionFunc) (*DeployKey, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/deploy_keys/%d", pathEscape(project), deployKey) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } k := new(DeployKey) resp, err := s.client.Do(req, k) if err != nil { return nil, resp, err } return k, resp, err } // AddDeployKeyOptions represents the available ADDDeployKey() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key type AddDeployKeyOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Key *string `url:"key,omitempty" json:"key,omitempty"` CanPush *bool `url:"can_push,omitempty" json:"can_push,omitempty"` } // AddDeployKey creates a new deploy key for a project. If deploy key already // exists in another project - it will be joined to project but only if // original one was is accessible by same user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key func (s *DeployKeysService) AddDeployKey(pid interface{}, opt *AddDeployKeyOptions, options ...OptionFunc) (*DeployKey, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/deploy_keys", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } k := new(DeployKey) resp, err := s.client.Do(req, k) if err != nil { return nil, resp, err } return k, resp, err } // DeleteDeployKey deletes a deploy key from a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#delete-deploy-key func (s *DeployKeysService) DeleteDeployKey(pid interface{}, deployKey int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/deploy_keys/%d", pathEscape(project), deployKey) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // EnableDeployKey enables a deploy key. // // GitLab API docs: // https://docs.gitlab.com/ce/api/deploy_keys.html#enable-deploy-key func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, options ...OptionFunc) (*DeployKey, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/deploy_keys/%d/enable", pathEscape(project), deployKey) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } k := new(DeployKey) resp, err := s.client.Do(req, k) if err != nil { return nil, resp, err } return k, resp, err } golang-github-xanzy-go-gitlab-0.22.2/deployments.go000066400000000000000000000072501357140411500222350ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gitlab import ( "fmt" "time" ) // DeploymentsService handles communication with the deployment related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html type DeploymentsService struct { client *Client } // Deployment represents the Gitlab deployment type Deployment struct { ID int `json:"id"` IID int `json:"iid"` Ref string `json:"ref"` SHA string `json:"sha"` CreatedAt *time.Time `json:"created_at"` User *ProjectUser `json:"user"` Environment *Environment `json:"environment"` Deployable struct { ID int `json:"id"` Status string `json:"status"` Stage string `json:"stage"` Name string `json:"name"` Ref string `json:"ref"` Tag bool `json:"tag"` Coverage float64 `json:"coverage"` CreatedAt *time.Time `json:"created_at"` StartedAt *time.Time `json:"started_at"` FinishedAt *time.Time `json:"finished_at"` Duration float64 `json:"duration"` User *User `json:"user"` Commit *Commit `json:"commit"` Pipeline struct { ID int `json:"id"` SHA string `json:"sha"` Ref string `json:"ref"` Status string `json:"status"` } `json:"pipeline"` Runner *Runner `json:"runner"` } `json:"deployable"` } // ListProjectDeploymentsOptions represents the available ListProjectDeployments() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments type ListProjectDeploymentsOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListProjectDeployments gets a list of deployments in a project. // // GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments func (s *DeploymentsService) ListProjectDeployments(pid interface{}, opts *ListProjectDeploymentsOptions, options ...OptionFunc) ([]*Deployment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/deployments", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opts, options) if err != nil { return nil, nil, err } var ds []*Deployment resp, err := s.client.Do(req, &ds) if err != nil { return nil, resp, err } return ds, resp, err } // GetProjectDeployment get a deployment for a project. // // GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#get-a-specific-deployment func (s *DeploymentsService) GetProjectDeployment(pid interface{}, deployment int, options ...OptionFunc) (*Deployment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/deployments/%d", pathEscape(project), deployment) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } d := new(Deployment) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } golang-github-xanzy-go-gitlab-0.22.2/discussions.go000066400000000000000000001003101357140411500222270ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // DiscussionsService handles communication with the discussions related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/discussions.html type DiscussionsService struct { client *Client } // Discussion represents a GitLab discussion. // // GitLab API docs: https://docs.gitlab.com/ce/api/discussions.html type Discussion struct { ID string `json:"id"` IndividualNote bool `json:"individual_note"` Notes []*Note `json:"notes"` } func (d Discussion) String() string { return Stringify(d) } // ListIssueDiscussionsOptions represents the available ListIssueDiscussions() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-issue-discussion-items type ListIssueDiscussionsOptions ListOptions // ListIssueDiscussions gets a list of all discussions for a single // issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-issue-discussion-items func (s *DiscussionsService) ListIssueDiscussions(pid interface{}, issue int, opt *ListIssueDiscussionsOptions, options ...OptionFunc) ([]*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/discussions", pathEscape(project), issue) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ds []*Discussion resp, err := s.client.Do(req, &ds) if err != nil { return nil, resp, err } return ds, resp, err } // GetIssueDiscussion returns a single discussion for a specific project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#get-single-issue-discussion-item func (s *DiscussionsService) GetIssueDiscussion(pid interface{}, issue int, discussion string, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s", pathEscape(project), issue, discussion, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // CreateIssueDiscussionOptions represents the available CreateIssueDiscussion() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-issue-thread type CreateIssueDiscussionOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // CreateIssueDiscussion creates a new discussion to a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-issue-thread func (s *DiscussionsService) CreateIssueDiscussion(pid interface{}, issue int, opt *CreateIssueDiscussionOptions, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/discussions", pathEscape(project), issue) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // AddIssueDiscussionNoteOptions represents the available AddIssueDiscussionNote() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-issue-thread type AddIssueDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // AddIssueDiscussionNote creates a new discussion to a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-issue-thread func (s *DiscussionsService) AddIssueDiscussionNote(pid interface{}, issue int, discussion string, opt *AddIssueDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s/notes", pathEscape(project), issue, discussion, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateIssueDiscussionNoteOptions represents the available // UpdateIssueDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-issue-thread-note type UpdateIssueDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // UpdateIssueDiscussionNote modifies existing discussion of an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-issue-thread-note func (s *DiscussionsService) UpdateIssueDiscussionNote(pid interface{}, issue int, discussion string, note int, opt *UpdateIssueDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s/notes/%d", pathEscape(project), issue, discussion, note, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteIssueDiscussionNote deletes an existing discussion of an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#delete-an-issue-thread-note func (s *DiscussionsService) DeleteIssueDiscussionNote(pid interface{}, issue int, discussion string, note int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s/notes/%d", pathEscape(project), issue, discussion, note, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListSnippetDiscussionsOptions represents the available ListSnippetDiscussions() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-snippet-discussion-items type ListSnippetDiscussionsOptions ListOptions // ListSnippetDiscussions gets a list of all discussions for a single // snippet. Snippet discussions are comments users can post to a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-snippet-discussion-items func (s *DiscussionsService) ListSnippetDiscussions(pid interface{}, snippet int, opt *ListSnippetDiscussionsOptions, options ...OptionFunc) ([]*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/discussions", pathEscape(project), snippet) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ds []*Discussion resp, err := s.client.Do(req, &ds) if err != nil { return nil, resp, err } return ds, resp, err } // GetSnippetDiscussion returns a single discussion for a given snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#get-single-snippet-discussion-item func (s *DiscussionsService) GetSnippetDiscussion(pid interface{}, snippet int, discussion string, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s", pathEscape(project), snippet, discussion, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // CreateSnippetDiscussionOptions represents the available // CreateSnippetDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-snippet-thread type CreateSnippetDiscussionOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // CreateSnippetDiscussion creates a new discussion for a single snippet. // Snippet discussions are comments users can post to a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-snippet-thread func (s *DiscussionsService) CreateSnippetDiscussion(pid interface{}, snippet int, opt *CreateSnippetDiscussionOptions, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/discussions", pathEscape(project), snippet) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // AddSnippetDiscussionNoteOptions represents the available // AddSnippetDiscussionNote() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-snippet-thread type AddSnippetDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // AddSnippetDiscussionNote creates a new discussion to a single project // snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-snippet-thread func (s *DiscussionsService) AddSnippetDiscussionNote(pid interface{}, snippet int, discussion string, opt *AddSnippetDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s/notes", pathEscape(project), snippet, discussion, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateSnippetDiscussionNoteOptions represents the available // UpdateSnippetDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-snippet-thread-note type UpdateSnippetDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // UpdateSnippetDiscussionNote modifies existing discussion of a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-snippet-thread-note func (s *DiscussionsService) UpdateSnippetDiscussionNote(pid interface{}, snippet int, discussion string, note int, opt *UpdateSnippetDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s/notes/%d", pathEscape(project), snippet, discussion, note, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteSnippetDiscussionNote deletes an existing discussion of a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#delete-a-snippet-thread-note func (s *DiscussionsService) DeleteSnippetDiscussionNote(pid interface{}, snippet int, discussion string, note int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s/notes/%d", pathEscape(project), snippet, discussion, note, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListGroupEpicDiscussionsOptions represents the available // ListEpicDiscussions() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-group-epic-discussion-items type ListGroupEpicDiscussionsOptions ListOptions // ListGroupEpicDiscussions gets a list of all discussions for a single // epic. Epic discussions are comments users can post to a epic. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-group-epic-discussion-items func (s *DiscussionsService) ListGroupEpicDiscussions(gid interface{}, epic int, opt *ListGroupEpicDiscussionsOptions, options ...OptionFunc) ([]*Discussion, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/discussions", pathEscape(group), epic, ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ds []*Discussion resp, err := s.client.Do(req, &ds) if err != nil { return nil, resp, err } return ds, resp, err } // GetEpicDiscussion returns a single discussion for a given epic. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#get-single-epic-discussion-item func (s *DiscussionsService) GetEpicDiscussion(gid interface{}, epic int, discussion string, options ...OptionFunc) (*Discussion, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s", pathEscape(group), epic, discussion, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // CreateEpicDiscussionOptions represents the available CreateEpicDiscussion() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread type CreateEpicDiscussionOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // CreateEpicDiscussion creates a new discussion for a single epic. Epic // discussions are comments users can post to a epic. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread func (s *DiscussionsService) CreateEpicDiscussion(gid interface{}, epic int, opt *CreateEpicDiscussionOptions, options ...OptionFunc) (*Discussion, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/discussions", pathEscape(group), epic, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // AddEpicDiscussionNoteOptions represents the available // AddEpicDiscussionNote() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread type AddEpicDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // AddEpicDiscussionNote creates a new discussion to a single project epic. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread func (s *DiscussionsService) AddEpicDiscussionNote(gid interface{}, epic int, discussion string, opt *AddEpicDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s/notes", pathEscape(group), epic, discussion, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateEpicDiscussionNoteOptions represents the available UpdateEpicDiscussion() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-epic-thread-note type UpdateEpicDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // UpdateEpicDiscussionNote modifies existing discussion of a epic. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-epic-thread-note func (s *DiscussionsService) UpdateEpicDiscussionNote(gid interface{}, epic int, discussion string, note int, opt *UpdateEpicDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s/notes/%d", pathEscape(group), epic, discussion, note, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteEpicDiscussionNote deletes an existing discussion of a epic. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#delete-an-epic-thread-note func (s *DiscussionsService) DeleteEpicDiscussionNote(gid interface{}, epic int, discussion string, note int, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s/notes/%d", pathEscape(group), epic, discussion, note, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListMergeRequestDiscussionsOptions represents the available // ListMergeRequestDiscussions() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-merge-request-discussion-items type ListMergeRequestDiscussionsOptions ListOptions // ListMergeRequestDiscussions gets a list of all discussions for a single // merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-merge-request-discussion-items func (s *DiscussionsService) ListMergeRequestDiscussions(pid interface{}, mergeRequest int, opt *ListMergeRequestDiscussionsOptions, options ...OptionFunc) ([]*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions", pathEscape(project), mergeRequest, ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ds []*Discussion resp, err := s.client.Do(req, &ds) if err != nil { return nil, resp, err } return ds, resp, err } // GetMergeRequestDiscussion returns a single discussion for a given merge // request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#get-single-merge-request-discussion-item func (s *DiscussionsService) GetMergeRequestDiscussion(pid interface{}, mergeRequest int, discussion string, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s", pathEscape(project), mergeRequest, discussion, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // CreateMergeRequestDiscussionOptions represents the available // CreateMergeRequestDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-thread type CreateMergeRequestDiscussionOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` Position *NotePosition `url:"position,omitempty" json:"position,omitempty"` } // CreateMergeRequestDiscussion creates a new discussion for a single merge // request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-thread func (s *DiscussionsService) CreateMergeRequestDiscussion(pid interface{}, mergeRequest int, opt *CreateMergeRequestDiscussionOptions, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions", pathEscape(project), mergeRequest, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // ResolveMergeRequestDiscussionOptions represents the available // ResolveMergeRequestDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#resolve-a-merge-request-thread type ResolveMergeRequestDiscussionOptions struct { Resolved *bool `url:"resolved,omitempty" json:"resolved,omitempty"` } // ResolveMergeRequestDiscussion resolves/unresolves whole discussion of a merge // request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#resolve-a-merge-request-thread func (s *DiscussionsService) ResolveMergeRequestDiscussion(pid interface{}, mergeRequest int, discussion string, opt *ResolveMergeRequestDiscussionOptions, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s", pathEscape(project), mergeRequest, discussion, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // AddMergeRequestDiscussionNoteOptions represents the available // AddMergeRequestDiscussionNote() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-merge-request-discussion type AddMergeRequestDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // AddMergeRequestDiscussionNote creates a new discussion to a single project // merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-merge-request-discussion func (s *DiscussionsService) AddMergeRequestDiscussionNote(pid interface{}, mergeRequest int, discussion string, opt *AddMergeRequestDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s/notes", pathEscape(project), mergeRequest, discussion, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateMergeRequestDiscussionNoteOptions represents the available // UpdateMergeRequestDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-merge-request-discussion-note type UpdateMergeRequestDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` Resolved *bool `url:"resolved,omitempty" json:"resolved,omitempty"` } // UpdateMergeRequestDiscussionNote modifies existing discussion of a merge // request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-existing-merge-request-discussion-note func (s *DiscussionsService) UpdateMergeRequestDiscussionNote(pid interface{}, mergeRequest int, discussion string, note int, opt *UpdateMergeRequestDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s/notes/%d", pathEscape(project), mergeRequest, discussion, note, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteMergeRequestDiscussionNote deletes an existing discussion of a merge // request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#delete-a-merge-request-discussion-note func (s *DiscussionsService) DeleteMergeRequestDiscussionNote(pid interface{}, mergeRequest int, discussion string, note int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s/notes/%d", pathEscape(project), mergeRequest, discussion, note, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListCommitDiscussionsOptions represents the available // ListCommitDiscussions() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-commit-discussion-items type ListCommitDiscussionsOptions ListOptions // ListCommitDiscussions gets a list of all discussions for a single // commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#list-project-commit-discussion-items func (s *DiscussionsService) ListCommitDiscussions(pid interface{}, commit string, opt *ListCommitDiscussionsOptions, options ...OptionFunc) ([]*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions", pathEscape(project), commit, ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ds []*Discussion resp, err := s.client.Do(req, &ds) if err != nil { return nil, resp, err } return ds, resp, err } // GetCommitDiscussion returns a single discussion for a specific project // commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#get-single-commit-discussion-item func (s *DiscussionsService) GetCommitDiscussion(pid interface{}, commit string, discussion string, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s", pathEscape(project), commit, discussion, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // CreateCommitDiscussionOptions represents the available // CreateCommitDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-commit-thread type CreateCommitDiscussionOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` Position *NotePosition `url:"position,omitempty" json:"position,omitempty"` } // CreateCommitDiscussion creates a new discussion to a single project commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#create-new-commit-thread func (s *DiscussionsService) CreateCommitDiscussion(pid interface{}, commit string, opt *CreateCommitDiscussionOptions, options ...OptionFunc) (*Discussion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions", pathEscape(project), commit, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } d := new(Discussion) resp, err := s.client.Do(req, d) if err != nil { return nil, resp, err } return d, resp, err } // AddCommitDiscussionNoteOptions represents the available // AddCommitDiscussionNote() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-commit-thread type AddCommitDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // AddCommitDiscussionNote creates a new discussion to a single project commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-commit-thread func (s *DiscussionsService) AddCommitDiscussionNote(pid interface{}, commit string, discussion string, opt *AddCommitDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes", pathEscape(project), commit, discussion, ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateCommitDiscussionNoteOptions represents the available // UpdateCommitDiscussion() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-an-existing-commit-thread-note type UpdateCommitDiscussionNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // UpdateCommitDiscussionNote modifies existing discussion of an commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#modify-an-existing-commit-thread-note func (s *DiscussionsService) UpdateCommitDiscussionNote(pid interface{}, commit string, discussion string, note int, opt *UpdateCommitDiscussionNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes/%d", pathEscape(project), commit, discussion, note, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteCommitDiscussionNote deletes an existing discussion of an commit. // // GitLab API docs: // https://docs.gitlab.com/ce/api/discussions.html#delete-a-commit-thread-note func (s *DiscussionsService) DeleteCommitDiscussionNote(pid interface{}, commit string, discussion string, note int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes/%d", pathEscape(project), commit, discussion, note, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/environments.go000066400000000000000000000146421357140411500224240ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // EnvironmentsService handles communication with the environment related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/environments.html type EnvironmentsService struct { client *Client } // Environment represents a GitLab environment. // // GitLab API docs: https://docs.gitlab.com/ce/api/environments.html type Environment struct { ID int `json:"id"` Name string `json:"name"` Slug string `json:"slug"` State string `json:"state"` ExternalURL string `json:"external_url"` Project *Project `json:"project"` LastDeployment *Deployment `json:"last_deployment"` } func (env Environment) String() string { return Stringify(env) } // ListEnvironmentsOptions represents the available ListEnvironments() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/environments.html#list-environments type ListEnvironmentsOptions ListOptions // ListEnvironments gets a list of environments from a project, sorted by name // alphabetically. // // GitLab API docs: // https://docs.gitlab.com/ee/api/environments.html#list-environments func (s *EnvironmentsService) ListEnvironments(pid interface{}, opts *ListEnvironmentsOptions, options ...OptionFunc) ([]*Environment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/environments", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opts, options) if err != nil { return nil, nil, err } var envs []*Environment resp, err := s.client.Do(req, &envs) if err != nil { return nil, resp, err } return envs, resp, err } // GetEnvironment gets a specific environment from a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/environments.html#get-a-specific-environment func (s *EnvironmentsService) GetEnvironment(pid interface{}, environment int, options ...OptionFunc) (*Environment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } env := new(Environment) resp, err := s.client.Do(req, env) if err != nil { return nil, resp, err } return env, resp, err } // CreateEnvironmentOptions represents the available CreateEnvironment() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment type CreateEnvironmentOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` } // CreateEnvironment adds an environment to a project. This is an idempotent // method and can be called multiple times with the same parameters. Createing // an environment that is already a environment does not affect the // existing environmentship. // // GitLab API docs: // https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment func (s *EnvironmentsService) CreateEnvironment(pid interface{}, opt *CreateEnvironmentOptions, options ...OptionFunc) (*Environment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/environments", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } env := new(Environment) resp, err := s.client.Do(req, env) if err != nil { return nil, resp, err } return env, resp, err } // EditEnvironmentOptions represents the available EditEnvironment() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment type EditEnvironmentOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` } // EditEnvironment updates a project team environment to a specified access level.. // // GitLab API docs: // https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment func (s *EnvironmentsService) EditEnvironment(pid interface{}, environment int, opt *EditEnvironmentOptions, options ...OptionFunc) (*Environment, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } env := new(Environment) resp, err := s.client.Do(req, env) if err != nil { return nil, resp, err } return env, resp, err } // DeleteEnvironment removes an environment from a project team. // // GitLab API docs: // https://docs.gitlab.com/ce/api/environments.html#remove-a-environment-from-a-group-or-project func (s *EnvironmentsService) DeleteEnvironment(pid interface{}, environment int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // StopEnvironment stop an environment from a project team. // // GitLab API docs: // https://docs.gitlab.com/ce/api/environments.html#stop-an-environment func (s *EnvironmentsService) StopEnvironment(pid interface{}, environmentID int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/environments/%d/stop", pathEscape(project), environmentID) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/environments_test.go000066400000000000000000000133421357140411500234570ustar00rootroot00000000000000package gitlab import ( "encoding/json" "fmt" "log" "net/http" "reflect" "testing" "github.com/stretchr/testify/assert" ) func TestListEnvironments(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/environments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/projects/1/environments?page=1&per_page=10") fmt.Fprint(w, `[{"id": 1,"name": "review/fix-foo", "slug": "review-fix-foo-dfjre3", "external_url": "https://review-fix-foo-dfjre3.example.gitlab.com"}]`) }) envs, _, err := client.Environments.ListEnvironments(1, &ListEnvironmentsOptions{Page: 1, PerPage: 10}) if err != nil { log.Fatal(err) } want := []*Environment{{ID: 1, Name: "review/fix-foo", Slug: "review-fix-foo-dfjre3", ExternalURL: "https://review-fix-foo-dfjre3.example.gitlab.com"}} if !reflect.DeepEqual(want, envs) { t.Errorf("Environments.ListEnvironments returned %+v, want %+v", envs, want) } } func TestGetEnvironment(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/environments/5949167", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1,"name":"test/test"}`) }) env, _, err := client.Environments.GetEnvironment(1, 5949167) if err != nil { t.Errorf("Environemtns.GetEnvironment returned error: %v", err) } want := &Environment{ID: 1, Name: "test/test"} if !reflect.DeepEqual(want, env) { t.Errorf("Environments.GetEnvironment returned %+v, want %+v", env, want) } } func TestCreateEnvironment(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/environments", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") testURL(t, r, "/api/v4/projects/1/environments") fmt.Fprint(w, `{"id": 1,"name": "deploy", "slug": "deploy", "external_url": "https://deploy.example.gitlab.com"}`) }) envs, _, err := client.Environments.CreateEnvironment(1, &CreateEnvironmentOptions{Name: String("deploy"), ExternalURL: String("https://deploy.example.gitlab.com")}) if err != nil { log.Fatal(err) } want := &Environment{ID: 1, Name: "deploy", Slug: "deploy", ExternalURL: "https://deploy.example.gitlab.com"} if !reflect.DeepEqual(want, envs) { t.Errorf("Environments.CreateEnvironment returned %+v, want %+v", envs, want) } } func TestEditEnvironment(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/environments/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testURL(t, r, "/api/v4/projects/1/environments/1") fmt.Fprint(w, `{"id": 1,"name": "staging", "slug": "staging", "external_url": "https://staging.example.gitlab.com"}`) }) envs, _, err := client.Environments.EditEnvironment(1, 1, &EditEnvironmentOptions{Name: String("staging"), ExternalURL: String("https://staging.example.gitlab.com")}) if err != nil { log.Fatal(err) } want := &Environment{ID: 1, Name: "staging", Slug: "staging", ExternalURL: "https://staging.example.gitlab.com"} if !reflect.DeepEqual(want, envs) { t.Errorf("Environments.EditEnvironment returned %+v, want %+v", envs, want) } } func TestDeleteEnvironment(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/environments/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") testURL(t, r, "/api/v4/projects/1/environments/1") }) _, err := client.Environments.DeleteEnvironment(1, 1) if err != nil { log.Fatal(err) } } func TestStopEnvironment(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/environments/1/stop", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") testURL(t, r, "/api/v4/projects/1/environments/1/stop") }) _, err := client.Environments.StopEnvironment(1, 1) if err != nil { log.Fatal(err) } } func TestUnmarshal(t *testing.T) { jsonObject := ` { "id": 10, "name": "production", "slug": "production", "external_url": "https://example.com", "project": { "id": 1, "description": "", "name": "Awesome Project", "name_with_namespace": "FooBar Group / Awesome Project", "path": "awesome-project", "path_with_namespace": "foobar-group/awesome-project", "created_at": "2017-09-30T11:10:08.476-04:00", "default_branch": "develop", "tag_list": [], "ssh_url_to_repo": "git@example.gitlab.com:foobar-group/api.git", "http_url_to_repo": "https://example.gitlab.com/foobar-group/api.git", "web_url": "https://example.gitlab.com/foobar-group/api", "readme_url": null, "avatar_url": null, "star_count": 0, "forks_count": 1, "last_activity_at": "2019-11-03T22:22:46.564-05:00", "namespace": { "id": 15, "name": "FooBar Group", "path": "foobar-group", "kind": "group", "full_path": "foobar-group", "parent_id": null, "avatar_url": null, "web_url": "https://example.gitlab.com/groups/foobar-group" } }, "state": "available" }` var env Environment err := json.Unmarshal([]byte(jsonObject), &env) if assert.NoError(t, err) { assert.Equal(t, 10, env.ID) assert.Equal(t, "production", env.Name) assert.Equal(t, "https://example.com", env.ExternalURL) assert.Equal(t, "available", env.State) if assert.NotNil(t, env.Project) { assert.Equal(t, "Awesome Project", env.Project.Name) } } }golang-github-xanzy-go-gitlab-0.22.2/epics.go000066400000000000000000000162051357140411500207750ustar00rootroot00000000000000package gitlab import ( "fmt" "time" ) // EpicsService handles communication with the epic related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html type EpicsService struct { client *Client } // EpicAuthor represents a author of the epic. type EpicAuthor struct { ID int `json:"id"` State string `json:"state"` WebURL string `json:"web_url"` Name string `json:"name"` AvatarURL string `json:"avatar_url"` Username string `json:"username"` } // Epic represents a GitLab epic. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html type Epic struct { ID int `json:"id"` IID int `json:"iid"` GroupID int `json:"group_id"` Author *EpicAuthor `json:"author"` Description string `json:"description"` State string `json:"state"` Upvotes int `json:"upvotes"` Downvotes int `json:"downvotes"` Labels []string `json:"labels"` Title string `json:"title"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` UserNotesCount int `json:"user_notes_count"` StartDate *ISOTime `json:"start_date"` StartDateIsFixed bool `json:"start_date_is_fixed"` StartDateFixed *ISOTime `json:"start_date_fixed"` StartDateFromMilestones *ISOTime `json:"start_date_from_milestones"` DueDate *ISOTime `json:"due_date"` DueDateIsFixed bool `json:"due_date_is_fixed"` DueDateFixed *ISOTime `json:"due_date_fixed"` DueDateFromMilestones *ISOTime `json:"due_date_from_milestones"` } func (e Epic) String() string { return Stringify(e) } // ListGroupEpicsOptions represents the available ListGroupEpics() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group type ListGroupEpicsOptions struct { ListOptions State *string `url:"state,omitempty" json:"state,omitempty"` Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` } // ListGroupEpics gets a list of group epics. This function accepts pagination // parameters page and per_page to return the list of group epics. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group func (s *EpicsService) ListGroupEpics(gid interface{}, opt *ListGroupEpicsOptions, options ...OptionFunc) ([]*Epic, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var es []*Epic resp, err := s.client.Do(req, &es) if err != nil { return nil, resp, err } return es, resp, err } // GetEpic gets a single group epic. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#single-epic func (s *EpicsService) GetEpic(gid interface{}, epic int, options ...OptionFunc) (*Epic, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } e := new(Epic) resp, err := s.client.Do(req, e) if err != nil { return nil, resp, err } return e, resp, err } // CreateEpicOptions represents the available CreateEpic() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic type CreateEpicOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` StartDateIsFixed *bool `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"` StartDateFixed *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"` DueDateIsFixed *bool `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"` DueDateFixed *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"` } // CreateEpic creates a new group epic. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic func (s *EpicsService) CreateEpic(gid interface{}, opt *CreateEpicOptions, options ...OptionFunc) (*Epic, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics", pathEscape(group)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } e := new(Epic) resp, err := s.client.Do(req, e) if err != nil { return nil, resp, err } return e, resp, err } // UpdateEpicOptions represents the available UpdateEpic() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic type UpdateEpicOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` StartDateIsFixed *bool `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"` StartDateFixed *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"` DueDateIsFixed *bool `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"` DueDateFixed *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"` StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` } // UpdateEpic updates an existing group epic. This function is also used // to mark an epic as closed. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic func (s *EpicsService) UpdateEpic(gid interface{}, epic int, opt *UpdateEpicOptions, options ...OptionFunc) (*Epic, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } e := new(Epic) resp, err := s.client.Do(req, e) if err != nil { return nil, resp, err } return e, resp, err } // DeleteEpic deletes a single group epic. // // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#delete-epic func (s *EpicsService) DeleteEpic(gid interface{}, epic int, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/epics_test.go000066400000000000000000000071771357140411500220440ustar00rootroot00000000000000package gitlab import ( "fmt" "log" "net/http" "reflect" "testing" ) func TestGetEpic(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/7/epics/8", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":8, "title": "Incredible idea", "description": "This is a test epic", "author" : {"id" : 26, "name": "jramsay"}}`) }) epic, _, err := client.Epics.GetEpic("7", 8) if err != nil { log.Fatal(err) } want := &Epic{ ID: 8, Title: "Incredible idea", Description: "This is a test epic", Author: &EpicAuthor{ID: 26, Name: "jramsay"}, } if !reflect.DeepEqual(want, epic) { t.Errorf("Epics.GetEpic returned %+v, want %+v", epic, want) } } func TestDeleteEpic(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/7/epics/8", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) _, err := client.Epics.DeleteEpic("7", 8) if err != nil { log.Fatal(err) } } func TestListGroupEpics(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/7/epics", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/groups/7/epics?author_id=26&state=opened") fmt.Fprint(w, `[{"id":8, "title": "Incredible idea", "description": "This is a test epic", "author" : {"id" : 26, "name": "jramsay"}}]`) }) listGroupEpics := &ListGroupEpicsOptions{ AuthorID: Int(26), State: String("opened"), } epics, _, err := client.Epics.ListGroupEpics("7", listGroupEpics) if err != nil { log.Fatal(err) } want := []*Epic{{ ID: 8, Title: "Incredible idea", Description: "This is a test epic", Author: &EpicAuthor{ID: 26, Name: "jramsay"}, }} if !reflect.DeepEqual(want, epics) { t.Errorf("Epics.ListGroupEpics returned %+v, want %+v", epics, want) } } func TestCreateEpic(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/7/epics", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":8, "title": "Incredible idea", "description": "This is a test epic", "author" : {"id" : 26, "name": "jramsay"}}`) }) createEpicOptions := &CreateEpicOptions{ Title: String("Incredible idea"), Description: String("This is a test epic"), } epic, _, err := client.Epics.CreateEpic("7", createEpicOptions) if err != nil { log.Fatal(err) } want := &Epic{ ID: 8, Title: "Incredible idea", Description: "This is a test epic", Author: &EpicAuthor{ID: 26, Name: "jramsay"}, } if !reflect.DeepEqual(want, epic) { t.Errorf("Epics.CreateEpic returned %+v, want %+v", epic, want) } } func TestUpdateEpic(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/7/epics/8", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"id":8, "title": "Incredible idea", "description": "This is a test epic", "author" : {"id" : 26, "name": "jramsay"}}`) }) updateEpicOptions := &UpdateEpicOptions{ Title: String("Incredible idea"), Description: String("This is a test epic"), } epic, _, err := client.Epics.UpdateEpic("7", 8, updateEpicOptions) if err != nil { log.Fatal(err) } want := &Epic{ ID: 8, Title: "Incredible idea", Description: "This is a test epic", Author: &EpicAuthor{ID: 26, Name: "jramsay"}, } if !reflect.DeepEqual(want, epic) { t.Errorf("Epics.UpdateEpic returned %+v, want %+v", epic, want) } } golang-github-xanzy-go-gitlab-0.22.2/event_parsing.go000066400000000000000000000061111357140411500225310ustar00rootroot00000000000000package gitlab import ( "encoding/json" "fmt" "net/http" ) // EventType represents a Gitlab event type. type EventType string // List of available event types. const ( EventTypeBuild EventType = "Build Hook" EventTypeIssue EventType = "Issue Hook" EventTypeJob EventType = "Job Hook" EventTypeMergeRequest EventType = "Merge Request Hook" EventTypeNote EventType = "Note Hook" EventTypePipeline EventType = "Pipeline Hook" EventTypePush EventType = "Push Hook" EventTypeTagPush EventType = "Tag Push Hook" EventTypeWikiPage EventType = "Wiki Page Hook" ) const ( noteableTypeCommit = "Commit" noteableTypeMergeRequest = "MergeRequest" noteableTypeIssue = "Issue" noteableTypeSnippet = "Snippet" ) type noteEvent struct { ObjectKind string `json:"object_kind"` ObjectAttributes struct { NoteableType string `json:"noteable_type"` } `json:"object_attributes"` } const eventTypeHeader = "X-Gitlab-Event" // WebhookEventType returns the event type for the given request. func WebhookEventType(r *http.Request) EventType { return EventType(r.Header.Get(eventTypeHeader)) } // ParseWebhook parses the event payload. For recognized event types, a // value of the corresponding struct type will be returned. An error will // be returned for unrecognized event types. // // Example usage: // // func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // payload, err := ioutil.ReadAll(r.Body) // if err != nil { ... } // event, err := gitlab.ParseWebhook(gitlab.WebhookEventType(r), payload) // if err != nil { ... } // switch event := event.(type) { // case *gitlab.PushEvent: // processPushEvent(event) // case *gitlab.MergeEvent: // processMergeEvent(event) // ... // } // } // func ParseWebhook(eventType EventType, payload []byte) (event interface{}, err error) { switch eventType { case EventTypeBuild: event = &BuildEvent{} case EventTypeIssue: event = &IssueEvent{} case EventTypeJob: event = &JobEvent{} case EventTypeMergeRequest: event = &MergeEvent{} case EventTypePipeline: event = &PipelineEvent{} case EventTypePush: event = &PushEvent{} case EventTypeTagPush: event = &TagEvent{} case EventTypeWikiPage: event = &WikiPageEvent{} case EventTypeNote: note := ¬eEvent{} err := json.Unmarshal(payload, note) if err != nil { return nil, err } if note.ObjectKind != "note" { return nil, fmt.Errorf("unexpected object kind %s", note.ObjectKind) } switch note.ObjectAttributes.NoteableType { case noteableTypeCommit: event = &CommitCommentEvent{} case noteableTypeMergeRequest: event = &MergeCommentEvent{} case noteableTypeIssue: event = &IssueCommentEvent{} case noteableTypeSnippet: event = &SnippetCommentEvent{} default: return nil, fmt.Errorf("unexpected noteable type %s", note.ObjectAttributes.NoteableType) } default: return nil, fmt.Errorf("unexpected event type: %s", eventType) } if err := json.Unmarshal(payload, event); err != nil { return nil, err } return event, nil } golang-github-xanzy-go-gitlab-0.22.2/event_parsing_test.go000066400000000000000000001176031357140411500236010ustar00rootroot00000000000000package gitlab import ( "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestWebhookEventType(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "https://gitlab.com", nil) if err != nil { t.Errorf("Error creating HTTP request: %s", err) } req.Header.Set("X-Gitlab-Event", "Push Hook") eventType := WebhookEventType(req) if eventType != "Push Hook" { t.Errorf("WebhookEventType is %s, want %s", eventType, "Push Hook") } } func TestParsePushHook(t *testing.T) { raw := `{ "object_kind": "push", "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "ref": "refs/heads/master", "checkout_sha": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "user_id": 4, "user_name": "John Smith", "user_username": "jsmith", "user_email": "john@example.com", "user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80", "project_id": 15, "project":{ "id": 15, "name":"Diaspora", "description":"", "web_url":"http://example.com/mike/diaspora", "avatar_url":null, "git_ssh_url":"git@example.com:mike/diaspora.git", "git_http_url":"http://example.com/mike/diaspora.git", "namespace":"Mike", "visibility_level":0, "path_with_namespace":"mike/diaspora", "default_branch":"master", "homepage":"http://example.com/mike/diaspora", "url":"git@example.com:mike/diaspora.git", "ssh_url":"git@example.com:mike/diaspora.git", "http_url":"http://example.com/mike/diaspora.git" }, "repository":{ "name": "Diaspora", "url": "git@example.com:mike/diaspora.git", "description": "", "homepage": "http://example.com/mike/diaspora", "git_http_url":"http://example.com/mike/diaspora.git", "git_ssh_url":"git@example.com:mike/diaspora.git", "visibility_level":0 }, "commits": [ { "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", "message": "Update Catalan translation to e38cb41.", "timestamp": "2011-12-12T14:27:31+02:00", "url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", "author": { "name": "Jordi Mallach", "email": "jordi@softcatala.org" }, "added": ["CHANGELOG"], "modified": ["app/controller/application.rb"], "removed": [] }, { "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "message": "fixed readme", "timestamp": "2012-01-03T23:36:29+02:00", "url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "author": { "name": "GitLab dev user", "email": "gitlabdev@dv6700.(none)" }, "added": ["CHANGELOG"], "modified": ["app/controller/application.rb"], "removed": [] } ], "total_commits_count": 4 }` parsedEvent, err := ParseWebhook("Push Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing push hook: %s", err) } event, ok := parsedEvent.(*PushEvent) if !ok { t.Errorf("Expected PushEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "push" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "push") } if event.ProjectID != 15 { t.Errorf("ProjectID is %v, want %v", event.ProjectID, 15) } if event.UserName != "John Smith" { t.Errorf("Username is %s, want %s", event.UserName, "John Smith") } if event.Commits[0] == nil || event.Commits[0].Timestamp == nil { t.Errorf("Commit Timestamp isn't nil") } if event.Commits[0] == nil || event.Commits[0].Author.Name != "Jordi Mallach" { t.Errorf("Commit Username is %s, want %s", event.UserName, "Jordi Mallach") } } func TestParseTagHook(t *testing.T) { raw := `{ "object_kind": "tag_push", "before": "0000000000000000000000000000000000000000", "after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7", "ref": "refs/tags/v1.0.0", "checkout_sha": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7", "user_id": 1, "user_name": "John Smith", "user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80", "project_id": 1, "project":{ "id": 1, "name":"Example", "description":"", "web_url":"http://example.com/jsmith/example", "avatar_url":null, "git_ssh_url":"git@example.com:jsmith/example.git", "git_http_url":"http://example.com/jsmith/example.git", "namespace":"Jsmith", "visibility_level":0, "path_with_namespace":"jsmith/example", "default_branch":"master", "homepage":"http://example.com/jsmith/example", "url":"git@example.com:jsmith/example.git", "ssh_url":"git@example.com:jsmith/example.git", "http_url":"http://example.com/jsmith/example.git" }, "repository":{ "name": "Example", "url": "ssh://git@example.com/jsmith/example.git", "description": "", "homepage": "http://example.com/jsmith/example", "git_http_url":"http://example.com/jsmith/example.git", "git_ssh_url":"git@example.com:jsmith/example.git", "visibility_level":0 }, "commits": [], "total_commits_count": 0 }` parsedEvent, err := ParseWebhook("Tag Push Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing tag hook: %s", err) } event, ok := parsedEvent.(*TagEvent) if !ok { t.Errorf("Expected TagEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "tag_push" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "tag_push") } if event.ProjectID != 1 { t.Errorf("ProjectID is %v, want %v", event.ProjectID, 1) } if event.UserName != "John Smith" { t.Errorf("Username is %s, want %s", event.UserName, "John Smith") } if event.Ref != "refs/tags/v1.0.0" { t.Errorf("Ref is %s, want %s", event.Ref, "refs/tags/v1.0.0") } } func TestParseIssueHook(t *testing.T) { raw := `{ "object_kind": "issue", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "project": { "id": 1, "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlabhq/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "git_http_url":"http://example.com/gitlabhq/gitlab-test.git", "namespace":"GitlabHQ", "visibility_level":20, "path_with_namespace":"gitlabhq/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"http://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "http_url":"http://example.com/gitlabhq/gitlab-test.git" }, "repository": { "name": "Gitlab Test", "url": "http://example.com/gitlabhq/gitlab-test.git", "description": "Aut reprehenderit ut est.", "homepage": "http://example.com/gitlabhq/gitlab-test" }, "object_attributes": { "id": 301, "title": "New API: create/update/delete file", "assignee_ids": [51], "assignee_id": 51, "author_id": 51, "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "position": 0, "branch_name": null, "description": "Create new API for manipulations with repository", "milestone_id": null, "state": "opened", "iid": 23, "url": "http://example.com/diaspora/issues/23", "action": "open" }, "assignees": [{ "name": "User1", "username": "user1", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }], "assignee": { "name": "User1", "username": "user1", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "labels": [{ "id": 206, "title": "API", "color": "#ffffff", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "API related issues", "type": "ProjectLabel", "group_id": 41 }], "changes": { "updated_by_id": { "previous": null, "current": 1 }, "updated_at": { "previous": "2017-09-15 16:50:55 UTC", "current": "2017-09-15 16:52:00 UTC" }, "labels": { "previous": [{ "id": 206, "title": "API", "color": "#ffffff", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "API related issues", "type": "ProjectLabel", "group_id": 41 }], "current": [{ "id": 205, "title": "Platform", "color": "#123123", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "Platform related issues", "type": "ProjectLabel", "group_id": 41 }] } } }` parsedEvent, err := ParseWebhook("Issue Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing issue hook: %s", err) } event, ok := parsedEvent.(*IssueEvent) if !ok { t.Errorf("Expected IssueEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "issue" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "issue") } if event.Project.Name != "Gitlab Test" { t.Errorf("Project name is %v, want %v", event.Project.Name, "Gitlab Test") } if event.ObjectAttributes.State != "opened" { t.Errorf("Issue state is %v, want %v", event.ObjectAttributes.State, "opened") } if event.Assignee.Username != "user1" { t.Errorf("Assignee username is %v, want %v", event.Assignee.Username, "user1") } assert.Equal(t, 1, len(event.Labels)) assert.Equal(t, 0, event.Changes.UpdatedByID.Previous) assert.Equal(t, 1, event.Changes.UpdatedByID.Current) assert.Equal(t, 1, len(event.Changes.Labels.Previous)) assert.Equal(t, 1, len(event.Changes.Labels.Current)) } func TestParseCommitCommentHook(t *testing.T) { raw := `{ "object_kind": "note", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "project_id": 5, "project":{ "id": 5, "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlabhq/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "git_http_url":"http://example.com/gitlabhq/gitlab-test.git", "namespace":"GitlabHQ", "visibility_level":20, "path_with_namespace":"gitlabhq/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"http://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "http_url":"http://example.com/gitlabhq/gitlab-test.git" }, "repository":{ "name": "Gitlab Test", "url": "http://example.com/gitlab-org/gitlab-test.git", "description": "Aut reprehenderit ut est.", "homepage": "http://example.com/gitlab-org/gitlab-test" }, "object_attributes": { "id": 1243, "note": "This is a commit comment. How does this work?", "noteable_type": "Commit", "author_id": 1, "created_at": "2015-05-17 18:08:09 UTC", "updated_at": "2015-05-17 18:08:09 UTC", "project_id": 5, "attachment":null, "line_code": "bec9703f7a456cd2b4ab5fb3220ae016e3e394e3_0_1", "commit_id": "cfe32cf61b73a0d5e9f13e774abde7ff789b1660", "noteable_id": null, "system": false, "st_diff": { "diff": "--- /dev/null\n+++ b/six\n@@ -0,0 +1 @@\n+Subproject commit 409f37c4f05865e4fb208c771485f211a22c4c2d\n", "new_path": "six", "old_path": "six", "a_mode": "0", "b_mode": "160000", "new_file": true, "renamed_file": false, "deleted_file": false }, "url": "http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660#note_1243" }, "commit": { "id": "cfe32cf61b73a0d5e9f13e774abde7ff789b1660", "message": "Add submodule\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", "timestamp": "2014-02-27T10:06:20+02:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660", "author": { "name": "Dmitriy Zaporozhets", "email": "dmitriy.zaporozhets@gmail.com" } } }` parsedEvent, err := ParseWebhook("Note Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing note hook: %s", err) } event, ok := parsedEvent.(*CommitCommentEvent) if !ok { t.Errorf("Expected CommitCommentEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "note" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "note") } if event.ProjectID != 5 { t.Errorf("ProjectID is %v, want %v", event.ProjectID, 5) } if event.ObjectAttributes.NoteableType != "Commit" { t.Errorf("NoteableType is %v, want %v", event.ObjectAttributes.NoteableType, "Commit") } if event.Commit.ID != "cfe32cf61b73a0d5e9f13e774abde7ff789b1660" { t.Errorf("CommitID is %v, want %v", event.Commit.ID, "cfe32cf61b73a0d5e9f13e774abde7ff789b1660") } } func TestParseMergeRequestCommentHook(t *testing.T) { raw := `{ "object_kind": "note", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "project_id": 5, "project":{ "id": 5, "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlab-org/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "git_http_url":"http://example.com/gitlab-org/gitlab-test.git", "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"http://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "http_url":"http://example.com/gitlab-org/gitlab-test.git" }, "repository":{ "name": "Gitlab Test", "url": "http://localhost/gitlab-org/gitlab-test.git", "description": "Aut reprehenderit ut est.", "homepage": "http://example.com/gitlab-org/gitlab-test" }, "object_attributes": { "id": 1244, "note": "This MR needs work.", "noteable_type": "MergeRequest", "author_id": 1, "created_at": "2015-05-17 18:21:36 UTC", "updated_at": "2015-05-17 18:21:36 UTC", "project_id": 5, "attachment": null, "line_code": null, "commit_id": "", "noteable_id": 7, "system": false, "st_diff": null, "url": "http://example.com/gitlab-org/gitlab-test/merge_requests/1#note_1244" }, "merge_request": { "id": 7, "target_branch": "markdown", "source_branch": "master", "source_project_id": 5, "author_id": 8, "assignee_id": 28, "title": "Tempora et eos debitis quae laborum et.", "created_at": "2015-03-01 20:12:53 UTC", "updated_at": "2015-03-21 18:27:27 UTC", "milestone_id": 11, "state": "opened", "merge_status": "cannot_be_merged", "target_project_id": 5, "iid": 1, "description": "Et voluptas corrupti assumenda temporibus. Architecto cum animi eveniet amet asperiores. Vitae numquam voluptate est natus sit et ad id.", "position": 0, "source":{ "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlab-org/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "git_http_url":"http://example.com/gitlab-org/gitlab-test.git", "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"http://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "http_url":"http://example.com/gitlab-org/gitlab-test.git" }, "target": { "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlab-org/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "git_http_url":"http://example.com/gitlab-org/gitlab-test.git", "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"http://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "http_url":"http://example.com/gitlab-org/gitlab-test.git" }, "last_commit": { "id": "562e173be03b8ff2efb05345d12df18815438a4b", "message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n", "timestamp": "2015-04-08T21:00:25-07:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b", "author": { "name": "John Smith", "email": "john@example.com" } }, "work_in_progress": false, "assignee": { "name": "User1", "username": "user1", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } } }` parsedEvent, err := ParseWebhook("Note Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing note hook: %s", err) } event, ok := parsedEvent.(*MergeCommentEvent) if !ok { t.Errorf("Expected MergeCommentEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "note" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "note") } if event.ProjectID != 5 { t.Errorf("ProjectID is %v, want %v", event.ProjectID, 5) } if event.ObjectAttributes.NoteableType != "MergeRequest" { t.Errorf("NoteableType is %v, want %v", event.ObjectAttributes.NoteableType, "MergeRequest") } if event.MergeRequest.ID != 7 { t.Errorf("MergeRequest ID is %v, want %v", event.MergeRequest.ID, 7) } } func TestParseIssueCommentHook(t *testing.T) { raw := `{ "object_kind": "note", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "project_id": 5, "project":{ "id": 5, "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlab-org/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "git_http_url":"http://example.com/gitlab-org/gitlab-test.git", "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"http://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "http_url":"http://example.com/gitlab-org/gitlab-test.git" }, "repository":{ "name":"diaspora", "url":"git@example.com:mike/diaspora.git", "description":"", "homepage":"http://example.com/mike/diaspora" }, "object_attributes": { "id": 1241, "note": "Hello world", "noteable_type": "Issue", "author_id": 1, "created_at": "2015-05-17 17:06:40 UTC", "updated_at": "2015-05-17 17:06:40 UTC", "project_id": 5, "attachment": null, "line_code": null, "commit_id": "", "noteable_id": 92, "system": false, "st_diff": null, "url": "http://example.com/gitlab-org/gitlab-test/issues/17#note_1241" }, "issue": { "id": 92, "title": "test", "assignee_ids": [], "assignee_id": null, "author_id": 1, "project_id": 5, "created_at": "2016-01-04T15:31:46.176Z", "updated_at": "2016-01-04T15:31:46.176Z", "position": 0, "branch_name": null, "description": "test", "milestone_id": null, "state": "closed", "iid": 17 } }` parsedEvent, err := ParseWebhook("Note Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing note hook: %s", err) } event, ok := parsedEvent.(*IssueCommentEvent) if !ok { t.Errorf("Expected IssueCommentEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "note" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "note") } if event.ProjectID != 5 { t.Errorf("ProjectID is %v, want %v", event.ProjectID, 5) } if event.ObjectAttributes.NoteableType != "Issue" { t.Errorf("NoteableType is %v, want %v", event.ObjectAttributes.NoteableType, "Issue") } if event.Issue.Title != "test" { t.Errorf("Issue title is %v, want %v", event.Issue.Title, "test") } } func TestParseSnippetCommentHook(t *testing.T) { raw := `{ "object_kind": "note", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "project_id": 5, "project":{ "id": 5, "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlab-org/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "git_http_url":"http://example.com/gitlab-org/gitlab-test.git", "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"http://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", "http_url":"http://example.com/gitlab-org/gitlab-test.git" }, "repository":{ "name":"Gitlab Test", "url":"http://example.com/gitlab-org/gitlab-test.git", "description":"Aut reprehenderit ut est.", "homepage":"http://example.com/gitlab-org/gitlab-test" }, "object_attributes": { "id": 1245, "note": "Is this snippet doing what it's supposed to be doing?", "noteable_type": "Snippet", "author_id": 1, "created_at": "2015-05-17 18:35:50 UTC", "updated_at": "2015-05-17 18:35:50 UTC", "project_id": 5, "attachment": null, "line_code": null, "commit_id": "", "noteable_id": 53, "system": false, "st_diff": null, "url": "http://example.com/gitlab-org/gitlab-test/snippets/53#note_1245" }, "snippet": { "id": 53, "title": "test", "content": "puts 'Hello world'", "author_id": 1, "project_id": 5, "created_at": "2016-01-04T15:31:46.176Z", "updated_at": "2016-01-04T15:31:46.176Z", "file_name": "test.rb", "expires_at": null, "type": "ProjectSnippet", "visibility_level": 0 } }` parsedEvent, err := ParseWebhook("Note Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing note hook: %s", err) } event, ok := parsedEvent.(*SnippetCommentEvent) if !ok { t.Errorf("Expected SnippetCommentEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "note" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "note") } if event.ProjectID != 5 { t.Errorf("ProjectID is %v, want %v", event.ProjectID, 5) } if event.ObjectAttributes.NoteableType != "Snippet" { t.Errorf("NoteableType is %v, want %v", event.ObjectAttributes.NoteableType, "Snippet") } if event.Snippet.Title != "test" { t.Errorf("Snippet title is %v, want %v", event.Snippet.Title, "test") } } func TestParseMergeRequestHook(t *testing.T) { raw := `{ "object_kind": "merge_request", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "project": { "id": 1, "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlabhq/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "git_http_url":"http://example.com/gitlabhq/gitlab-test.git", "namespace":"GitlabHQ", "visibility_level":20, "path_with_namespace":"gitlabhq/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"http://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "http_url":"http://example.com/gitlabhq/gitlab-test.git" }, "repository": { "name": "Gitlab Test", "url": "http://example.com/gitlabhq/gitlab-test.git", "description": "Aut reprehenderit ut est.", "homepage": "http://example.com/gitlabhq/gitlab-test" }, "object_attributes": { "id": 99, "target_branch": "master", "source_branch": "ms-viewport", "source_project_id": 14, "author_id": 51, "assignee_id": 6, "title": "MS-Viewport", "created_at": "2013-12-03T17:23:34Z", "updated_at": "2013-12-03T17:23:34Z", "milestone_id": null, "state": "opened", "merge_status": "unchecked", "target_project_id": 14, "iid": 1, "description": "", "source": { "name":"Awesome Project", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/awesome_space/awesome_project", "avatar_url":null, "git_ssh_url":"git@example.com:awesome_space/awesome_project.git", "git_http_url":"http://example.com/awesome_space/awesome_project.git", "namespace":"Awesome Space", "visibility_level":20, "path_with_namespace":"awesome_space/awesome_project", "default_branch":"master", "homepage":"http://example.com/awesome_space/awesome_project", "url":"http://example.com/awesome_space/awesome_project.git", "ssh_url":"git@example.com:awesome_space/awesome_project.git", "http_url":"http://example.com/awesome_space/awesome_project.git" }, "target": { "name":"Awesome Project", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/awesome_space/awesome_project", "avatar_url":null, "git_ssh_url":"git@example.com:awesome_space/awesome_project.git", "git_http_url":"http://example.com/awesome_space/awesome_project.git", "namespace":"Awesome Space", "visibility_level":20, "path_with_namespace":"awesome_space/awesome_project", "default_branch":"master", "homepage":"http://example.com/awesome_space/awesome_project", "url":"http://example.com/awesome_space/awesome_project.git", "ssh_url":"git@example.com:awesome_space/awesome_project.git", "http_url":"http://example.com/awesome_space/awesome_project.git" }, "last_commit": { "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "message": "fixed readme", "timestamp": "2012-01-03T23:36:29+02:00", "url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "author": { "name": "GitLab dev user", "email": "gitlabdev@dv6700.(none)" } }, "work_in_progress": false, "url": "http://example.com/diaspora/merge_requests/1", "action": "open", "assignee": { "name": "User1", "username": "user1", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } }, "labels": [{ "id": 206, "title": "API", "color": "#ffffff", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "API related issues", "type": "ProjectLabel", "group_id": 41 }], "changes": { "updated_by_id": { "previous": null, "current": 1 }, "updated_at": { "previous": "2017-09-15 16:50:55 UTC", "current": "2017-09-15 16:52:00 UTC" }, "labels": { "previous": [{ "id": 206, "title": "API", "color": "#ffffff", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "API related issues", "type": "ProjectLabel", "group_id": 41 }], "current": [{ "id": 205, "title": "Platform", "color": "#123123", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "Platform related issues", "type": "ProjectLabel", "group_id": 41 }] } } }` parsedEvent, err := ParseWebhook("Merge Request Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing merge request hook: %s", err) } event, ok := parsedEvent.(*MergeEvent) if !ok { t.Errorf("Expected MergeEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "merge_request" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "merge_request") } if event.ObjectAttributes.MergeStatus != "unchecked" { t.Errorf("MergeStatus is %v, want %v", event.ObjectAttributes.MergeStatus, "unchecked") } if event.ObjectAttributes.LastCommit.ID != "da1560886d4f094c3e6c9ef40349f7d38b5d27d7" { t.Errorf("LastCommit ID is %v, want %v", event.ObjectAttributes.LastCommit.ID, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7") } if event.ObjectAttributes.WorkInProgress { t.Errorf("WorkInProgress is %v, want %v", event.ObjectAttributes.WorkInProgress, false) } assert.Equal(t, 1, len(event.Labels)) assert.Equal(t, 0, event.Changes.UpdatedByID.Previous) assert.Equal(t, 1, event.Changes.UpdatedByID.Current) assert.Equal(t, 1, len(event.Changes.Labels.Previous)) assert.Equal(t, 1, len(event.Changes.Labels.Current)) } func TestParseWikiPageHook(t *testing.T) { raw := `{ "object_kind": "wiki_page", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon" }, "project": { "id": 1, "name": "awesome-project", "description": "This is awesome", "web_url": "http://example.com/root/awesome-project", "avatar_url": null, "git_ssh_url": "git@example.com:root/awesome-project.git", "git_http_url": "http://example.com/root/awesome-project.git", "namespace": "root", "visibility_level": 0, "path_with_namespace": "root/awesome-project", "default_branch": "master", "homepage": "http://example.com/root/awesome-project", "url": "git@example.com:root/awesome-project.git", "ssh_url": "git@example.com:root/awesome-project.git", "http_url": "http://example.com/root/awesome-project.git" }, "wiki": { "web_url": "http://example.com/root/awesome-project/wikis/home", "git_ssh_url": "git@example.com:root/awesome-project.wiki.git", "git_http_url": "http://example.com/root/awesome-project.wiki.git", "path_with_namespace": "root/awesome-project.wiki", "default_branch": "master" }, "object_attributes": { "title": "Awesome", "content": "awesome content goes here", "format": "markdown", "message": "adding an awesome page to the wiki", "slug": "awesome", "url": "http://example.com/root/awesome-project/wikis/awesome", "action": "create" } }` parsedEvent, err := ParseWebhook("Wiki Page Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing wiki page hook: %s", err) } event, ok := parsedEvent.(*WikiPageEvent) if !ok { t.Errorf("Expected WikiPageEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "wiki_page" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "wiki_page") } if event.Project.Name != "awesome-project" { t.Errorf("Project name is %v, want %v", event.Project.Name, "awesome-project") } if event.Wiki.WebURL != "http://example.com/root/awesome-project/wikis/home" { t.Errorf("Wiki web URL is %v, want %v", event.Wiki.WebURL, "http://example.com/root/awesome-project/wikis/home") } if event.ObjectAttributes.Message != "adding an awesome page to the wiki" { t.Errorf("Message is %v, want %v", event.ObjectAttributes.Message, "adding an awesome page to the wiki") } } func TestParsePipelineHook(t *testing.T) { raw := `{ "object_kind": "pipeline", "object_attributes":{ "id": 31, "ref": "master", "tag": false, "sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", "before_sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", "status": "success", "stages":[ "build", "test", "deploy" ], "created_at": "2016-08-12 15:23:28 UTC", "finished_at": "2016-08-12 15:26:29 UTC", "duration": 63, "variables": [ { "key": "NESTOR_PROD_ENVIRONMENT", "value": "us-west-1" } ] }, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "project":{ "id": 1, "name": "Gitlab Test", "description": "Atque in sunt eos similique dolores voluptatem.", "web_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test", "avatar_url": null, "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", "git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", "namespace": "Gitlab Org", "visibility_level": 20, "path_with_namespace": "gitlab-org/gitlab-test", "default_branch": "master" }, "commit":{ "id": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", "message": "test\n", "timestamp": "2016-08-12T17:23:21+02:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2", "author":{ "name": "User", "email": "user@gitlab.com" } }, "builds":[ { "id": 380, "stage": "deploy", "name": "production", "status": "skipped", "created_at": "2016-08-12 15:23:28 UTC", "started_at": null, "finished_at": null, "when": "manual", "manual": true, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": null, "artifacts_file":{ "filename": null, "size": null } }, { "id": 377, "stage": "test", "name": "test-image", "status": "success", "created_at": "2016-08-12 15:23:28 UTC", "started_at": "2016-08-12 15:26:12 UTC", "finished_at": null, "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": { "id":380987, "description":"shared-runners-manager-6.gitlab.com", "active":true, "is_shared":true }, "artifacts_file":{ "filename": null, "size": null } }, { "id": 378, "stage": "test", "name": "test-build", "status": "success", "created_at": "2016-08-12 15:23:28 UTC", "started_at": "2016-08-12 15:26:12 UTC", "finished_at": "2016-08-12 15:26:29 UTC", "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": { "id":380987, "description":"shared-runners-manager-6.gitlab.com", "active":true, "is_shared":true }, "artifacts_file":{ "filename": null, "size": null } }, { "id": 376, "stage": "build", "name": "build-image", "status": "success", "created_at": "2016-08-12 15:23:28 UTC", "started_at": "2016-08-12 15:24:56 UTC", "finished_at": "2016-08-12 15:25:26 UTC", "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": { "id":380987, "description":"shared-runners-manager-6.gitlab.com", "active":true, "is_shared":true }, "artifacts_file":{ "filename": null, "size": null } }, { "id": 379, "stage": "deploy", "name": "staging", "status": "created", "created_at": "2016-08-12 15:23:28 UTC", "started_at": null, "finished_at": null, "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": null, "artifacts_file":{ "filename": null, "size": null } } ] }` parsedEvent, err := ParseWebhook("Pipeline Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing pipeline hook: %s", err) } event, ok := parsedEvent.(*PipelineEvent) if !ok { t.Errorf("Expected PipelineEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "pipeline" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "pipeline") } if event.ObjectAttributes.Duration != 63 { t.Errorf("Duration is %v, want %v", event.ObjectAttributes.Duration, 63) } if event.Commit.ID != "bcbb5ec396a2c0f828686f14fac9b80b780504f2" { t.Errorf("Commit ID is %v, want %v", event.Commit.ID, "bcbb5ec396a2c0f828686f14fac9b80b780504f2") } if event.Builds[0].ID != 380 { t.Errorf("Builds[0] ID is %v, want %v", event.Builds[0].ID, 380) } } func TestParseBuildHook(t *testing.T) { raw := `{ "object_kind": "build", "ref": "gitlab-script-trigger", "tag": false, "before_sha": "2293ada6b400935a1378653304eaf6221e0fdb8f", "sha": "2293ada6b400935a1378653304eaf6221e0fdb8f", "build_id": 1977, "build_name": "test", "build_stage": "test", "build_status": "created", "build_started_at": null, "build_finished_at": null, "build_duration": null, "build_allow_failure": false, "build_failure_reason": "script_failure", "project_id": 380, "project_name": "gitlab-org/gitlab-test", "user": { "id": 3, "name": "User", "email": "user@gitlab.com" }, "commit": { "id": 2366, "sha": "2293ada6b400935a1378653304eaf6221e0fdb8f", "message": "test\n", "author_name": "User", "author_email": "user@gitlab.com", "status": "created", "duration": null, "started_at": null, "finished_at": null }, "repository": { "name": "gitlab_test", "description": "Atque in sunt eos similique dolores voluptatem.", "homepage": "http://192.168.64.1:3005/gitlab-org/gitlab-test", "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", "git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", "visibility_level": 20 } }` parsedEvent, err := ParseWebhook("Build Hook", []byte(raw)) if err != nil { t.Errorf("Error parsing build hook: %s", err) } event, ok := parsedEvent.(*BuildEvent) if !ok { t.Errorf("Expected BuildEvent, but parsing produced %T", parsedEvent) } if event.ObjectKind != "build" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "build") } if event.BuildID != 1977 { t.Errorf("BuildID is %v, want %v", event.BuildID, 1977) } if event.BuildAllowFailure { t.Errorf("BuildAllowFailure is %v, want %v", event.BuildAllowFailure, false) } if event.Commit.SHA != "2293ada6b400935a1378653304eaf6221e0fdb8f" { t.Errorf("Commit SHA is %v, want %v", event.Commit.SHA, "2293ada6b400935a1378653304eaf6221e0fdb8f") } } golang-github-xanzy-go-gitlab-0.22.2/event_types.go000066400000000000000000000765171357140411500222530ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "encoding/json" "fmt" "strconv" "time" ) // PushEvent represents a push event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#push-events type PushEvent struct { ObjectKind string `json:"object_kind"` Before string `json:"before"` After string `json:"after"` Ref string `json:"ref"` CheckoutSHA string `json:"checkout_sha"` UserID int `json:"user_id"` UserName string `json:"user_name"` UserUsername string `json:"user_username"` UserEmail string `json:"user_email"` UserAvatar string `json:"user_avatar"` ProjectID int `json:"project_id"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Repository *Repository `json:"repository"` Commits []*struct { ID string `json:"id"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author struct { Name string `json:"name"` Email string `json:"email"` } `json:"author"` Added []string `json:"added"` Modified []string `json:"modified"` Removed []string `json:"removed"` } `json:"commits"` TotalCommitsCount int `json:"total_commits_count"` } // TagEvent represents a tag event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#tag-events type TagEvent struct { ObjectKind string `json:"object_kind"` Before string `json:"before"` After string `json:"after"` Ref string `json:"ref"` CheckoutSHA string `json:"checkout_sha"` UserID int `json:"user_id"` UserName string `json:"user_name"` UserAvatar string `json:"user_avatar"` ProjectID int `json:"project_id"` Message string `json:"message"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Repository *Repository `json:"repository"` Commits []*struct { ID string `json:"id"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author struct { Name string `json:"name"` Email string `json:"email"` } `json:"author"` Added []string `json:"added"` Modified []string `json:"modified"` Removed []string `json:"removed"` } `json:"commits"` TotalCommitsCount int `json:"total_commits_count"` } // IssueEvent represents a issue event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#issues-events type IssueEvent struct { ObjectKind string `json:"object_kind"` User *User `json:"user"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Repository *Repository `json:"repository"` ObjectAttributes struct { ID int `json:"id"` Title string `json:"title"` AssigneeID int `json:"assignee_id"` AuthorID int `json:"author_id"` ProjectID int `json:"project_id"` CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468) UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468) Position int `json:"position"` BranchName string `json:"branch_name"` Description string `json:"description"` MilestoneID int `json:"milestone_id"` State string `json:"state"` IID int `json:"iid"` URL string `json:"url"` Action string `json:"action"` } `json:"object_attributes"` Assignee struct { Name string `json:"name"` Username string `json:"username"` AvatarURL string `json:"avatar_url"` } `json:"assignee"` Assignees []struct { Name string `json:"name"` Username string `json:"username"` AvatarURL string `json:"avatar_url"` } `json:"assignees"` Labels []Label `json:"labels"` Changes struct { Labels struct { Previous []Label `json:"previous"` Current []Label `json:"current"` } `json:"labels"` UpdatedByID struct { Previous int `json:"previous"` Current int `json:"current"` } `json:"updated_by_id"` } `json:"changes"` } // JobEvent represents a job event. // // GitLab API docs: // TODO: link to docs instead of src once they are published. // https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/data_builder/build.rb type JobEvent struct { ObjectKind string `json:"object_kind"` Ref string `json:"ref"` Tag bool `json:"tag"` BeforeSHA string `json:"before_sha"` SHA string `json:"sha"` BuildID int `json:"build_id"` BuildName string `json:"build_name"` BuildStage string `json:"build_stage"` BuildStatus string `json:"build_status"` BuildStartedAt string `json:"build_started_at"` BuildFinishedAt string `json:"build_finished_at"` BuildDuration float64 `json:"build_duration"` BuildAllowFailure bool `json:"build_allow_failure"` ProjectID int `json:"project_id"` ProjectName string `json:"project_name"` User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` } `json:"user"` Commit struct { ID int `json:"id"` SHA string `json:"sha"` Message string `json:"message"` AuthorName string `json:"author_name"` AuthorEmail string `json:"author_email"` AuthorURL string `json:"author_url"` Status string `json:"status"` Duration int `json:"duration"` StartedAt string `json:"started_at"` FinishedAt string `json:"finished_at"` } `json:"commit"` Repository *Repository `json:"repository"` } // CommitCommentEvent represents a comment on a commit event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-commit type CommitCommentEvent struct { ObjectKind string `json:"object_kind"` User *User `json:"user"` ProjectID int `json:"project_id"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Repository *Repository `json:"repository"` ObjectAttributes struct { ID int `json:"id"` Note string `json:"note"` NoteableType string `json:"noteable_type"` AuthorID int `json:"author_id"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` ProjectID int `json:"project_id"` Attachment string `json:"attachment"` LineCode string `json:"line_code"` CommitID string `json:"commit_id"` NoteableID int `json:"noteable_id"` System bool `json:"system"` StDiff struct { Diff string `json:"diff"` NewPath string `json:"new_path"` OldPath string `json:"old_path"` AMode string `json:"a_mode"` BMode string `json:"b_mode"` NewFile bool `json:"new_file"` RenamedFile bool `json:"renamed_file"` DeletedFile bool `json:"deleted_file"` } `json:"st_diff"` } `json:"object_attributes"` Commit *struct { ID string `json:"id"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author struct { Name string `json:"name"` Email string `json:"email"` } `json:"author"` } `json:"commit"` } // MergeCommentEvent represents a comment on a merge event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-merge-request type MergeCommentEvent struct { ObjectKind string `json:"object_kind"` User *User `json:"user"` ProjectID int `json:"project_id"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` ObjectAttributes struct { ID int `json:"id"` DiscussionID string `json:"discussion_id"` Note string `json:"note"` NoteableType string `json:"noteable_type"` AuthorID int `json:"author_id"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` ProjectID int `json:"project_id"` Attachment string `json:"attachment"` LineCode string `json:"line_code"` CommitID string `json:"commit_id"` NoteableID int `json:"noteable_id"` System bool `json:"system"` StDiff *Diff `json:"st_diff"` URL string `json:"url"` } `json:"object_attributes"` Repository *Repository `json:"repository"` MergeRequest struct { ID int `json:"id"` TargetBranch string `json:"target_branch"` SourceBranch string `json:"source_branch"` SourceProjectID int `json:"source_project_id"` AuthorID int `json:"author_id"` AssigneeID int `json:"assignee_id"` Title string `json:"title"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` MilestoneID int `json:"milestone_id"` State string `json:"state"` MergeStatus string `json:"merge_status"` TargetProjectID int `json:"target_project_id"` IID int `json:"iid"` Description string `json:"description"` Position int `json:"position"` LockedAt string `json:"locked_at"` UpdatedByID int `json:"updated_by_id"` MergeError string `json:"merge_error"` MergeParams *MergeParams `json:"merge_params"` MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` MergeUserID int `json:"merge_user_id"` MergeCommitSHA string `json:"merge_commit_sha"` DeletedAt string `json:"deleted_at"` InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"` LockVersion int `json:"lock_version"` ApprovalsBeforeMerge string `json:"approvals_before_merge"` RebaseCommitSHA string `json:"rebase_commit_sha"` TimeEstimate int `json:"time_estimate"` Squash bool `json:"squash"` LastEditedAt string `json:"last_edited_at"` LastEditedByID int `json:"last_edited_by_id"` Source *Repository `json:"source"` Target *Repository `json:"target"` LastCommit struct { ID string `json:"id"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author struct { Name string `json:"name"` Email string `json:"email"` } `json:"author"` } `json:"last_commit"` WorkInProgress bool `json:"work_in_progress"` TotalTimeSpent int `json:"total_time_spent"` HeadPipelineID int `json:"head_pipeline_id"` } `json:"merge_request"` } // IssueCommentEvent represents a comment on an issue event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-issue type IssueCommentEvent struct { ObjectKind string `json:"object_kind"` User *User `json:"user"` ProjectID int `json:"project_id"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Repository *Repository `json:"repository"` ObjectAttributes struct { ID int `json:"id"` Note string `json:"note"` NoteableType string `json:"noteable_type"` AuthorID int `json:"author_id"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` ProjectID int `json:"project_id"` Attachment string `json:"attachment"` LineCode string `json:"line_code"` CommitID string `json:"commit_id"` NoteableID int `json:"noteable_id"` System bool `json:"system"` StDiff []*Diff `json:"st_diff"` URL string `json:"url"` } `json:"object_attributes"` Issue struct { ID int `json:"id"` IID int `json:"iid"` ProjectID int `json:"project_id"` MilestoneID int `json:"milestone_id"` AuthorID int `json:"author_id"` Description string `json:"description"` State string `json:"state"` Title string `json:"title"` LastEditedAt string `json:"last_edit_at"` LastEditedByID int `json:"last_edited_by_id"` UpdatedAt string `json:"updated_at"` UpdatedByID int `json:"updated_by_id"` CreatedAt string `json:"created_at"` ClosedAt string `json:"closed_at"` DueDate *ISOTime `json:"due_date"` URL string `json:"url"` TimeEstimate int `json:"time_estimate"` Confidential bool `json:"confidential"` TotalTimeSpent int `json:"total_time_spent"` HumanTotalTimeSpent int `json:"human_total_time_spent"` HumanTimeEstimate int `json:"human_time_estimate"` AssigneeIDs []int `json:"assignee_ids"` AssigneeID int `json:"assignee_id"` } `json:"issue"` } // SnippetCommentEvent represents a comment on a snippet event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-code-snippet type SnippetCommentEvent struct { ObjectKind string `json:"object_kind"` User *User `json:"user"` ProjectID int `json:"project_id"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Repository *Repository `json:"repository"` ObjectAttributes struct { ID int `json:"id"` Note string `json:"note"` NoteableType string `json:"noteable_type"` AuthorID int `json:"author_id"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` ProjectID int `json:"project_id"` Attachment string `json:"attachment"` LineCode string `json:"line_code"` CommitID string `json:"commit_id"` NoteableID int `json:"noteable_id"` System bool `json:"system"` StDiff *Diff `json:"st_diff"` URL string `json:"url"` } `json:"object_attributes"` Snippet *Snippet `json:"snippet"` } // MergeEvent represents a merge event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#merge-request-events type MergeEvent struct { ObjectKind string `json:"object_kind"` User *User `json:"user"` Project struct { ID int `json:"id"` Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` ObjectAttributes struct { ID int `json:"id"` TargetBranch string `json:"target_branch"` SourceBranch string `json:"source_branch"` SourceProjectID int `json:"source_project_id"` AuthorID int `json:"author_id"` AssigneeID int `json:"assignee_id"` Title string `json:"title"` CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468) UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468) StCommits []*Commit `json:"st_commits"` StDiffs []*Diff `json:"st_diffs"` MilestoneID int `json:"milestone_id"` State string `json:"state"` MergeStatus string `json:"merge_status"` TargetProjectID int `json:"target_project_id"` IID int `json:"iid"` Description string `json:"description"` Position int `json:"position"` LockedAt string `json:"locked_at"` UpdatedByID int `json:"updated_by_id"` MergeError string `json:"merge_error"` MergeParams *MergeParams `json:"merge_params"` MergeWhenBuildSucceeds bool `json:"merge_when_build_succeeds"` MergeUserID int `json:"merge_user_id"` MergeCommitSHA string `json:"merge_commit_sha"` DeletedAt string `json:"deleted_at"` ApprovalsBeforeMerge string `json:"approvals_before_merge"` RebaseCommitSHA string `json:"rebase_commit_sha"` InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"` LockVersion int `json:"lock_version"` TimeEstimate int `json:"time_estimate"` Source *Repository `json:"source"` Target *Repository `json:"target"` LastCommit struct { ID string `json:"id"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author struct { Name string `json:"name"` Email string `json:"email"` } `json:"author"` } `json:"last_commit"` WorkInProgress bool `json:"work_in_progress"` URL string `json:"url"` Action string `json:"action"` OldRev string `json:"oldrev"` Assignee MergeAssignee `json:"assignee"` } `json:"object_attributes"` Repository *Repository `json:"repository"` Assignee MergeAssignee `json:"assignee"` Labels []Label `json:"labels"` Changes struct { Assignees struct { Previous []MergeAssignee `json:"previous"` Current []MergeAssignee `json:"current"` } `json:"assignees"` Description struct { Previous string `json:"previous"` Current string `json:"current"` } `json:"description"` Labels struct { Previous []Label `json:"previous"` Current []Label `json:"current"` } `json:"labels"` SourceBranch struct { Previous string `json:"previous"` Current string `json:"current"` } `json:"source_branch"` SourceProjectID struct { Previous int `json:"previous"` Current int `json:"current"` } `json:"source_project_id"` TargetBranch struct { Previous string `json:"previous"` Current string `json:"current"` } `json:"target_branch"` TargetProjectID struct { Previous int `json:"previous"` Current int `json:"current"` } `json:"target_project_id"` Title struct { Previous string `json:"previous"` Current string `json:"current"` } `json:"title"` UpdatedByID struct { Previous int `json:"previous"` Current int `json:"current"` } `json:"updated_by_id"` } `json:"changes"` } // MergeAssignee represents a merge assignee. type MergeAssignee struct { Name string `json:"name"` Username string `json:"username"` AvatarURL string `json:"avatar_url"` } // MergeParams represents the merge params. type MergeParams struct { ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` } // UnmarshalJSON decodes the merge parameters // // This allows support of ForceRemoveSourceBranch for both type bool (>11.9) and string (<11.9) func (p *MergeParams) UnmarshalJSON(b []byte) error { type Alias MergeParams raw := struct { *Alias ForceRemoveSourceBranch interface{} `json:"force_remove_source_branch"` }{ Alias: (*Alias)(p), } err := json.Unmarshal(b, &raw) if err != nil { return err } switch v := raw.ForceRemoveSourceBranch.(type) { case nil: // No action needed. case bool: p.ForceRemoveSourceBranch = v case string: p.ForceRemoveSourceBranch, err = strconv.ParseBool(v) if err != nil { return err } default: return fmt.Errorf("failed to unmarshal ForceRemoveSourceBranch of type: %T", v) } return nil } // WikiPageEvent represents a wiki page event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#wiki-page-events type WikiPageEvent struct { ObjectKind string `json:"object_kind"` User *User `json:"user"` Project struct { Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Wiki struct { WebURL string `json:"web_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` } `json:"wiki"` ObjectAttributes struct { Title string `json:"title"` Content string `json:"content"` Format string `json:"format"` Message string `json:"message"` Slug string `json:"slug"` URL string `json:"url"` Action string `json:"action"` } `json:"object_attributes"` } // PipelineEvent represents a pipeline event. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#pipeline-events type PipelineEvent struct { ObjectKind string `json:"object_kind"` ObjectAttributes struct { ID int `json:"id"` Ref string `json:"ref"` Tag bool `json:"tag"` SHA string `json:"sha"` BeforeSHA string `json:"before_sha"` Status string `json:"status"` Stages []string `json:"stages"` CreatedAt string `json:"created_at"` FinishedAt string `json:"finished_at"` Duration int `json:"duration"` } `json:"object_attributes"` User struct { Name string `json:"name"` Username string `json:"username"` AvatarURL string `json:"avatar_url"` } `json:"user"` Project struct { ID int `json:"id"` Name string `json:"name"` Description string `json:"description"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` WebURL string `json:"web_url"` Visibility VisibilityValue `json:"visibility"` } `json:"project"` Commit struct { ID string `json:"id"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author struct { Name string `json:"name"` Email string `json:"email"` } `json:"author"` } `json:"commit"` Builds []struct { ID int `json:"id"` Stage string `json:"stage"` Name string `json:"name"` Status string `json:"status"` CreatedAt string `json:"created_at"` StartedAt string `json:"started_at"` FinishedAt string `json:"finished_at"` When string `json:"when"` Manual bool `json:"manual"` User struct { Name string `json:"name"` Username string `json:"username"` AvatarURL string `json:"avatar_url"` } `json:"user"` Runner struct { ID int `json:"id"` Description string `json:"description"` Active bool `json:"active"` IsShared bool `json:"is_shared"` } `json:"runner"` ArtifactsFile struct { Filename string `json:"filename"` Size int `json:"size"` } `json:"artifacts_file"` } `json:"builds"` } //BuildEvent represents a build event // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#build-events type BuildEvent struct { ObjectKind string `json:"object_kind"` Ref string `json:"ref"` Tag bool `json:"tag"` BeforeSHA string `json:"before_sha"` SHA string `json:"sha"` BuildID int `json:"build_id"` BuildName string `json:"build_name"` BuildStage string `json:"build_stage"` BuildStatus string `json:"build_status"` BuildStartedAt string `json:"build_started_at"` BuildFinishedAt string `json:"build_finished_at"` BuildDuration float64 `json:"build_duration"` BuildAllowFailure bool `json:"build_allow_failure"` ProjectID int `json:"project_id"` ProjectName string `json:"project_name"` User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` } `json:"user"` Commit struct { ID int `json:"id"` SHA string `json:"sha"` Message string `json:"message"` AuthorName string `json:"author_name"` AuthorEmail string `json:"author_email"` Status string `json:"status"` Duration int `json:"duration"` StartedAt string `json:"started_at"` FinishedAt string `json:"finished_at"` } `json:"commit"` Repository *Repository `json:"repository"` } golang-github-xanzy-go-gitlab-0.22.2/event_types_test.go000066400000000000000000000557201357140411500233030ustar00rootroot00000000000000package gitlab import ( "encoding/json" "github.com/stretchr/testify/assert" "testing" ) func TestPushEventUnmarshal(t *testing.T) { jsonObject := `{ "object_kind": "push", "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "ref": "refs/heads/master", "checkout_sha": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "user_id": 4, "user_name": "John Smith", "user_username": "jsmith", "user_email": "john@example.com", "user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80", "project_id": 15, "project":{ "id": 15, "name":"Diaspora", "description":"", "web_url":"http://example.com/mike/diaspora", "avatar_url":null, "git_ssh_url":"git@example.com:mike/diaspora.git", "git_http_url":"http://example.com/mike/diaspora.git", "namespace":"Mike", "visibility_level":0, "path_with_namespace":"mike/diaspora", "default_branch":"master", "homepage":"http://example.com/mike/diaspora", "url":"git@example.com:mike/diaspora.git", "ssh_url":"git@example.com:mike/diaspora.git", "http_url":"http://example.com/mike/diaspora.git" }, "repository":{ "name": "Diaspora", "url": "git@example.com:mike/diaspora.git", "description": "", "homepage": "http://example.com/mike/diaspora", "git_http_url":"http://example.com/mike/diaspora.git", "git_ssh_url":"git@example.com:mike/diaspora.git", "visibility_level":0 }, "commits": [ { "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", "message": "Update Catalan translation to e38cb41.", "timestamp": "2011-12-12T14:27:31+02:00", "url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", "author": { "name": "Jordi Mallach", "email": "jordi@softcatala.org" }, "added": ["CHANGELOG"], "modified": ["app/controller/application.rb"], "removed": [] }, { "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "message": "fixed readme", "timestamp": "2012-01-03T23:36:29+02:00", "url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "author": { "name": "GitLab dev user", "email": "gitlabdev@dv6700.(none)" }, "added": ["CHANGELOG"], "modified": ["app/controller/application.rb"], "removed": [] } ], "total_commits_count": 4 }` var event *PushEvent err := json.Unmarshal([]byte(jsonObject), &event) if err != nil { t.Errorf("Push Event can not unmarshaled: %v\n ", err.Error()) } if event == nil { t.Errorf("Push Event is null") } if event.ProjectID != 15 { t.Errorf("ProjectID is %v, want %v", event.ProjectID, 15) } if event.UserName != "John Smith" { t.Errorf("Username is %s, want %s", event.UserName, "John Smith") } if event.Commits[0] == nil || event.Commits[0].Timestamp == nil { t.Errorf("Commit Timestamp isn't nil") } if event.Commits[0] == nil || event.Commits[0].Author.Name != "Jordi Mallach" { t.Errorf("Commit Username is %s, want %s", event.UserName, "Jordi Mallach") } } func TestMergeEventUnmarshal(t *testing.T) { jsonObject := `{ "object_kind": "merge_request", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "project": { "id": 1, "name":"Gitlab Test", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/gitlabhq/gitlab-test", "avatar_url":null, "git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "git_http_url":"http://example.com/gitlabhq/gitlab-test.git", "namespace":"GitlabHQ", "visibility_level":20, "path_with_namespace":"gitlabhq/gitlab-test", "default_branch":"master", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"http://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", "http_url":"http://example.com/gitlabhq/gitlab-test.git" }, "repository": { "name": "Gitlab Test", "url": "http://example.com/gitlabhq/gitlab-test.git", "description": "Aut reprehenderit ut est.", "homepage": "http://example.com/gitlabhq/gitlab-test" }, "object_attributes": { "id": 99, "target_branch": "master", "source_branch": "ms-viewport", "source_project_id": 14, "author_id": 51, "assignee_id": 6, "title": "MS-Viewport", "created_at": "2013-12-03T17:23:34Z", "updated_at": "2013-12-03T17:23:34Z", "milestone_id": null, "state": "opened", "merge_status": "unchecked", "target_project_id": 14, "iid": 1, "description": "", "source": { "name":"Awesome Project", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/awesome_space/awesome_project", "avatar_url":null, "git_ssh_url":"git@example.com:awesome_space/awesome_project.git", "git_http_url":"http://example.com/awesome_space/awesome_project.git", "namespace":"Awesome Space", "visibility_level":20, "path_with_namespace":"awesome_space/awesome_project", "default_branch":"master", "homepage":"http://example.com/awesome_space/awesome_project", "url":"http://example.com/awesome_space/awesome_project.git", "ssh_url":"git@example.com:awesome_space/awesome_project.git", "http_url":"http://example.com/awesome_space/awesome_project.git" }, "target": { "name":"Awesome Project", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/awesome_space/awesome_project", "avatar_url":null, "git_ssh_url":"git@example.com:awesome_space/awesome_project.git", "git_http_url":"http://example.com/awesome_space/awesome_project.git", "namespace":"Awesome Space", "visibility_level":20, "path_with_namespace":"awesome_space/awesome_project", "default_branch":"master", "homepage":"http://example.com/awesome_space/awesome_project", "url":"http://example.com/awesome_space/awesome_project.git", "ssh_url":"git@example.com:awesome_space/awesome_project.git", "http_url":"http://example.com/awesome_space/awesome_project.git" }, "last_commit": { "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "message": "fixed readme", "timestamp": "2012-01-03T23:36:29+02:00", "url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "author": { "name": "GitLab dev user", "email": "gitlabdev@dv6700.(none)" } }, "work_in_progress": false, "url": "http://example.com/diaspora/merge_requests/1", "action": "open", "assignee": { "name": "User1", "username": "user1", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } }, "labels": [{ "id": 206, "title": "API", "color": "#ffffff", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "API related issues", "type": "ProjectLabel", "group_id": 41 }], "changes": { "updated_by_id": { "previous": null, "current": 1 }, "updated_at": { "previous": "2017-09-15 16:50:55 UTC", "current": "2017-09-15 16:52:00 UTC" }, "labels": { "previous": [{ "id": 206, "title": "API", "color": "#ffffff", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "API related issues", "type": "ProjectLabel", "group_id": 41 }], "current": [{ "id": 205, "title": "Platform", "color": "#123123", "project_id": 14, "created_at": "2013-12-03T17:15:43Z", "updated_at": "2013-12-03T17:15:43Z", "template": false, "description": "Platform related issues", "type": "ProjectLabel", "group_id": 41 }] }, "source_branch": { "previous": null, "current": "feature/test" }, "source_project_id": { "previous": null, "current": 1 }, "target_branch": { "previous": null, "current": "develop" }, "target_project_id": { "previous": null, "current": 1 }, "assignees": { "previous": [], "current": [ { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } ] }, "total_time_spent": { "previous": null, "current": 0 } } }` var event *MergeEvent err := json.Unmarshal([]byte(jsonObject), &event) if !assert.NoError(t, err, "Merge Event can not unmarshaled") { return } assert.Equal(t, 99, event.ObjectAttributes.ID) assert.Equal(t, "http://example.com/awesome_space/awesome_project", event.ObjectAttributes.Source.Homepage) assert.Equal(t, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", event.ObjectAttributes.LastCommit.ID) assert.Equal(t, "User1", event.ObjectAttributes.Assignee.Name) assert.Equal(t, "user1", event.ObjectAttributes.Assignee.Username) assert.Equal(t, "Administrator", event.User.Name) assert.NotNil(t, "Administrator", event.ObjectAttributes.LastCommit.Timestamp) assert.Equal(t, "GitLab dev user", event.ObjectAttributes.LastCommit.Author.Name) assert.Equal(t, "feature/test", event.Changes.SourceBranch.Current) assert.Empty(t, event.Changes.Assignees.Previous) if assert.NotEmpty(t, event.Changes.Assignees.Current) { assert.Equal(t, "Administrator", event.Changes.Assignees.Current[0].Name) } } func TestPipelineEventUnmarshal(t *testing.T) { jsonObject := `{ "object_kind": "pipeline", "object_attributes":{ "id": 31, "ref": "master", "tag": false, "sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", "before_sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", "status": "success", "stages":[ "build", "test", "deploy" ], "created_at": "2016-08-12 15:23:28 UTC", "finished_at": "2016-08-12 15:26:29 UTC", "duration": 63, "variables": [ { "key": "NESTOR_PROD_ENVIRONMENT", "value": "us-west-1" } ] }, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "project":{ "id": 1, "name": "Gitlab Test", "description": "Atque in sunt eos similique dolores voluptatem.", "web_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test", "avatar_url": null, "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", "git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", "namespace": "Gitlab Org", "visibility_level": 20, "path_with_namespace": "gitlab-org/gitlab-test", "default_branch": "master" }, "commit":{ "id": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", "message": "test\n", "timestamp": "2016-08-12T17:23:21+02:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2", "author":{ "name": "User", "email": "user@gitlab.com" } }, "builds":[ { "id": 380, "stage": "deploy", "name": "production", "status": "skipped", "created_at": "2016-08-12 15:23:28 UTC", "started_at": null, "finished_at": null, "when": "manual", "manual": true, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": null, "artifacts_file":{ "filename": null, "size": null } }, { "id": 377, "stage": "test", "name": "test-image", "status": "success", "created_at": "2016-08-12 15:23:28 UTC", "started_at": "2016-08-12 15:26:12 UTC", "finished_at": null, "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": { "id":380987, "description":"shared-runners-manager-6.gitlab.com", "active":true, "is_shared":true }, "artifacts_file":{ "filename": null, "size": null } }, { "id": 378, "stage": "test", "name": "test-build", "status": "success", "created_at": "2016-08-12 15:23:28 UTC", "started_at": "2016-08-12 15:26:12 UTC", "finished_at": "2016-08-12 15:26:29 UTC", "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": { "id":380987, "description":"shared-runners-manager-6.gitlab.com", "active":true, "is_shared":true }, "artifacts_file":{ "filename": null, "size": null } }, { "id": 376, "stage": "build", "name": "build-image", "status": "success", "created_at": "2016-08-12 15:23:28 UTC", "started_at": "2016-08-12 15:24:56 UTC", "finished_at": "2016-08-12 15:25:26 UTC", "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": { "id":380987, "description":"shared-runners-manager-6.gitlab.com", "active":true, "is_shared":true }, "artifacts_file":{ "filename": null, "size": null } }, { "id": 379, "stage": "deploy", "name": "staging", "status": "created", "created_at": "2016-08-12 15:23:28 UTC", "started_at": null, "finished_at": null, "when": "on_success", "manual": false, "user":{ "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon" }, "runner": null, "artifacts_file":{ "filename": null, "size": null } } ] }` var event *PipelineEvent err := json.Unmarshal([]byte(jsonObject), &event) if err != nil { t.Errorf("Pipeline Event can not unmarshaled: %v\n ", err.Error()) } if event == nil { t.Errorf("Pipeline Event is null") } if event.ObjectAttributes.ID != 31 { t.Errorf("ObjectAttributes is %v, want %v", event.ObjectAttributes.ID, 1977) } if event.User.Name == "" { t.Errorf("Username is %s, want %s", event.User.Name, "Administrator") } if event.Commit.Timestamp == nil { t.Errorf("Timestamp isn't nil") } if name := event.Commit.Author.Name; name != "User" { t.Errorf("Commit Username is %s, want %s", name, "User") } } func TestBuildEventUnmarshal(t *testing.T) { jsonObject := `{ "object_kind": "build", "ref": "gitlab-script-trigger", "tag": false, "before_sha": "2293ada6b400935a1378653304eaf6221e0fdb8f", "sha": "2293ada6b400935a1378653304eaf6221e0fdb8f", "build_id": 1977, "build_name": "test", "build_stage": "test", "build_status": "created", "build_started_at": null, "build_finished_at": null, "build_duration": null, "build_allow_failure": false, "build_failure_reason": "script_failure", "project_id": 380, "project_name": "gitlab-org/gitlab-test", "user": { "id": 3, "name": "User", "email": "user@gitlab.com" }, "commit": { "id": 2366, "sha": "2293ada6b400935a1378653304eaf6221e0fdb8f", "message": "test\n", "author_name": "User", "author_email": "user@gitlab.com", "status": "created", "duration": null, "started_at": null, "finished_at": null }, "repository": { "name": "gitlab_test", "description": "Atque in sunt eos similique dolores voluptatem.", "homepage": "http://192.168.64.1:3005/gitlab-org/gitlab-test", "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", "git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", "visibility_level": 20 } }` var event *BuildEvent err := json.Unmarshal([]byte(jsonObject), &event) if err != nil { t.Errorf("Build Event can not unmarshaled: %v\n ", err.Error()) } if event == nil { t.Errorf("Build Event is null") } if event.BuildID != 1977 { t.Errorf("BuildID is %v, want %v", event.BuildID, 1977) } } func TestMergeEventUnmarshalFromGroup(t *testing.T) { jsonObject := `{ "object_kind": "merge_request", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/d22738dc40839e3d95fca77ca3eac067?s=80\u0026d=identicon" }, "project": { "name": "example-project", "description": "", "web_url": "http://example.com/exm-namespace/example-project", "avatar_url": null, "git_ssh_url": "git@example.com:exm-namespace/example-project.git", "git_http_url": "http://example.com/exm-namespace/example-project.git", "namespace": "exm-namespace", "visibility": "public", "path_with_namespace": "exm-namespace/example-project", "default_branch": "master", "homepage": "http://example.com/exm-namespace/example-project", "url": "git@example.com:exm-namespace/example-project.git", "ssh_url": "git@example.com:exm-namespace/example-project.git", "http_url": "http://example.com/exm-namespace/example-project.git" }, "object_attributes": { "id": 15917, "target_branch ": "master ", "source_branch ": "source-branch-test ", "source_project_id ": 87, "author_id ": 15, "assignee_id ": 29, "title ": "source-branch-test ", "created_at ": "2016 - 12 - 01 13: 11: 10 UTC ", "updated_at ": "2016 - 12 - 01 13: 21: 20 UTC ", "milestone_id ": null, "state ": "merged ", "merge_status ": "can_be_merged ", "target_project_id ": 87, "iid ": 1402, "description ": "word doc support for e - ticket ", "position ": 0, "locked_at ": null, "updated_by_id ": null, "merge_error ": null, "merge_params": { "force_remove_source_branch": "0" }, "merge_when_build_succeeds": false, "merge_user_id": null, "merge_commit_sha": "ac3ca1559bc39abf963586372eff7f8fdded646e", "deleted_at": null, "approvals_before_merge": null, "rebase_commit_sha": null, "in_progress_merge_commit_sha": null, "lock_version": 0, "time_estimate": 0, "source": { "name": "example-project", "description": "", "web_url": "http://example.com/exm-namespace/example-project", "avatar_url": null, "git_ssh_url": "git@example.com:exm-namespace/example-project.git", "git_http_url": "http://example.com/exm-namespace/example-project.git", "namespace": "exm-namespace", "visibility": "public", "path_with_namespace": "exm-namespace/example-project", "default_branch": "master", "homepage": "http://example.com/exm-namespace/example-project", "url": "git@example.com:exm-namespace/example-project.git", "ssh_url": "git@example.com:exm-namespace/example-project.git", "http_url": "http://example.com/exm-namespace/example-project.git" }, "target": { "name": "example-project", "description": "", "web_url": "http://example.com/exm-namespace/example-project", "avatar_url": null, "git_ssh_url": "git@example.com:exm-namespace/example-project.git", "git_http_url": "http://example.com/exm-namespace/example-project.git", "namespace": "exm-namespace", "visibility": "public", "path_with_namespace": "exm-namespace/example-project", "default_branch": "master", "homepage": "http://example.com/exm-namespace/example-project", "url": "git@example.com:exm-namespace/example-project.git", "ssh_url": "git@example.com:exm-namespace/example-project.git", "http_url": "http://example.com/exm-namespace/example-project.git" }, "last_commit": { "id": "61b6a0d35dbaf915760233b637622e383d3cc9ec", "message": "commit message", "timestamp": "2016-12-01T15:07:53+02:00", "url": "http://example.com/exm-namespace/example-project/commit/61b6a0d35dbaf915760233b637622e383d3cc9ec", "author": { "name": "Test User", "email": "test.user@mail.com" } }, "work_in_progress": false, "url": "http://example.com/exm-namespace/example-project/merge_requests/1402", "action": "merge" }, "repository": { "name": "example-project", "url": "git@example.com:exm-namespace/example-project.git", "description": "", "homepage": "http://example.com/exm-namespace/example-project" }, "assignee": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/d22738dc40839e3d95fca77ca3eac067?s=80\u0026d=identicon" } }` var event *MergeEvent err := json.Unmarshal([]byte(jsonObject), &event) if err != nil { t.Errorf("Group Merge Event can not unmarshaled: %v\n ", err.Error()) } if event == nil { t.Errorf("Group Merge Event is null") } if event.ObjectKind != "merge_request" { t.Errorf("ObjectKind is %v, want %v", event.ObjectKind, "merge_request") } if event.User.Username != "root" { t.Errorf("User.Username is %v, want %v", event.User.Username, "root") } if event.Project.Name != "example-project" { t.Errorf("Project.Name is %v, want %v", event.Project.Name, "example-project") } if event.ObjectAttributes.ID != 15917 { t.Errorf("ObjectAttributes.ID is %v, want %v", event.ObjectAttributes.ID, 15917) } if event.ObjectAttributes.Source.Name != "example-project" { t.Errorf("ObjectAttributes.Source.Name is %v, want %v", event.ObjectAttributes.Source.Name, "example-project") } if event.ObjectAttributes.LastCommit.Author.Email != "test.user@mail.com" { t.Errorf("ObjectAttributes.LastCommit.Author.Email is %v, want %v", event.ObjectAttributes.LastCommit.Author.Email, "test.user@mail.com") } if event.Repository.Name != "example-project" { t.Errorf("Repository.Name is %v, want %v", event.Repository.Name, "example-project") } if event.Assignee.Username != "root" { t.Errorf("Assignee.Username is %v, want %v", event.Assignee, "root") } if event.User.Name == "" { t.Errorf("Username is %s, want %s", event.User.Name, "Administrator") } if event.ObjectAttributes.LastCommit.Timestamp == nil { t.Errorf("Timestamp isn't nil") } if name := event.ObjectAttributes.LastCommit.Author.Name; name != "Test User" { t.Errorf("Commit Username is %s, want %s", name, "Test User") } } golang-github-xanzy-go-gitlab-0.22.2/events.go000066400000000000000000000112771357140411500212020ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // EventsService handles communication with the event related methods of // the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/events.html type EventsService struct { client *Client } // ContributionEvent represents a user's contribution // // GitLab API docs: // https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events type ContributionEvent struct { Title string `json:"title"` ProjectID int `json:"project_id"` ActionName string `json:"action_name"` TargetID int `json:"target_id"` TargetIID int `json:"target_iid"` TargetType string `json:"target_type"` AuthorID int `json:"author_id"` TargetTitle string `json:"target_title"` CreatedAt *time.Time `json:"created_at"` PushData struct { CommitCount int `json:"commit_count"` Action string `json:"action"` RefType string `json:"ref_type"` CommitFrom string `json:"commit_from"` CommitTo string `json:"commit_to"` Ref string `json:"ref"` CommitTitle string `json:"commit_title"` } `json:"push_data"` Note *Note `json:"note"` Author struct { Name string `json:"name"` Username string `json:"username"` ID int `json:"id"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"author"` AuthorUsername string `json:"author_username"` } // ListContributionEventsOptions represents the options for GetUserContributionEvents // // GitLap API docs: // https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events type ListContributionEventsOptions struct { ListOptions Action *EventTypeValue `url:"action,omitempty" json:"action,omitempty"` TargetType *EventTargetTypeValue `url:"target_type,omitempty" json:"target_type,omitempty"` Before *ISOTime `url:"before,omitempty" json:"before,omitempty"` After *ISOTime `url:"after,omitempty" json:"after,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListUserContributionEvents retrieves user contribution events // for the specified user, sorted from newest to oldest. // // GitLab API docs: // https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events func (s *UsersService) ListUserContributionEvents(uid interface{}, opt *ListContributionEventsOptions, options ...OptionFunc) ([]*ContributionEvent, *Response, error) { user, err := parseID(uid) if err != nil { return nil, nil, err } u := fmt.Sprintf("users/%s/events", user) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var cs []*ContributionEvent resp, err := s.client.Do(req, &cs) if err != nil { return nil, resp, err } return cs, resp, err } // ListCurrentUserContributionEvents gets a list currently authenticated user's events // // GitLab API docs: https://docs.gitlab.com/ce/api/events.html#list-currently-authenticated-user-39-s-events func (s *EventsService) ListCurrentUserContributionEvents(opt *ListContributionEventsOptions, options ...OptionFunc) ([]*ContributionEvent, *Response, error) { req, err := s.client.NewRequest("GET", "events", opt, options) if err != nil { return nil, nil, err } var cs []*ContributionEvent resp, err := s.client.Do(req, &cs) if err != nil { return nil, resp, err } return cs, resp, err } // ListProjectVisibleEvents gets a list of visible events for a particular project // // GitLab API docs: https://docs.gitlab.com/ee/api/events.html#list-a-project-s-visible-events func (s *EventsService) ListProjectVisibleEvents(pid interface{}, opt *ListContributionEventsOptions, options ...OptionFunc) ([]*ContributionEvent, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/events", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var cs []*ContributionEvent resp, err := s.client.Do(req, &cs) if err != nil { return nil, resp, err } return cs, resp, err } golang-github-xanzy-go-gitlab-0.22.2/examples/000077500000000000000000000000001357140411500211555ustar00rootroot00000000000000golang-github-xanzy-go-gitlab-0.22.2/examples/basic_auth.go000066400000000000000000000007211357140411500236060ustar00rootroot00000000000000package main import ( "log" "github.com/xanzy/go-gitlab" ) // This example shows how to create a client with username and password. func basicAuthExample() { git, err := gitlab.NewBasicAuthClient(nil, "https://gitlab.company.com", "svanharmelen", "password") if err != nil { log.Fatal(err) } // List all projects projects, _, err := git.Projects.ListProjects(nil) if err != nil { log.Fatal(err) } log.Printf("Found %d projects", len(projects)) } golang-github-xanzy-go-gitlab-0.22.2/examples/impersonation.go000066400000000000000000000012441357140411500243740ustar00rootroot00000000000000package main import ( "log" "github.com/xanzy/go-gitlab" ) func impersonationExample() { git := gitlab.NewClient(nil, "yourtokengoeshere") uid := 1 //list impersonation token from an user tokens, _, err := git.Users.GetAllImpersonationTokens( uid, &gitlab.GetAllImpersonationTokensOptions{State: gitlab.String("active")}, ) if err != nil { panic(err) } for _, token := range tokens { log.Println(token.Token) } //create an impersonation token of an user token, _, err := git.Users.CreateImpersonationToken( uid, &gitlab.CreateImpersonationTokenOptions{Scopes: &[]string{"api"}}, ) if err != nil { panic(err) } log.Println(token.Token) } golang-github-xanzy-go-gitlab-0.22.2/examples/labels.go000066400000000000000000000012121357140411500227420ustar00rootroot00000000000000package main import ( "log" "github.com/xanzy/go-gitlab" ) func labelExample() { git := gitlab.NewClient(nil, "yourtokengoeshere") // Create new label l := &gitlab.CreateLabelOptions{ Name: gitlab.String("My Label"), Color: gitlab.String("#11FF22"), } label, _, err := git.Labels.CreateLabel("myname/myproject", l) if err != nil { log.Fatal(err) } log.Printf("Created label: %s\nWith color: %s\n", label.Name, label.Color) // List all labels labels, _, err := git.Labels.ListLabels("myname/myproject", nil) if err != nil { log.Fatal(err) } for _, label := range labels { log.Printf("Found label: %s", label.Name) } } golang-github-xanzy-go-gitlab-0.22.2/examples/languages.go000066400000000000000000000005221357140411500234510ustar00rootroot00000000000000package main import ( "log" "github.com/xanzy/go-gitlab" ) func languagesExample() { git := gitlab.NewClient(nil, "yourtokengoeshere") git.SetBaseURL("https://gitlab.com/api/v4") languages, _, err := git.Projects.GetProjectLanguages("2743054") if err != nil { log.Fatal(err) } log.Printf("Found languages: %v", languages) } golang-github-xanzy-go-gitlab-0.22.2/examples/main.go000066400000000000000000000003061357140411500224270ustar00rootroot00000000000000package main func main() { // See the separate files in this directory for the examples. This file is only // here to provide a main() function for the `example` package, keeping Travis happy. } golang-github-xanzy-go-gitlab-0.22.2/examples/pagination.go000066400000000000000000000012711357140411500236360ustar00rootroot00000000000000package main import ( "fmt" "log" "github.com/xanzy/go-gitlab" ) func pagination() { git := gitlab.NewClient(nil, "yourtokengoeshere") opt := &gitlab.ListProjectsOptions{ ListOptions: gitlab.ListOptions{ PerPage: 10, Page: 1, }, } for { // Get the first page with projects. ps, resp, err := git.Projects.ListProjects(opt) if err != nil { log.Fatal(err) } // List all the projects we've found so far. for _, p := range ps { fmt.Printf("Found project: %s", p.Name) } // Exit the loop when we've seen all pages. if resp.CurrentPage >= resp.TotalPages { break } // Update the page number to get the next page. opt.Page = resp.NextPage } } golang-github-xanzy-go-gitlab-0.22.2/examples/pipelines.go000066400000000000000000000013531357140411500234760ustar00rootroot00000000000000package main import ( "log" "github.com/xanzy/go-gitlab" ) func pipelineExample() { git := gitlab.NewClient(nil, "yourtokengoeshere") git.SetBaseURL("https://gitlab.com/api/v4") opt := &gitlab.ListProjectPipelinesOptions{ Scope: gitlab.String("branches"), Status: gitlab.BuildState(gitlab.Running), Ref: gitlab.String("master"), YamlErrors: gitlab.Bool(true), Name: gitlab.String("name"), Username: gitlab.String("username"), OrderBy: gitlab.String("status"), Sort: gitlab.String("asc"), } pipelines, _, err := git.Pipelines.ListProjectPipelines(2743054, opt) if err != nil { log.Fatal(err) } for _, pipeline := range pipelines { log.Printf("Found pipeline: %v", pipeline) } } golang-github-xanzy-go-gitlab-0.22.2/examples/projects.go000066400000000000000000000022751357140411500233430ustar00rootroot00000000000000package main import ( "log" "github.com/xanzy/go-gitlab" ) func projectExample() { git := gitlab.NewClient(nil, "yourtokengoeshere") // Create new project p := &gitlab.CreateProjectOptions{ Name: gitlab.String("My Project"), Description: gitlab.String("Just a test project to play with"), MergeRequestsEnabled: gitlab.Bool(true), SnippetsEnabled: gitlab.Bool(true), Visibility: gitlab.Visibility(gitlab.PublicVisibility), } project, _, err := git.Projects.CreateProject(p) if err != nil { log.Fatal(err) } // Add a new snippet s := &gitlab.CreateProjectSnippetOptions{ Title: gitlab.String("Dummy Snippet"), FileName: gitlab.String("snippet.go"), Code: gitlab.String("package main...."), Visibility: gitlab.Visibility(gitlab.PublicVisibility), } _, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s) if err != nil { log.Fatal(err) } // List all project snippets snippets, _, err := git.ProjectSnippets.ListSnippets(project.PathWithNamespace, &gitlab.ListProjectSnippetsOptions{}) if err != nil { log.Fatal(err) } for _, snippet := range snippets { log.Printf("Found snippet: %s", snippet.Title) } } golang-github-xanzy-go-gitlab-0.22.2/examples/repository_files.go000066400000000000000000000020241357140411500251030ustar00rootroot00000000000000package main import ( "log" "github.com/xanzy/go-gitlab" ) func repositoryFileExample() { git := gitlab.NewClient(nil, "yourtokengoeshere") // Create a new repository file cf := &gitlab.CreateFileOptions{ Branch: gitlab.String("master"), Content: gitlab.String("My file contents"), CommitMessage: gitlab.String("Adding a test file"), } file, _, err := git.RepositoryFiles.CreateFile("myname/myproject", "file.go", cf) if err != nil { log.Fatal(err) } // Update a repository file uf := &gitlab.UpdateFileOptions{ Branch: gitlab.String("master"), Content: gitlab.String("My file content"), CommitMessage: gitlab.String("Fixing typo"), } _, _, err = git.RepositoryFiles.UpdateFile("myname/myproject", file.FilePath, uf) if err != nil { log.Fatal(err) } gf := &gitlab.GetFileOptions{ Ref: gitlab.String("master"), } f, _, err := git.RepositoryFiles.GetFile("myname/myproject", file.FilePath, gf) if err != nil { log.Fatal(err) } log.Printf("File contains: %s", f.Content) } golang-github-xanzy-go-gitlab-0.22.2/feature_flags.go000066400000000000000000000034741357140411500225050ustar00rootroot00000000000000package gitlab import ( "fmt" "net/url" ) // FeaturesService handles the communication with the application FeaturesService // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/features.html type FeaturesService struct { client *Client } // Feature represents a GitLab feature flag. // // GitLab API docs: https://docs.gitlab.com/ce/api/features.html type Feature struct { Name string `json:"name"` State string `json:"state"` Gates []Gate } // Gate represents a gate of a GitLab feature flag. // // GitLab API docs: https://docs.gitlab.com/ce/api/features.html type Gate struct { Key string `json:"key"` Value interface{} `json:"value"` } func (f Feature) String() string { return Stringify(f) } // ListFeatures gets a list of feature flags // // GitLab API docs: // https://docs.gitlab.com/ce/api/features.html#list-all-features func (s *FeaturesService) ListFeatures(options ...OptionFunc) ([]*Feature, *Response, error) { req, err := s.client.NewRequest("GET", "features", nil, options) if err != nil { return nil, nil, err } var f []*Feature resp, err := s.client.Do(req, &f) if err != nil { return nil, resp, err } return f, resp, err } // SetFeatureFlag sets or creates a feature flag gate // // GitLab API docs: // https://docs.gitlab.com/ce/api/features.html#set-or-create-a-feature func (s *FeaturesService) SetFeatureFlag(name string, value interface{}, options ...OptionFunc) (*Feature, *Response, error) { u := fmt.Sprintf("features/%s", url.PathEscape(name)) opt := struct { Value interface{} `url:"value" json:"value"` }{ value, } req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } f := &Feature{} resp, err := s.client.Do(req, f) if err != nil { return nil, resp, err } return f, resp, err } golang-github-xanzy-go-gitlab-0.22.2/feature_flags_test.go000066400000000000000000000034541357140411500235420ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestListFeatureFlags(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/features", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, ` [ { "name": "experimental_feature", "state": "off", "gates": [ { "key": "boolean", "value": false } ] }, { "name": "new_library", "state": "on" } ] `) }) features, _, err := client.Features.ListFeatures() if err != nil { t.Errorf("Features.ListFeatures returned error: %v", err) } want := []*Feature{ {Name: "experimental_feature", State: "off", Gates: []Gate{ {Key: "boolean", Value: false}, }}, {Name: "new_library", State: "on"}, } if !reflect.DeepEqual(want, features) { t.Errorf("Features.ListFeatures returned %+v, want %+v", features, want) } } func TestSetFeatureFlag(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/features/new_library", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, ` { "name": "new_library", "state": "conditional", "gates": [ { "key": "boolean", "value": false }, { "key": "percentage_of_time", "value": 30 } ] } `) }) feature, _, err := client.Features.SetFeatureFlag("new_library", "30") if err != nil { t.Errorf("Features.SetFeatureFlag returned error: %v", err) } want := &Feature{ Name: "new_library", State: "conditional", Gates: []Gate{ {Key: "boolean", Value: false}, {Key: "percentage_of_time", Value: 30.0}, }, } if !reflect.DeepEqual(want, feature) { t.Errorf("Features.SetFeatureFlag returned %+v, want %+v", feature, want) } } golang-github-xanzy-go-gitlab-0.22.2/gitignore_templates.go000066400000000000000000000047211357140411500237370ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/url" ) // GitIgnoreTemplatesService handles communication with the gitignore // templates related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html type GitIgnoreTemplatesService struct { client *Client } // GitIgnoreTemplate represents a GitLab gitignore template. // // GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html type GitIgnoreTemplate struct { Name string `json:"name"` Content string `json:"content"` } // ListTemplatesOptions represents the available ListAllTemplates() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates type ListTemplatesOptions ListOptions // ListTemplates get a list of available git ignore templates // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates func (s *GitIgnoreTemplatesService) ListTemplates(opt *ListTemplatesOptions, options ...OptionFunc) ([]*GitIgnoreTemplate, *Response, error) { req, err := s.client.NewRequest("GET", "templates/gitignores", opt, options) if err != nil { return nil, nil, err } var gs []*GitIgnoreTemplate resp, err := s.client.Do(req, &gs) if err != nil { return nil, resp, err } return gs, resp, err } // GetTemplate get a git ignore template // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/gitignores.html#single-gitignore-template func (s *GitIgnoreTemplatesService) GetTemplate(key string, options ...OptionFunc) (*GitIgnoreTemplate, *Response, error) { u := fmt.Sprintf("templates/gitignores/%s", url.PathEscape(key)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } g := new(GitIgnoreTemplate) resp, err := s.client.Do(req, g) if err != nil { return nil, resp, err } return g, resp, err } golang-github-xanzy-go-gitlab-0.22.2/gitlab.go000066400000000000000000000701531357140411500211360ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Package gitlab implements a GitLab API client. package gitlab import ( "bytes" "context" "encoding/json" "errors" "fmt" "io" "io/ioutil" "net/http" "net/url" "sort" "strconv" "strings" "time" "github.com/google/go-querystring/query" "golang.org/x/oauth2" ) const ( defaultBaseURL = "https://gitlab.com/" apiVersionPath = "api/v4/" userAgent = "go-gitlab" ) // authType represents an authentication type within GitLab. // // GitLab API docs: https://docs.gitlab.com/ce/api/ type authType int // List of available authentication types. // // GitLab API docs: https://docs.gitlab.com/ce/api/ const ( basicAuth authType = iota oAuthToken privateToken ) // AccessLevelValue represents a permission level within GitLab. // // GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html type AccessLevelValue int // List of available access levels // // GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html const ( NoPermissions AccessLevelValue = 0 GuestPermissions AccessLevelValue = 10 ReporterPermissions AccessLevelValue = 20 DeveloperPermissions AccessLevelValue = 30 MaintainerPermissions AccessLevelValue = 40 OwnerPermissions AccessLevelValue = 50 // These are deprecated and should be removed in a future version MasterPermissions AccessLevelValue = 40 OwnerPermission AccessLevelValue = 50 ) // BuildStateValue represents a GitLab build state. type BuildStateValue string // These constants represent all valid build states. const ( Pending BuildStateValue = "pending" Running BuildStateValue = "running" Success BuildStateValue = "success" Failed BuildStateValue = "failed" Canceled BuildStateValue = "canceled" Skipped BuildStateValue = "skipped" Manual BuildStateValue = "manual" ) // ISOTime represents an ISO 8601 formatted date type ISOTime time.Time // ISO 8601 date format const iso8601 = "2006-01-02" // MarshalJSON implements the json.Marshaler interface func (t ISOTime) MarshalJSON() ([]byte, error) { if y := time.Time(t).Year(); y < 0 || y >= 10000 { // ISO 8901 uses 4 digits for the years return nil, errors.New("json: ISOTime year outside of range [0,9999]") } b := make([]byte, 0, len(iso8601)+2) b = append(b, '"') b = time.Time(t).AppendFormat(b, iso8601) b = append(b, '"') return b, nil } // UnmarshalJSON implements the json.Unmarshaler interface func (t *ISOTime) UnmarshalJSON(data []byte) error { // Ignore null, like in the main JSON package if string(data) == "null" { return nil } isotime, err := time.Parse(`"`+iso8601+`"`, string(data)) *t = ISOTime(isotime) return err } // EncodeValues implements the query.Encoder interface func (t *ISOTime) EncodeValues(key string, v *url.Values) error { if t == nil || (time.Time(*t)).IsZero() { return nil } v.Add(key, t.String()) return nil } // String implements the Stringer interface func (t ISOTime) String() string { return time.Time(t).Format(iso8601) } // NotificationLevelValue represents a notification level. type NotificationLevelValue int // String implements the fmt.Stringer interface. func (l NotificationLevelValue) String() string { return notificationLevelNames[l] } // MarshalJSON implements the json.Marshaler interface. func (l NotificationLevelValue) MarshalJSON() ([]byte, error) { return json.Marshal(l.String()) } // UnmarshalJSON implements the json.Unmarshaler interface. func (l *NotificationLevelValue) UnmarshalJSON(data []byte) error { var raw interface{} if err := json.Unmarshal(data, &raw); err != nil { return err } switch raw := raw.(type) { case float64: *l = NotificationLevelValue(raw) case string: *l = notificationLevelTypes[raw] case nil: // No action needed. default: return fmt.Errorf("json: cannot unmarshal %T into Go value of type %T", raw, *l) } return nil } // List of valid notification levels. const ( DisabledNotificationLevel NotificationLevelValue = iota ParticipatingNotificationLevel WatchNotificationLevel GlobalNotificationLevel MentionNotificationLevel CustomNotificationLevel ) var notificationLevelNames = [...]string{ "disabled", "participating", "watch", "global", "mention", "custom", } var notificationLevelTypes = map[string]NotificationLevelValue{ "disabled": DisabledNotificationLevel, "participating": ParticipatingNotificationLevel, "watch": WatchNotificationLevel, "global": GlobalNotificationLevel, "mention": MentionNotificationLevel, "custom": CustomNotificationLevel, } // VisibilityValue represents a visibility level within GitLab. // // GitLab API docs: https://docs.gitlab.com/ce/api/ type VisibilityValue string // List of available visibility levels. // // GitLab API docs: https://docs.gitlab.com/ce/api/ const ( PrivateVisibility VisibilityValue = "private" InternalVisibility VisibilityValue = "internal" PublicVisibility VisibilityValue = "public" ) // VariableTypeValue represents a variable type within GitLab. // // GitLab API docs: https://docs.gitlab.com/ce/api/ type VariableTypeValue string // List of available variable types. // // GitLab API docs: https://docs.gitlab.com/ce/api/ const ( EnvVariableType VariableTypeValue = "env_var" FileVariableType VariableTypeValue = "file" ) // MergeMethodValue represents a project merge type within GitLab. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#project-merge-method type MergeMethodValue string // List of available merge type // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#project-merge-method const ( NoFastForwardMerge MergeMethodValue = "merge" FastForwardMerge MergeMethodValue = "ff" RebaseMerge MergeMethodValue = "rebase_merge" ) // EventTypeValue represents actions type for contribution events type EventTypeValue string // List of available action type // // GitLab API docs: https://docs.gitlab.com/ce/api/events.html#action-types const ( CreatedEventType EventTypeValue = "created" UpdatedEventType EventTypeValue = "updated" ClosedEventType EventTypeValue = "closed" ReopenedEventType EventTypeValue = "reopened" PushedEventType EventTypeValue = "pushed" CommentedEventType EventTypeValue = "commented" MergedEventType EventTypeValue = "merged" JoinedEventType EventTypeValue = "joined" LeftEventType EventTypeValue = "left" DestroyedEventType EventTypeValue = "destroyed" ExpiredEventType EventTypeValue = "expired" ) // EventTargetTypeValue represents actions type value for contribution events type EventTargetTypeValue string // List of available action type // // GitLab API docs: https://docs.gitlab.com/ce/api/events.html#target-types const ( IssueEventTargetType EventTargetTypeValue = "issue" MilestoneEventTargetType EventTargetTypeValue = "milestone" MergeRequestEventTargetType EventTargetTypeValue = "merge_request" NoteEventTargetType EventTargetTypeValue = "note" ProjectEventTargetType EventTargetTypeValue = "project" SnippetEventTargetType EventTargetTypeValue = "snippet" UserEventTargetType EventTargetTypeValue = "user" ) // A Client manages communication with the GitLab API. type Client struct { // HTTP client used to communicate with the API. client *http.Client // Base URL for API requests. Defaults to the public GitLab API, but can be // set to a domain endpoint to use with a self hosted GitLab server. baseURL // should always be specified with a trailing slash. baseURL *url.URL // Token type used to make authenticated API calls. authType authType // Username and password used for basix authentication. username, password string // Token used to make authenticated API calls. token string // User agent used when communicating with the GitLab API. UserAgent string // Services used for talking to different parts of the GitLab API. AccessRequests *AccessRequestsService AwardEmoji *AwardEmojiService Boards *IssueBoardsService Branches *BranchesService BroadcastMessage *BroadcastMessagesService CIYMLTemplate *CIYMLTemplatesService Commits *CommitsService ContainerRegistry *ContainerRegistryService CustomAttribute *CustomAttributesService DeployKeys *DeployKeysService Deployments *DeploymentsService Discussions *DiscussionsService Environments *EnvironmentsService Epics *EpicsService Events *EventsService Features *FeaturesService GitIgnoreTemplates *GitIgnoreTemplatesService GroupBadges *GroupBadgesService GroupCluster *GroupClustersService GroupIssueBoards *GroupIssueBoardsService GroupLabels *GroupLabelsService GroupMembers *GroupMembersService GroupMilestones *GroupMilestonesService GroupVariables *GroupVariablesService Groups *GroupsService IssueLinks *IssueLinksService Issues *IssuesService Jobs *JobsService Keys *KeysService Labels *LabelsService License *LicenseService LicenseTemplates *LicenseTemplatesService MergeRequestApprovals *MergeRequestApprovalsService MergeRequests *MergeRequestsService Milestones *MilestonesService Namespaces *NamespacesService Notes *NotesService NotificationSettings *NotificationSettingsService PagesDomains *PagesDomainsService PipelineSchedules *PipelineSchedulesService PipelineTriggers *PipelineTriggersService Pipelines *PipelinesService ProjectBadges *ProjectBadgesService ProjectCluster *ProjectClustersService ProjectImportExport *ProjectImportExportService ProjectMembers *ProjectMembersService ProjectSnippets *ProjectSnippetsService ProjectVariables *ProjectVariablesService Projects *ProjectsService ProtectedBranches *ProtectedBranchesService ProtectedTags *ProtectedTagsService ReleaseLinks *ReleaseLinksService Releases *ReleasesService Repositories *RepositoriesService RepositoryFiles *RepositoryFilesService ResourceLabelEvents *ResourceLabelEventsService Runners *RunnersService Search *SearchService Services *ServicesService Settings *SettingsService Sidekiq *SidekiqService Snippets *SnippetsService SystemHooks *SystemHooksService Tags *TagsService Todos *TodosService Users *UsersService Validate *ValidateService Version *VersionService Wikis *WikisService } // ListOptions specifies the optional parameters to various List methods that // support pagination. type ListOptions struct { // For paginated result sets, page of results to retrieve. Page int `url:"page,omitempty" json:"page,omitempty"` // For paginated result sets, the number of results to include per page. PerPage int `url:"per_page,omitempty" json:"per_page,omitempty"` } // NewClient returns a new GitLab API client. If a nil httpClient is // provided, http.DefaultClient will be used. To use API methods which require // authentication, provide a valid private or personal token. func NewClient(httpClient *http.Client, token string) *Client { client := newClient(httpClient) client.authType = privateToken client.token = token return client } // NewBasicAuthClient returns a new GitLab API client. If a nil httpClient is // provided, http.DefaultClient will be used. To use API methods which require // authentication, provide a valid username and password. func NewBasicAuthClient(httpClient *http.Client, endpoint, username, password string) (*Client, error) { client := newClient(httpClient) client.authType = basicAuth client.username = username client.password = password client.SetBaseURL(endpoint) err := client.requestOAuthToken(context.TODO()) if err != nil { return nil, err } return client, nil } func (c *Client) requestOAuthToken(ctx context.Context) error { config := &oauth2.Config{ Endpoint: oauth2.Endpoint{ AuthURL: fmt.Sprintf("%s://%s/oauth/authorize", c.BaseURL().Scheme, c.BaseURL().Host), TokenURL: fmt.Sprintf("%s://%s/oauth/token", c.BaseURL().Scheme, c.BaseURL().Host), }, } ctx = context.WithValue(ctx, oauth2.HTTPClient, c.client) t, err := config.PasswordCredentialsToken(ctx, c.username, c.password) if err != nil { return err } c.token = t.AccessToken return nil } // NewOAuthClient returns a new GitLab API client. If a nil httpClient is // provided, http.DefaultClient will be used. To use API methods which require // authentication, provide a valid oauth token. func NewOAuthClient(httpClient *http.Client, token string) *Client { client := newClient(httpClient) client.authType = oAuthToken client.token = token return client } func newClient(httpClient *http.Client) *Client { if httpClient == nil { httpClient = http.DefaultClient } c := &Client{client: httpClient, UserAgent: userAgent} if err := c.SetBaseURL(defaultBaseURL); err != nil { // Should never happen since defaultBaseURL is our constant. panic(err) } // Create the internal timeStats service. timeStats := &timeStatsService{client: c} // Create all the public services. c.AccessRequests = &AccessRequestsService{client: c} c.AwardEmoji = &AwardEmojiService{client: c} c.Boards = &IssueBoardsService{client: c} c.Branches = &BranchesService{client: c} c.BroadcastMessage = &BroadcastMessagesService{client: c} c.CIYMLTemplate = &CIYMLTemplatesService{client: c} c.Commits = &CommitsService{client: c} c.ContainerRegistry = &ContainerRegistryService{client: c} c.CustomAttribute = &CustomAttributesService{client: c} c.DeployKeys = &DeployKeysService{client: c} c.Deployments = &DeploymentsService{client: c} c.Discussions = &DiscussionsService{client: c} c.Environments = &EnvironmentsService{client: c} c.Epics = &EpicsService{client: c} c.Events = &EventsService{client: c} c.Features = &FeaturesService{client: c} c.GitIgnoreTemplates = &GitIgnoreTemplatesService{client: c} c.GroupBadges = &GroupBadgesService{client: c} c.GroupCluster = &GroupClustersService{client: c} c.GroupIssueBoards = &GroupIssueBoardsService{client: c} c.GroupLabels = &GroupLabelsService{client: c} c.GroupMembers = &GroupMembersService{client: c} c.GroupMilestones = &GroupMilestonesService{client: c} c.GroupVariables = &GroupVariablesService{client: c} c.Groups = &GroupsService{client: c} c.IssueLinks = &IssueLinksService{client: c} c.Issues = &IssuesService{client: c, timeStats: timeStats} c.Jobs = &JobsService{client: c} c.Keys = &KeysService{client: c} c.Labels = &LabelsService{client: c} c.License = &LicenseService{client: c} c.LicenseTemplates = &LicenseTemplatesService{client: c} c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c} c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats} c.Milestones = &MilestonesService{client: c} c.Namespaces = &NamespacesService{client: c} c.Notes = &NotesService{client: c} c.NotificationSettings = &NotificationSettingsService{client: c} c.PagesDomains = &PagesDomainsService{client: c} c.PipelineSchedules = &PipelineSchedulesService{client: c} c.PipelineTriggers = &PipelineTriggersService{client: c} c.Pipelines = &PipelinesService{client: c} c.ProjectBadges = &ProjectBadgesService{client: c} c.ProjectCluster = &ProjectClustersService{client: c} c.ProjectImportExport = &ProjectImportExportService{client: c} c.ProjectMembers = &ProjectMembersService{client: c} c.ProjectSnippets = &ProjectSnippetsService{client: c} c.ProjectVariables = &ProjectVariablesService{client: c} c.Projects = &ProjectsService{client: c} c.ProtectedBranches = &ProtectedBranchesService{client: c} c.ProtectedTags = &ProtectedTagsService{client: c} c.ReleaseLinks = &ReleaseLinksService{client: c} c.Releases = &ReleasesService{client: c} c.Repositories = &RepositoriesService{client: c} c.RepositoryFiles = &RepositoryFilesService{client: c} c.ResourceLabelEvents = &ResourceLabelEventsService{client: c} c.Runners = &RunnersService{client: c} c.Search = &SearchService{client: c} c.Services = &ServicesService{client: c} c.Settings = &SettingsService{client: c} c.Sidekiq = &SidekiqService{client: c} c.Snippets = &SnippetsService{client: c} c.SystemHooks = &SystemHooksService{client: c} c.Tags = &TagsService{client: c} c.Todos = &TodosService{client: c} c.Users = &UsersService{client: c} c.Validate = &ValidateService{client: c} c.Version = &VersionService{client: c} c.Wikis = &WikisService{client: c} return c } // BaseURL return a copy of the baseURL. func (c *Client) BaseURL() *url.URL { u := *c.baseURL return &u } // SetBaseURL sets the base URL for API requests to a custom endpoint. urlStr // should always be specified with a trailing slash. func (c *Client) SetBaseURL(urlStr string) error { // Make sure the given URL end with a slash if !strings.HasSuffix(urlStr, "/") { urlStr += "/" } baseURL, err := url.Parse(urlStr) if err != nil { return err } if !strings.HasSuffix(baseURL.Path, apiVersionPath) { baseURL.Path += apiVersionPath } // Update the base URL of the client. c.baseURL = baseURL return nil } // NewRequest creates an API request. A relative URL path can be provided in // urlStr, in which case it is resolved relative to the base URL of the Client. // Relative URL paths should always be specified without a preceding slash. If // specified, the value pointed to by body is JSON encoded and included as the // request body. func (c *Client) NewRequest(method, path string, opt interface{}, options []OptionFunc) (*http.Request, error) { u := *c.baseURL unescaped, err := url.PathUnescape(path) if err != nil { return nil, err } // Set the encoded path data u.RawPath = c.baseURL.Path + path u.Path = c.baseURL.Path + unescaped if opt != nil { q, err := query.Values(opt) if err != nil { return nil, err } u.RawQuery = q.Encode() } req := &http.Request{ Method: method, URL: &u, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, Header: make(http.Header), Host: u.Host, } for _, fn := range options { if fn == nil { continue } if err := fn(req); err != nil { return nil, err } } if method == "POST" || method == "PUT" { bodyBytes, err := json.Marshal(opt) if err != nil { return nil, err } bodyReader := bytes.NewReader(bodyBytes) u.RawQuery = "" req.Body = ioutil.NopCloser(bodyReader) req.GetBody = func() (io.ReadCloser, error) { return ioutil.NopCloser(bodyReader), nil } req.ContentLength = int64(bodyReader.Len()) req.Header.Set("Content-Type", "application/json") } req.Header.Set("Accept", "application/json") switch c.authType { case basicAuth, oAuthToken: req.Header.Set("Authorization", "Bearer "+c.token) case privateToken: req.Header.Set("PRIVATE-TOKEN", c.token) } if c.UserAgent != "" { req.Header.Set("User-Agent", c.UserAgent) } return req, nil } // Response is a GitLab API response. This wraps the standard http.Response // returned from GitLab and provides convenient access to things like // pagination links. type Response struct { *http.Response // These fields provide the page values for paginating through a set of // results. Any or all of these may be set to the zero value for // responses that are not part of a paginated set, or for which there // are no additional pages. TotalItems int TotalPages int ItemsPerPage int CurrentPage int NextPage int PreviousPage int } // newResponse creates a new Response for the provided http.Response. func newResponse(r *http.Response) *Response { response := &Response{Response: r} response.populatePageValues() return response } const ( xTotal = "X-Total" xTotalPages = "X-Total-Pages" xPerPage = "X-Per-Page" xPage = "X-Page" xNextPage = "X-Next-Page" xPrevPage = "X-Prev-Page" ) // populatePageValues parses the HTTP Link response headers and populates the // various pagination link values in the Response. func (r *Response) populatePageValues() { if totalItems := r.Response.Header.Get(xTotal); totalItems != "" { r.TotalItems, _ = strconv.Atoi(totalItems) } if totalPages := r.Response.Header.Get(xTotalPages); totalPages != "" { r.TotalPages, _ = strconv.Atoi(totalPages) } if itemsPerPage := r.Response.Header.Get(xPerPage); itemsPerPage != "" { r.ItemsPerPage, _ = strconv.Atoi(itemsPerPage) } if currentPage := r.Response.Header.Get(xPage); currentPage != "" { r.CurrentPage, _ = strconv.Atoi(currentPage) } if nextPage := r.Response.Header.Get(xNextPage); nextPage != "" { r.NextPage, _ = strconv.Atoi(nextPage) } if previousPage := r.Response.Header.Get(xPrevPage); previousPage != "" { r.PreviousPage, _ = strconv.Atoi(previousPage) } } // Do sends an API request and returns the API response. The API response is // JSON decoded and stored in the value pointed to by v, or returned as an // error if an API error has occurred. If v implements the io.Writer // interface, the raw response body will be written to v, without attempting to // first decode it. func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { resp, err := c.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode == http.StatusUnauthorized && c.authType == basicAuth { err = c.requestOAuthToken(req.Context()) if err != nil { return nil, err } return c.Do(req, v) } response := newResponse(resp) err = CheckResponse(resp) if err != nil { // even though there was an error, we still return the response // in case the caller wants to inspect it further return response, err } if v != nil { if w, ok := v.(io.Writer); ok { _, err = io.Copy(w, resp.Body) } else { err = json.NewDecoder(resp.Body).Decode(v) } } return response, err } // Helper function to accept and format both the project ID or name as project // identifier for all API calls. func parseID(id interface{}) (string, error) { switch v := id.(type) { case int: return strconv.Itoa(v), nil case string: return v, nil default: return "", fmt.Errorf("invalid ID type %#v, the ID must be an int or a string", id) } } // Helper function to escape a project identifier. func pathEscape(s string) string { return strings.Replace(url.PathEscape(s), ".", "%2E", -1) } // An ErrorResponse reports one or more errors caused by an API request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/README.html#data-validation-and-error-reporting type ErrorResponse struct { Body []byte Response *http.Response Message string } func (e *ErrorResponse) Error() string { path, _ := url.QueryUnescape(e.Response.Request.URL.Path) u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, path) return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message) } // CheckResponse checks the API response for errors, and returns them if present. func CheckResponse(r *http.Response) error { switch r.StatusCode { case 200, 201, 202, 204, 304: return nil } errorResponse := &ErrorResponse{Response: r} data, err := ioutil.ReadAll(r.Body) if err == nil && data != nil { errorResponse.Body = data var raw interface{} if err := json.Unmarshal(data, &raw); err != nil { errorResponse.Message = "failed to parse unknown error format" } else { errorResponse.Message = parseError(raw) } } return errorResponse } // Format: // { // "message": { // "": [ // "", // "", // ... // ], // "": { // "": [ // "", // "", // ... // ], // } // }, // "error": "" // } func parseError(raw interface{}) string { switch raw := raw.(type) { case string: return raw case []interface{}: var errs []string for _, v := range raw { errs = append(errs, parseError(v)) } return fmt.Sprintf("[%s]", strings.Join(errs, ", ")) case map[string]interface{}: var errs []string for k, v := range raw { errs = append(errs, fmt.Sprintf("{%s: %s}", k, parseError(v))) } sort.Strings(errs) return strings.Join(errs, ", ") default: return fmt.Sprintf("failed to parse unexpected error type: %T", raw) } } // OptionFunc can be passed to all API requests to make the API call as if you were // another user, provided your private token is from an administrator account. // // GitLab docs: https://docs.gitlab.com/ce/api/README.html#sudo type OptionFunc func(*http.Request) error // WithSudo takes either a username or user ID and sets the SUDO request header func WithSudo(uid interface{}) OptionFunc { return func(req *http.Request) error { user, err := parseID(uid) if err != nil { return err } req.Header.Set("SUDO", user) return nil } } // WithContext runs the request with the provided context func WithContext(ctx context.Context) OptionFunc { return func(req *http.Request) error { *req = *req.WithContext(ctx) return nil } } // Bool is a helper routine that allocates a new bool value // to store v and returns a pointer to it. func Bool(v bool) *bool { p := new(bool) *p = v return p } // Int is a helper routine that allocates a new int32 value // to store v and returns a pointer to it, but unlike Int32 // its argument value is an int. func Int(v int) *int { p := new(int) *p = v return p } // String is a helper routine that allocates a new string value // to store v and returns a pointer to it. func String(v string) *string { p := new(string) *p = v return p } // Time is a helper routine that allocates a new time.Time value // to store v and returns a pointer to it. func Time(v time.Time) *time.Time { p := new(time.Time) *p = v return p } // AccessLevel is a helper routine that allocates a new AccessLevelValue // to store v and returns a pointer to it. func AccessLevel(v AccessLevelValue) *AccessLevelValue { p := new(AccessLevelValue) *p = v return p } // BuildState is a helper routine that allocates a new BuildStateValue // to store v and returns a pointer to it. func BuildState(v BuildStateValue) *BuildStateValue { p := new(BuildStateValue) *p = v return p } // NotificationLevel is a helper routine that allocates a new NotificationLevelValue // to store v and returns a pointer to it. func NotificationLevel(v NotificationLevelValue) *NotificationLevelValue { p := new(NotificationLevelValue) *p = v return p } // VariableType is a helper routine that allocates a new VariableTypeValue // to store v and returns a pointer to it. func VariableType(v VariableTypeValue) *VariableTypeValue { p := new(VariableTypeValue) *p = v return p } // Visibility is a helper routine that allocates a new VisibilityValue // to store v and returns a pointer to it. func Visibility(v VisibilityValue) *VisibilityValue { p := new(VisibilityValue) *p = v return p } // MergeMethod is a helper routine that allocates a new MergeMethod // to sotre v and returns a pointer to it. func MergeMethod(v MergeMethodValue) *MergeMethodValue { p := new(MergeMethodValue) *p = v return p } // BoolValue is a boolean value with advanced json unmarshaling features. type BoolValue bool // UnmarshalJSON allows 1 and 0 to be considered as boolean values // Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/50122 func (t *BoolValue) UnmarshalJSON(b []byte) error { switch string(b) { case `"1"`: *t = true return nil case `"0"`: *t = false return nil default: var v bool err := json.Unmarshal(b, &v) *t = BoolValue(v) return err } } golang-github-xanzy-go-gitlab-0.22.2/gitlab_test.go000066400000000000000000000111621357140411500221700ustar00rootroot00000000000000package gitlab import ( "bytes" "context" "encoding/json" "errors" "io" "io/ioutil" "net/http" "net/http/httptest" "os" "strings" "testing" ) // setup sets up a test HTTP server along with a gitlab.Client that is // configured to talk to that test server. Tests should register handlers on // mux which provide mock responses for the API method being tested. func setup() (*http.ServeMux, *httptest.Server, *Client) { // mux is the HTTP request multiplexer used with the test server. mux := http.NewServeMux() // server is a test HTTP server used to provide mock API responses. server := httptest.NewServer(mux) // client is the Gitlab client being tested. client := NewClient(nil, "") client.SetBaseURL(server.URL) return mux, server, client } // teardown closes the test HTTP server. func teardown(server *httptest.Server) { server.Close() } func testURL(t *testing.T, r *http.Request, want string) { if got := r.RequestURI; got != want { t.Errorf("Request url: %+v, want %s", got, want) } } func testMethod(t *testing.T, r *http.Request, want string) { if got := r.Method; got != want { t.Errorf("Request method: %s, want %s", got, want) } } func testBody(t *testing.T, r *http.Request, want string) { buffer := new(bytes.Buffer) _, err := buffer.ReadFrom(r.Body) if err != nil { t.Fatalf("Failed to Read Body: %v", err) } if got := buffer.String(); got != want { t.Errorf("Request body: %s, want %s", got, want) } } func mustWriteHTTPResponse(t *testing.T, w io.Writer, fixturePath string) { f, err := os.Open(fixturePath) if err != nil { t.Fatalf("error opening fixture file: %v", err) } if _, err = io.Copy(w, f); err != nil { t.Fatalf("error writing response: %v", err) } } func errorOption(*http.Request) error { return errors.New("OptionFunc returns an error") } func TestNewClient(t *testing.T) { c := NewClient(nil, "") expectedBaseURL := defaultBaseURL + apiVersionPath if c.BaseURL().String() != expectedBaseURL { t.Errorf("NewClient BaseURL is %s, want %s", c.BaseURL().String(), expectedBaseURL) } if c.UserAgent != userAgent { t.Errorf("NewClient UserAgent is %s, want %s", c.UserAgent, userAgent) } } func TestSetBaseURL(t *testing.T) { expectedBaseURL := "http://gitlab.local/foo/" + apiVersionPath c := NewClient(nil, "") err := c.SetBaseURL("http://gitlab.local/foo") if err != nil { t.Fatalf("Failed to SetBaseURL: %v", err) } if c.BaseURL().String() != expectedBaseURL { t.Errorf("BaseURL is %s, want %s", c.BaseURL().String(), expectedBaseURL) } } func TestCheckResponse(t *testing.T) { req, err := NewClient(nil, "").NewRequest("GET", "test", nil, nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } resp := &http.Response{ Request: req, StatusCode: http.StatusBadRequest, Body: ioutil.NopCloser(strings.NewReader(` { "message": { "prop1": [ "message 1", "message 2" ], "prop2":[ "message 3" ], "embed1": { "prop3": [ "msg 1", "msg2" ] }, "embed2": { "prop4": [ "some msg" ] } }, "error": "message 1" }`)), } errResp := CheckResponse(resp) if errResp == nil { t.Fatal("Expected error response.") } want := "GET https://gitlab.com/api/v4/test: 400 {error: message 1}, {message: {embed1: {prop3: [msg 1, msg2]}}, {embed2: {prop4: [some msg]}}, {prop1: [message 1, message 2]}, {prop2: [message 3]}}" if errResp.Error() != want { t.Errorf("Expected error: %s, got %s", want, errResp.Error()) } } func TestRequestWithContext(t *testing.T) { ctx := context.WithValue(context.Background(), interface{}("myKey"), interface{}("myValue")) req, err := NewClient(nil, "").NewRequest("GET", "test", nil, []OptionFunc{WithContext(ctx)}) if err != nil { t.Fatalf("Failed to create request: %v", err) } if req.Context() != ctx { t.Fatal("Context was not set correctly") } } func TestBoolValue(t *testing.T) { testCases := map[string]struct { data []byte expected bool }{ "should unmarshal true as true": { data: []byte("true"), expected: true, }, "should unmarshal false as true": { data: []byte("false"), expected: false, }, "should unmarshal \"1\" as true": { data: []byte(`"1"`), expected: true, }, "should unmarshal \"0\" as false": { data: []byte(`"0"`), expected: false, }, } for name, testCase := range testCases { t.Run(name, func(t *testing.T) { var b BoolValue if err := json.Unmarshal(testCase.data, &b); err != nil { t.Fatalf("Unexpected error: %v", err) } if bool(b) != testCase.expected { t.Fatalf("Expected %v but got %v", testCase.expected, b) } }) } } golang-github-xanzy-go-gitlab-0.22.2/go.mod000066400000000000000000000005601357140411500204460ustar00rootroot00000000000000module github.com/xanzy/go-gitlab require ( github.com/google/go-querystring v1.0.0 github.com/stretchr/testify v1.4.0 golang.org/x/net v0.0.0-20181108082009-03003ca0c849 // indirect golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect google.golang.org/appengine v1.3.0 // indirect ) go 1.13 golang-github-xanzy-go-gitlab-0.22.2/go.sum000066400000000000000000000044071357140411500204770ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849 h1:FSqE2GGG7wzsYUsWiQ8MZrvEd1EOyU3NCF0AW3Wtltg= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= golang-github-xanzy-go-gitlab-0.22.2/group_badges.go000066400000000000000000000136341357140411500223360ustar00rootroot00000000000000package gitlab import ( "fmt" ) // GroupBadgesService handles communication with the group badges // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html type GroupBadgesService struct { client *Client } // BadgeKind represents a GitLab Badge Kind type BadgeKind string // all possible values Badge Kind const ( ProjectBadgeKind BadgeKind = "project" GroupBadgeKind BadgeKind = "group" ) // GroupBadge represents a group badge. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html type GroupBadge struct { ID int `json:"id"` LinkURL string `json:"link_url"` ImageURL string `json:"image_url"` RenderedLinkURL string `json:"rendered_link_url"` RenderedImageURL string `json:"rendered_image_url"` Kind BadgeKind `json:"kind"` } // ListGroupBadgesOptions represents the available ListGroupBadges() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group type ListGroupBadgesOptions ListOptions // ListGroupBadges gets a list of a group badges. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group func (s *GroupBadgesService) ListGroupBadges(gid interface{}, opt *ListGroupBadgesOptions, options ...OptionFunc) ([]*GroupBadge, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/badges", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var gb []*GroupBadge resp, err := s.client.Do(req, &gb) if err != nil { return nil, resp, err } return gb, resp, err } // GetGroupBadge gets a group badge. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#get-a-badge-of-a-group func (s *GroupBadgesService) GetGroupBadge(gid interface{}, badge int, options ...OptionFunc) (*GroupBadge, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } gb := new(GroupBadge) resp, err := s.client.Do(req, gb) if err != nil { return nil, resp, err } return gb, resp, err } // AddGroupBadgeOptions represents the available AddGroupBadge() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group type AddGroupBadgeOptions struct { LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` } // AddGroupBadge adds a badge to a group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group func (s *GroupBadgesService) AddGroupBadge(gid interface{}, opt *AddGroupBadgeOptions, options ...OptionFunc) (*GroupBadge, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/badges", pathEscape(group)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } gb := new(GroupBadge) resp, err := s.client.Do(req, gb) if err != nil { return nil, resp, err } return gb, resp, err } // EditGroupBadgeOptions represents the available EditGroupBadge() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group type EditGroupBadgeOptions struct { LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` } // EditGroupBadge updates a badge of a group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group func (s *GroupBadgesService) EditGroupBadge(gid interface{}, badge int, opt *EditGroupBadgeOptions, options ...OptionFunc) (*GroupBadge, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } gb := new(GroupBadge) resp, err := s.client.Do(req, gb) if err != nil { return nil, resp, err } return gb, resp, err } // DeleteGroupBadge removes a badge from a group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#remove-a-badge-from-a-group func (s *GroupBadgesService) DeleteGroupBadge(gid interface{}, badge int, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // GroupBadgePreviewOptions represents the available PreviewGroupBadge() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group type GroupBadgePreviewOptions struct { LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` } // PreviewGroupBadge returns how the link_url and image_url final URLs would be after // resolving the placeholder interpolation. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group func (s *GroupBadgesService) PreviewGroupBadge(gid interface{}, opt *GroupBadgePreviewOptions, options ...OptionFunc) (*GroupBadge, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/badges/render", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } gb := new(GroupBadge) resp, err := s.client.Do(req, &gb) if err != nil { return nil, resp, err } return gb, resp, err } golang-github-xanzy-go-gitlab-0.22.2/group_boards.go000066400000000000000000000161301357140411500223550ustar00rootroot00000000000000// // Copyright 2018, Patrick Webster // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // GroupIssueBoardsService handles communication with the group issue board // related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html type GroupIssueBoardsService struct { client *Client } // GroupIssueBoard represents a GitLab group issue board. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html type GroupIssueBoard struct { ID int `json:"id"` Name string `json:"name"` Group *Group `json:"group"` Milestone *Milestone `json:"milestone"` Lists []*BoardList `json:"lists"` } func (b GroupIssueBoard) String() string { return Stringify(b) } // ListGroupIssueBoardsOptions represents the available // ListGroupIssueBoards() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#group-board type ListGroupIssueBoardsOptions ListOptions // ListGroupIssueBoards gets a list of all issue boards in a group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#group-board func (s *GroupIssueBoardsService) ListGroupIssueBoards(gid interface{}, opt *ListGroupIssueBoardsOptions, options ...OptionFunc) ([]*GroupIssueBoard, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/boards", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var gs []*GroupIssueBoard resp, err := s.client.Do(req, &gs) if err != nil { return nil, resp, err } return gs, resp, err } // GetGroupIssueBoard gets a single issue board of a group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#single-board func (s *GroupIssueBoardsService) GetGroupIssueBoard(gid interface{}, board int, options ...OptionFunc) (*GroupIssueBoard, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/boards/%d", pathEscape(group), board) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } gib := new(GroupIssueBoard) resp, err := s.client.Do(req, gib) if err != nil { return nil, resp, err } return gib, resp, err } // ListGroupIssueBoardListsOptions represents the available // ListGroupIssueBoardLists() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#list-board-lists type ListGroupIssueBoardListsOptions ListOptions // ListGroupIssueBoardLists gets a list of the issue board's lists. Does not include // backlog and closed lists. // // GitLab API docs: https://docs.gitlab.com/ce/api/group_boards.html#list-board-lists func (s *GroupIssueBoardsService) ListGroupIssueBoardLists(gid interface{}, board int, opt *ListGroupIssueBoardListsOptions, options ...OptionFunc) ([]*BoardList, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/boards/%d/lists", pathEscape(group), board) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var gbl []*BoardList resp, err := s.client.Do(req, &gbl) if err != nil { return nil, resp, err } return gbl, resp, err } // GetGroupIssueBoardList gets a single issue board list. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#single-board-list func (s *GroupIssueBoardsService) GetGroupIssueBoardList(gid interface{}, board, list int, options ...OptionFunc) (*BoardList, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/boards/%d/lists/%d", pathEscape(group), board, list, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } gbl := new(BoardList) resp, err := s.client.Do(req, gbl) if err != nil { return nil, resp, err } return gbl, resp, err } // CreateGroupIssueBoardListOptions represents the available // CreateGroupIssueBoardList() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#new-board-list type CreateGroupIssueBoardListOptions struct { LabelID *int `url:"label_id" json:"label_id"` } // CreateGroupIssueBoardList creates a new issue board list. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#new-board-list func (s *GroupIssueBoardsService) CreateGroupIssueBoardList(gid interface{}, board int, opt *CreateGroupIssueBoardListOptions, options ...OptionFunc) (*BoardList, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/boards/%d/lists", pathEscape(group), board) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } gbl := new(BoardList) resp, err := s.client.Do(req, gbl) if err != nil { return nil, resp, err } return gbl, resp, err } // UpdateGroupIssueBoardListOptions represents the available // UpdateGroupIssueBoardList() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#edit-board-list type UpdateGroupIssueBoardListOptions struct { Position *int `url:"position" json:"position"` } // UpdateIssueBoardList updates the position of an existing // group issue board list. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#edit-board-list func (s *GroupIssueBoardsService) UpdateIssueBoardList(gid interface{}, board, list int, opt *UpdateGroupIssueBoardListOptions, options ...OptionFunc) ([]*BoardList, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/boards/%d/lists/%d", pathEscape(group), board, list, ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } var gbl []*BoardList resp, err := s.client.Do(req, gbl) if err != nil { return nil, resp, err } return gbl, resp, err } // DeleteGroupIssueBoardList soft deletes a group issue board list. // Only for admins and group owners. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_boards.html#delete-a-board-list func (s *GroupIssueBoardsService) DeleteGroupIssueBoardList(gid interface{}, board, list int, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/boards/%d/lists/%d", pathEscape(group), board, list, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/group_clusters.go000066400000000000000000000164421357140411500227550ustar00rootroot00000000000000// // Copyright 2019, Paul Shoemaker // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // GroupClustersService handles communication with the // group clusters related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html type GroupClustersService struct { client *Client } // GroupCluster represents a GitLab Group Cluster. // // GitLab API docs: https://docs.gitlab.com/ee/api/group_clusters.html type GroupCluster struct { ID int `json:"id"` Name string `json:"name"` Domain string `json:"domain"` CreatedAt *time.Time `json:"created_at"` ProviderType string `json:"provider_type"` PlatformType string `json:"platform_type"` EnvironmentScope string `json:"environment_scope"` ClusterType string `json:"cluster_type"` User *User `json:"user"` PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"` Group *Group `json:"group"` } func (v GroupCluster) String() string { return Stringify(v) } // ListClusters gets a list of all clusters in a group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html#list-group-clusters func (s *GroupClustersService) ListClusters(pid interface{}, options ...OptionFunc) ([]*GroupCluster, *Response, error) { group, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/clusters", pathEscape(group)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var pcs []*GroupCluster resp, err := s.client.Do(req, &pcs) if err != nil { return nil, resp, err } return pcs, resp, err } // GetCluster gets a cluster. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html#get-a-single-group-cluster func (s *GroupClustersService) GetCluster(pid interface{}, cluster int, options ...OptionFunc) (*GroupCluster, *Response, error) { group, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pc := new(GroupCluster) resp, err := s.client.Do(req, &pc) if err != nil { return nil, resp, err } return pc, resp, err } // AddGroupClusterOptions represents the available AddCluster() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html#add-existing-cluster-to-group type AddGroupClusterOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Domain *string `url:"domain,omitempty" json:"domain,omitempty"` Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` Managed *bool `url:"managed,omitempty" json:"managed,omitempty"` EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` PlatformKubernetes *AddGroupPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` } // AddGroupPlatformKubernetesOptions represents the available PlatformKubernetes options for adding. type AddGroupPlatformKubernetesOptions struct { APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` Token *string `url:"token,omitempty" json:"token,omitempty"` CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` AuthorizationType *string `url:"authorization_type,omitempty" json:"authorization_type,omitempty"` } // AddCluster adds an existing cluster to the group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html#add-existing-cluster-to-group func (s *GroupClustersService) AddCluster(pid interface{}, opt *AddGroupClusterOptions, options ...OptionFunc) (*GroupCluster, *Response, error) { group, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/clusters/user", pathEscape(group)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pc := new(GroupCluster) resp, err := s.client.Do(req, pc) if err != nil { return nil, resp, err } return pc, resp, err } // EditGroupClusterOptions represents the available EditCluster() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html#edit-group-cluster type EditGroupClusterOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Domain *string `url:"domain,omitempty" json:"domain,omitempty"` EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` PlatformKubernetes *EditGroupPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` } // EditGroupPlatformKubernetesOptions represents the available PlatformKubernetes options for editing. type EditGroupPlatformKubernetesOptions struct { APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` Token *string `url:"token,omitempty" json:"token,omitempty"` CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` } // EditCluster updates an existing group cluster. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html#edit-group-cluster func (s *GroupClustersService) EditCluster(pid interface{}, cluster int, opt *EditGroupClusterOptions, options ...OptionFunc) (*GroupCluster, *Response, error) { group, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } pc := new(GroupCluster) resp, err := s.client.Do(req, pc) if err != nil { return nil, resp, err } return pc, resp, err } // DeleteCluster deletes an existing group cluster. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_clusters.html#delete-group-cluster func (s *GroupClustersService) DeleteCluster(pid interface{}, cluster int, options ...OptionFunc) (*Response, error) { group, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/group_labels.go000066400000000000000000000127611357140411500223530ustar00rootroot00000000000000package gitlab import ( "fmt" ) // GroupLabelsService handles communication with the label related methods of the // GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html type GroupLabelsService struct { client *Client } // GroupLabel represents a GitLab group label. // // GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html type GroupLabel Label func (l GroupLabel) String() string { return Stringify(l) } // ListGroupLabelsOptions represents the available ListGroupLabels() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels type ListGroupLabelsOptions ListOptions // ListGroupLabels gets all labels for given group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#list-group-labels func (s *GroupLabelsService) ListGroupLabels(gid interface{}, opt *ListGroupLabelsOptions, options ...OptionFunc) ([]*GroupLabel, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var l []*GroupLabel resp, err := s.client.Do(req, &l) if err != nil { return nil, resp, err } return l, resp, err } // CreateGroupLabelOptions represents the available CreateGroupLabel() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label type CreateGroupLabelOptions CreateLabelOptions // CreateGroupLabel creates a new label for given group with given name and // color. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label func (s *GroupLabelsService) CreateGroupLabel(gid interface{}, opt *CreateGroupLabelOptions, options ...OptionFunc) (*GroupLabel, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } l := new(GroupLabel) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // DeleteGroupLabelOptions represents the available DeleteGroupLabel() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#delete-a-group-label type DeleteGroupLabelOptions DeleteLabelOptions // DeleteGroupLabel deletes a group label given by its name. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label func (s *GroupLabelsService) DeleteGroupLabel(gid interface{}, opt *DeleteGroupLabelOptions, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) req, err := s.client.NewRequest("DELETE", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // UpdateGroupLabelOptions represents the available UpdateGroupLabel() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label type UpdateGroupLabelOptions UpdateLabelOptions // UpdateGroupLabel updates an existing label with new name or now color. At least // one parameter is required, to update the label. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label func (s *GroupLabelsService) UpdateGroupLabel(gid interface{}, opt *UpdateGroupLabelOptions, options ...OptionFunc) (*GroupLabel, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } l := new(GroupLabel) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // SubscribeToGroupLabel subscribes the authenticated user to a label to receive // notifications. If the user is already subscribed to the label, the status // code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#subscribe-to-a-group-label func (s *GroupLabelsService) SubscribeToGroupLabel(gid interface{}, labelID interface{}, options ...OptionFunc) (*GroupLabel, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } label, err := parseID(labelID) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/labels/%s/subscribe", pathEscape(group), label) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } l := new(GroupLabel) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // UnsubscribeFromGroupLabel unsubscribes the authenticated user from a label to not // receive notifications from it. If the user is not subscribed to the label, the // status code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_labels.html#unsubscribe-from-a-group-label func (s *GroupLabelsService) UnsubscribeFromGroupLabel(gid interface{}, labelID interface{}, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } label, err := parseID(labelID) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/labels/%s/unsubscribe", pathEscape(group), label) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/group_labels_test.go000066400000000000000000000102731357140411500234060ustar00rootroot00000000000000package gitlab import ( "fmt" "log" "net/http" "reflect" "testing" ) func TestCreateGroupGroupLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1, "name": "My GroupLabel", "color" : "#11FF22"}`) }) l := &CreateGroupLabelOptions{ Name: String("My GroupLabel"), Color: String("#11FF22"), } label, _, err := client.GroupLabels.CreateGroupLabel("1", l) if err != nil { log.Fatal(err) } want := &GroupLabel{ID: 1, Name: "My GroupLabel", Color: "#11FF22"} if !reflect.DeepEqual(want, label) { t.Errorf("GroupLabels.CreateGroupLabel returned %+v, want %+v", label, want) } } func TestDeleteGroupLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) label := &DeleteGroupLabelOptions{ Name: String("My GroupLabel"), } _, err := client.GroupLabels.DeleteGroupLabel("1", label) if err != nil { log.Fatal(err) } } func TestUpdateGroupLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"id":1, "name": "New GroupLabel", "color" : "#11FF23" , "description":"This is updated label"}`) }) l := &UpdateGroupLabelOptions{ Name: String("My GroupLabel"), NewName: String("New GroupLabel"), Color: String("#11FF23"), Description: String("This is updated label"), } label, resp, err := client.GroupLabels.UpdateGroupLabel("1", l) if resp == nil { log.Fatal(err) } if err != nil { log.Fatal(err) } want := &GroupLabel{ID: 1, Name: "New GroupLabel", Color: "#11FF23", Description: "This is updated label"} if !reflect.DeepEqual(want, label) { t.Errorf("GroupLabels.UpdateGroupLabel returned %+v, want %+v", label, want) } } func TestSubscribeToGroupLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/labels/5/subscribe", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{ "id" : 5, "name" : "bug", "color" : "#d9534f", "description": "Bug reported by user", "open_issues_count": 1, "closed_issues_count": 0, "open_merge_requests_count": 1, "subscribed": true,"priority": null}`) }) label, _, err := client.GroupLabels.SubscribeToGroupLabel("1", "5") if err != nil { log.Fatal(err) } want := &GroupLabel{ID: 5, Name: "bug", Color: "#d9534f", Description: "Bug reported by user", OpenIssuesCount: 1, ClosedIssuesCount: 0, OpenMergeRequestsCount: 1, Subscribed: true} if !reflect.DeepEqual(want, label) { t.Errorf("GroupLabels.SubscribeToGroupLabel returned %+v, want %+v", label, want) } } func TestUnsubscribeFromGroupLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/labels/5/unsubscribe", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") }) _, err := client.GroupLabels.UnsubscribeFromGroupLabel("1", "5") if err != nil { log.Fatal(err) } } func TestListGroupLabels(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{ "id" : 5, "name" : "bug", "color" : "#d9534f", "description": "Bug reported by user", "open_issues_count": 1, "closed_issues_count": 0, "open_merge_requests_count": 1, "subscribed": true,"priority": null}]`) }) o := &ListGroupLabelsOptions{ Page: 1, PerPage: 10, } label, _, err := client.GroupLabels.ListGroupLabels("1", o) if err != nil { t.Log(err.Error() == "invalid ID type 1.1, the ID must be an int or a string") } want := []*GroupLabel{{ID: 5, Name: "bug", Color: "#d9534f", Description: "Bug reported by user", OpenIssuesCount: 1, ClosedIssuesCount: 0, OpenMergeRequestsCount: 1, Subscribed: true}} if !reflect.DeepEqual(want, label) { t.Errorf("GroupLabels.ListGroupLabels returned %+v, want %+v", label, want) } } golang-github-xanzy-go-gitlab-0.22.2/group_members.go000066400000000000000000000150721357140411500225410ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // GroupMembersService handles communication with the group members // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/members.html type GroupMembersService struct { client *Client } // GroupMember represents a GitLab group member. // // GitLab API docs: https://docs.gitlab.com/ce/api/members.html type GroupMember struct { ID int `json:"id"` Username string `json:"username"` Name string `json:"name"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` ExpiresAt *ISOTime `json:"expires_at"` AccessLevel AccessLevelValue `json:"access_level"` } // ListGroupMembersOptions represents the available ListGroupMembers() and // ListAllGroupMembers() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project type ListGroupMembersOptions struct { ListOptions Query *string `url:"query,omitempty" json:"query,omitempty"` } // ListGroupMembers get a list of group members viewable by the authenticated // user. Inherited members through ancestor groups are not included. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project func (s *GroupsService) ListGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...OptionFunc) ([]*GroupMember, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/members", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var gm []*GroupMember resp, err := s.client.Do(req, &gm) if err != nil { return nil, resp, err } return gm, resp, err } // ListAllGroupMembers get a list of group members viewable by the authenticated // user. Returns a list including inherited members through ancestor groups. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members func (s *GroupsService) ListAllGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...OptionFunc) ([]*GroupMember, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/members/all", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var gm []*GroupMember resp, err := s.client.Do(req, &gm) if err != nil { return nil, resp, err } return gm, resp, err } // AddGroupMemberOptions represents the available AddGroupMember() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project type AddGroupMemberOptions struct { UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` } // GetGroupMember gets a member of a group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project func (s *GroupMembersService) GetGroupMember(gid interface{}, user int, options ...OptionFunc) (*GroupMember, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } gm := new(GroupMember) resp, err := s.client.Do(req, gm) if err != nil { return nil, resp, err } return gm, resp, err } // AddGroupMember adds a user to the list of group members. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project func (s *GroupMembersService) AddGroupMember(gid interface{}, opt *AddGroupMemberOptions, options ...OptionFunc) (*GroupMember, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/members", pathEscape(group)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } gm := new(GroupMember) resp, err := s.client.Do(req, gm) if err != nil { return nil, resp, err } return gm, resp, err } // EditGroupMemberOptions represents the available EditGroupMember() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project type EditGroupMemberOptions struct { AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` } // EditGroupMember updates a member of a group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project func (s *GroupMembersService) EditGroupMember(gid interface{}, user int, opt *EditGroupMemberOptions, options ...OptionFunc) (*GroupMember, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } gm := new(GroupMember) resp, err := s.client.Do(req, gm) if err != nil { return nil, resp, err } return gm, resp, err } // RemoveGroupMember removes user from user team. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project func (s *GroupMembersService) RemoveGroupMember(gid interface{}, user int, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/group_milestones.go000066400000000000000000000175171357140411500232770ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // GroupMilestonesService handles communication with the milestone related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html type GroupMilestonesService struct { client *Client } // GroupMilestone represents a GitLab milestone. // // GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html type GroupMilestone struct { ID int `json:"id"` IID int `json:"iid"` GroupID int `json:"group_id"` Title string `json:"title"` Description string `json:"description"` StartDate *ISOTime `json:"start_date"` DueDate *ISOTime `json:"due_date"` State string `json:"state"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` } func (m GroupMilestone) String() string { return Stringify(m) } // ListGroupMilestonesOptions represents the available // ListGroupMilestones() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones type ListGroupMilestonesOptions struct { ListOptions IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` State string `url:"state,omitempty" json:"state,omitempty"` Search string `url:"search,omitempty" json:"search,omitempty"` } // ListGroupMilestones returns a list of group milestones. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones func (s *GroupMilestonesService) ListGroupMilestones(gid interface{}, opt *ListGroupMilestonesOptions, options ...OptionFunc) ([]*GroupMilestone, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/milestones", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var m []*GroupMilestone resp, err := s.client.Do(req, &m) if err != nil { return nil, resp, err } return m, resp, err } // GetGroupMilestone gets a single group milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#get-single-milestone func (s *GroupMilestonesService) GetGroupMilestone(gid interface{}, milestone int, options ...OptionFunc) (*GroupMilestone, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/milestones/%d", pathEscape(group), milestone) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } m := new(GroupMilestone) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // CreateGroupMilestoneOptions represents the available CreateGroupMilestone() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone type CreateGroupMilestoneOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` } // CreateGroupMilestone creates a new group milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone func (s *GroupMilestonesService) CreateGroupMilestone(gid interface{}, opt *CreateGroupMilestoneOptions, options ...OptionFunc) (*GroupMilestone, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/milestones", pathEscape(group)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } m := new(GroupMilestone) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // UpdateGroupMilestoneOptions represents the available UpdateGroupMilestone() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone type UpdateGroupMilestoneOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` } // UpdateGroupMilestone updates an existing group milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone func (s *GroupMilestonesService) UpdateGroupMilestone(gid interface{}, milestone int, opt *UpdateGroupMilestoneOptions, options ...OptionFunc) (*GroupMilestone, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/milestones/%d", pathEscape(group), milestone) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } m := new(GroupMilestone) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // GetGroupMilestoneIssuesOptions represents the available GetGroupMilestoneIssues() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone type GetGroupMilestoneIssuesOptions ListOptions // GetGroupMilestoneIssues gets all issues assigned to a single group milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone func (s *GroupMilestonesService) GetGroupMilestoneIssues(gid interface{}, milestone int, opt *GetGroupMilestoneIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/milestones/%d/issues", pathEscape(group), milestone) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var i []*Issue resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } // GetGroupMilestoneMergeRequestsOptions represents the available // GetGroupMilestoneMergeRequests() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone type GetGroupMilestoneMergeRequestsOptions ListOptions // GetGroupMilestoneMergeRequests gets all merge requests assigned to a // single group milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone func (s *GroupMilestonesService) GetGroupMilestoneMergeRequests(gid interface{}, milestone int, opt *GetGroupMilestoneMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/milestones/%d/merge_requests", pathEscape(group), milestone) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var mr []*MergeRequest resp, err := s.client.Do(req, &mr) if err != nil { return nil, resp, err } return mr, resp, err } golang-github-xanzy-go-gitlab-0.22.2/group_variables.go000066400000000000000000000134461357140411500230620ustar00rootroot00000000000000// // Copyright 2018, Patrick Webster // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/url" ) // GroupVariablesService handles communication with the // group variables related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html type GroupVariablesService struct { client *Client } // GroupVariable represents a GitLab group Variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html type GroupVariable struct { Key string `json:"key"` Value string `json:"value"` VariableType VariableTypeValue `json:"variable_type"` Protected bool `json:"protected"` } func (v GroupVariable) String() string { return Stringify(v) } // ListGroupVariablesOptions represents the available options for listing variables // for a group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#list-group-variables type ListGroupVariablesOptions ListOptions // ListVariables gets a list of all variables for a group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#list-group-variables func (s *GroupVariablesService) ListVariables(gid interface{}, opt *ListGroupVariablesOptions, options ...OptionFunc) ([]*GroupVariable, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/variables", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var vs []*GroupVariable resp, err := s.client.Do(req, &vs) if err != nil { return nil, resp, err } return vs, resp, err } // GetVariable gets a variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#show-variable-details func (s *GroupVariablesService) GetVariable(gid interface{}, key string, options ...OptionFunc) (*GroupVariable, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } v := new(GroupVariable) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } // CreateGroupVariableOptions represents the available CreateVariable() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#create-variable type CreateGroupVariableOptions struct { Key *string `url:"key,omitempty" json:"key,omitempty"` Value *string `url:"value,omitempty" json:"value,omitempty"` VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` } // CreateVariable creates a new group variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#create-variable func (s *GroupVariablesService) CreateVariable(gid interface{}, opt *CreateGroupVariableOptions, options ...OptionFunc) (*GroupVariable, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/variables", pathEscape(group)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } v := new(GroupVariable) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } // UpdateGroupVariableOptions represents the available UpdateVariable() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#update-variable type UpdateGroupVariableOptions struct { Value *string `url:"value,omitempty" json:"value,omitempty"` VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` } // UpdateVariable updates the position of an existing // group issue board list. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#update-variable func (s *GroupVariablesService) UpdateVariable(gid interface{}, key string, opt *UpdateGroupVariableOptions, options ...OptionFunc) (*GroupVariable, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } v := new(GroupVariable) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } // RemoveVariable removes a group's variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/group_level_variables.html#remove-variable func (s *GroupVariablesService) RemoveVariable(gid interface{}, key string, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/groups.go000066400000000000000000000302721357140411500212110ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // GroupsService handles communication with the group related methods of // the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html type GroupsService struct { client *Client } // Group represents a GitLab group. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html type Group struct { ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` Description string `json:"description"` Visibility *VisibilityValue `json:"visibility"` LFSEnabled bool `json:"lfs_enabled"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` RequestAccessEnabled bool `json:"request_access_enabled"` FullName string `json:"full_name"` FullPath string `json:"full_path"` ParentID int `json:"parent_id"` Projects []*Project `json:"projects"` Statistics *StorageStatistics `json:"statistics"` CustomAttributes []*CustomAttribute `json:"custom_attributes"` ShareWithGroupLock bool `json:"share_with_group_lock"` RequireTwoFactorAuth bool `json:"require_two_factor_authentication"` TwoFactorGracePeriod int `json:"two_factor_grace_period"` ProjectCreationLevel string `json:"project_creation_level"` AutoDevopsEnabled bool `json:"auto_devops_enabled"` SubGroupCreationLevel string `json:"subgroup_creation_level"` EmailsDisabled bool `json:"emails_disabled"` RunnersToken string `json:"runners_token"` SharedProjects []*Project `json:"shared_projects"` LDAPCN string `json:"ldap_cn"` LDAPAccess bool `json:"ldap_access"` SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"` ExtraSharedRunnersMinutesLimit int `json:"extra_shared_runners_minutes_limit"` } // ListGroupsOptions represents the available ListGroups() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-project-groups type ListGroupsOptions struct { ListOptions AllAvailable *bool `url:"all_available,omitempty" json:"all_available,omitempty"` MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` SkipGroups []int `url:"skip_groups,omitempty" json:"skip_groups,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` } // ListGroups gets a list of groups (as user: my groups, as admin: all groups). // // GitLab API docs: // https://docs.gitlab.com/ce/api/groups.html#list-project-groups func (s *GroupsService) ListGroups(opt *ListGroupsOptions, options ...OptionFunc) ([]*Group, *Response, error) { req, err := s.client.NewRequest("GET", "groups", opt, options) if err != nil { return nil, nil, err } var g []*Group resp, err := s.client.Do(req, &g) if err != nil { return nil, resp, err } return g, resp, err } // GetGroup gets all details of a group. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#details-of-a-group func (s *GroupsService) GetGroup(gid interface{}, options ...OptionFunc) (*Group, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s", pathEscape(group)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } g := new(Group) resp, err := s.client.Do(req, g) if err != nil { return nil, resp, err } return g, resp, err } // CreateGroupOptions represents the available CreateGroup() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group type CreateGroupOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Path *string `url:"path,omitempty" json:"path,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` ParentID *int `url:"parent_id,omitempty" json:"parent_id,omitempty"` } // CreateGroup creates a new project group. Available only for users who can // create groups. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group func (s *GroupsService) CreateGroup(opt *CreateGroupOptions, options ...OptionFunc) (*Group, *Response, error) { req, err := s.client.NewRequest("POST", "groups", opt, options) if err != nil { return nil, nil, err } g := new(Group) resp, err := s.client.Do(req, g) if err != nil { return nil, resp, err } return g, resp, err } // TransferGroup transfers a project to the Group namespace. Available only // for admin. // // GitLab API docs: // https://docs.gitlab.com/ce/api/groups.html#transfer-project-to-group func (s *GroupsService) TransferGroup(gid interface{}, pid interface{}, options ...OptionFunc) (*Group, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/projects/%s", pathEscape(group), pathEscape(project)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } g := new(Group) resp, err := s.client.Do(req, g) if err != nil { return nil, resp, err } return g, resp, err } // UpdateGroupOptions represents the set of available options to update a Group; // as of today these are exactly the same available when creating a new Group. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group type UpdateGroupOptions CreateGroupOptions // UpdateGroup updates an existing group; only available to group owners and // administrators. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group func (s *GroupsService) UpdateGroup(gid interface{}, opt *UpdateGroupOptions, options ...OptionFunc) (*Group, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s", pathEscape(group)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } g := new(Group) resp, err := s.client.Do(req, g) if err != nil { return nil, resp, err } return g, resp, err } // DeleteGroup removes group with all projects inside. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#remove-group func (s *GroupsService) DeleteGroup(gid interface{}, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s", pathEscape(group)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // SearchGroup get all groups that match your string in their name or path. // // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#search-for-group func (s *GroupsService) SearchGroup(query string, options ...OptionFunc) ([]*Group, *Response, error) { var q struct { Search string `url:"search,omitempty" json:"search,omitempty"` } q.Search = query req, err := s.client.NewRequest("GET", "groups", &q, options) if err != nil { return nil, nil, err } var g []*Group resp, err := s.client.Do(req, &g) if err != nil { return nil, resp, err } return g, resp, err } // ListGroupProjectsOptions represents the available ListGroupProjects() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects type ListGroupProjectsOptions struct { ListOptions Archived *bool `url:"archived,omitempty" json:"archived,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` Simple *bool `url:"simple,omitempty" json:"simple,omitempty"` Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` Starred *bool `url:"starred,omitempty" json:"starred,omitempty"` WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"` WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"` WithShared *bool `url:"with_shared,omitempty" json:"with_shared,omitempty"` IncludeSubgroups *bool `url:"include_subgroups,omitempty" json:"include_subgroups,omitempty"` WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` } // ListGroupProjects get a list of group projects // // GitLab API docs: // https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects func (s *GroupsService) ListGroupProjects(gid interface{}, opt *ListGroupProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/projects", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var p []*Project resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // ListSubgroupsOptions represents the available ListSubgroupsOptions() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups type ListSubgroupsOptions ListGroupsOptions // ListSubgroups gets a list of subgroups for a given project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups func (s *GroupsService) ListSubgroups(gid interface{}, opt *ListSubgroupsOptions, options ...OptionFunc) ([]*Group, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/subgroups", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var g []*Group resp, err := s.client.Do(req, &g) if err != nil { return nil, resp, err } return g, resp, err } golang-github-xanzy-go-gitlab-0.22.2/groups_badges_test.go000066400000000000000000000065121357140411500235550ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestListGroupBadges(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/badges", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1, "kind":"group"},{"id":2, "kind":"group"}]`) }) badges, _, err := client.GroupBadges.ListGroupBadges(1, &ListGroupBadgesOptions{}) if err != nil { t.Errorf("GroupBadges.ListGroupBadges returned error: %v", err) } want := []*GroupBadge{{ID: 1, Kind: GroupBadgeKind}, {ID: 2, Kind: GroupBadgeKind}} if !reflect.DeepEqual(want, badges) { t.Errorf("GroupBadges.ListGroupBadges returned %+v, want %+v", badges, want) } } func TestGetGroupBadge(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/badges/2", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":2, "kind":"group"}`) }) badge, _, err := client.GroupBadges.GetGroupBadge(1, 2) if err != nil { t.Errorf("GroupBadges.GetGroupBadge returned error: %v", err) } want := &GroupBadge{ID: 2, Kind: GroupBadgeKind} if !reflect.DeepEqual(want, badge) { t.Errorf("GroupBadges.GetGroupBadge returned %+v, want %+v", badge, want) } } func TestAddGroupBadge(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/badges", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":3, "link_url":"LINK", "image_url":"IMAGE", "kind":"group"}`) }) opt := &AddGroupBadgeOptions{ImageURL: String("IMAGE"), LinkURL: String("LINK")} badge, _, err := client.GroupBadges.AddGroupBadge(1, opt) if err != nil { t.Errorf("GroupBadges.AddGroupBadge returned error: %v", err) } want := &GroupBadge{ID: 3, ImageURL: "IMAGE", LinkURL: "LINK", Kind: GroupBadgeKind} if !reflect.DeepEqual(want, badge) { t.Errorf("GroupBadges.AddGroupBadge returned %+v, want %+v", badge, want) } } func TestEditGroupBadge(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/badges/2", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"id":2, "link_url":"NEW_LINK", "image_url":"NEW_IMAGE", "kind":"group"}`) }) opt := &EditGroupBadgeOptions{ImageURL: String("NEW_IMAGE"), LinkURL: String("NEW_LINK")} badge, _, err := client.GroupBadges.EditGroupBadge(1, 2, opt) if err != nil { t.Errorf("GroupBadges.EditGroupBadge returned error: %v", err) } want := &GroupBadge{ID: 2, ImageURL: "NEW_IMAGE", LinkURL: "NEW_LINK", Kind: GroupBadgeKind} if !reflect.DeepEqual(want, badge) { t.Errorf("GroupBadges.EditGroupBadge returned %+v, want %+v", badge, want) } } func TestRemoveGroupBadge(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/badges/2", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusAccepted) }, ) resp, err := client.GroupBadges.DeleteGroupBadge(1, 2) if err != nil { t.Errorf("GroupBadges.DeleteGroupBadge returned error: %v", err) } want := http.StatusAccepted got := resp.StatusCode if got != want { t.Errorf("GroupsBadges.DeleteGroupBadge returned %d, want %d", got, want) } } golang-github-xanzy-go-gitlab-0.22.2/groups_test.go000066400000000000000000000117171357140411500222530ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestListGroups(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) groups, _, err := client.Groups.ListGroups(&ListGroupsOptions{}) if err != nil { t.Errorf("Groups.ListGroups returned error: %v", err) } want := []*Group{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, groups) { t.Errorf("Groups.ListGroups returned %+v, want %+v", groups, want) } } func TestGetGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/g", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id": 1, "name": "g"}`) }) group, _, err := client.Groups.GetGroup("g") if err != nil { t.Errorf("Groups.GetGroup returned error: %v", err) } want := &Group{ID: 1, Name: "g"} if !reflect.DeepEqual(want, group) { t.Errorf("Groups.GetGroup returned %+v, want %+v", group, want) } } func TestCreateGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id": 1, "name": "g", "path": "g"}`) }) opt := &CreateGroupOptions{ Name: String("g"), Path: String("g"), } group, _, err := client.Groups.CreateGroup(opt, nil) if err != nil { t.Errorf("Groups.CreateGroup returned error: %v", err) } want := &Group{ID: 1, Name: "g", Path: "g"} if !reflect.DeepEqual(want, group) { t.Errorf("Groups.CreateGroup returned %+v, want %+v", group, want) } } func TestTransferGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/projects/2", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprintf(w, `{"id": 1}`) }) group, _, err := client.Groups.TransferGroup(1, 2) if err != nil { t.Errorf("Groups.TransferGroup returned error: %v", err) } want := &Group{ID: 1} if !reflect.DeepEqual(group, want) { t.Errorf("Groups.TransferGroup returned %+v, want %+v", group, want) } } func TestDeleteGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusAccepted) }) resp, err := client.Groups.DeleteGroup(1) if err != nil { t.Errorf("Groups.DeleteGroup returned error: %v", err) } want := http.StatusAccepted got := resp.StatusCode if got != want { t.Errorf("Groups.DeleteGroup returned %d, want %d", got, want) } } func TestSearchGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id": 1, "name": "Foobar Group"}]`) }) groups, _, err := client.Groups.SearchGroup("foobar") if err != nil { t.Errorf("Groups.SearchGroup returned error: %v", err) } want := []*Group{{ID: 1, Name: "Foobar Group"}} if !reflect.DeepEqual(want, groups) { t.Errorf("Groups.SearchGroup returned +%v, want %+v", groups, want) } } func TestUpdateGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"id": 1}`) }) group, _, err := client.Groups.UpdateGroup(1, &UpdateGroupOptions{}) if err != nil { t.Errorf("Groups.UpdateGroup returned error: %v", err) } want := &Group{ID: 1} if !reflect.DeepEqual(want, group) { t.Errorf("Groups.UpdatedGroup returned %+v, want %+v", group, want) } } func TestListGroupProjects(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/22/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) projects, _, err := client.Groups.ListGroupProjects(22, &ListGroupProjectsOptions{}) if err != nil { t.Errorf("Groups.ListGroupProjects returned error: %v", err) } want := []*Project{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Groups.ListGroupProjects returned %+v, want %+v", projects, want) } } func TestListSubgroups(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/subgroups", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id": 1}, {"id": 2}]`) }) groups, _, err := client.Groups.ListSubgroups(1, &ListSubgroupsOptions{}) if err != nil { t.Errorf("Groups.ListSubgroups returned error: %v", err) } want := []*Group{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, groups) { t.Errorf("Groups.ListSubgroups returned %+v, want %+v", groups, want) } } golang-github-xanzy-go-gitlab-0.22.2/issue_links.go000066400000000000000000000071521357140411500222230ustar00rootroot00000000000000// // Copyright 2017, Arkbriar // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // IssueLinksService handles communication with the issue relations related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html type IssueLinksService struct { client *Client } // IssueLink represents a two-way relation between two issues. // // GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html type IssueLink struct { SourceIssue *Issue `json:"source_issue"` TargetIssue *Issue `json:"target_issue"` } // ListIssueRelations gets a list of related issues of a given issue, // sorted by the relationship creation datetime (ascending). // // Issues will be filtered according to the user authorizations. // // GitLab API docs: // https://docs.gitlab.com/ee/api/issue_links.html#list-issue-relations func (s *IssueLinksService) ListIssueRelations(pid interface{}, issueIID int, options ...OptionFunc) ([]*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/links", pathEscape(project), issueIID) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var is []*Issue resp, err := s.client.Do(req, &is) if err != nil { return nil, resp, err } return is, resp, err } // CreateIssueLinkOptions represents the available CreateIssueLink() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html type CreateIssueLinkOptions struct { TargetProjectID *string `json:"target_project_id"` TargetIssueIID *string `json:"target_issue_iid"` } // CreateIssueLink creates a two-way relation between two issues. // User must be allowed to update both issues in order to succeed. // // GitLab API docs: // https://docs.gitlab.com/ee/api/issue_links.html#create-an-issue-link func (s *IssueLinksService) CreateIssueLink(pid interface{}, issueIID int, opt *CreateIssueLinkOptions, options ...OptionFunc) (*IssueLink, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/links", pathEscape(project), issueIID) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } i := new(IssueLink) resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } // DeleteIssueLink deletes an issue link, thus removes the two-way relationship. // // GitLab API docs: // https://docs.gitlab.com/ee/api/issue_links.html#delete-an-issue-link func (s *IssueLinksService) DeleteIssueLink(pid interface{}, issueIID, issueLinkID int, options ...OptionFunc) (*IssueLink, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/links/%d", pathEscape(project), issueIID, issueLinkID) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, nil, err } i := new(IssueLink) resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } golang-github-xanzy-go-gitlab-0.22.2/issues.go000066400000000000000000000533351357140411500212120ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "encoding/json" "fmt" "strings" "time" ) // IssuesService handles communication with the issue related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html type IssuesService struct { client *Client timeStats *timeStatsService } // IssueAuthor represents a author of the issue. type IssueAuthor struct { ID int `json:"id"` State string `json:"state"` WebURL string `json:"web_url"` Name string `json:"name"` AvatarURL string `json:"avatar_url"` Username string `json:"username"` } // IssueAssignee represents a assignee of the issue. type IssueAssignee struct { ID int `json:"id"` State string `json:"state"` WebURL string `json:"web_url"` Name string `json:"name"` AvatarURL string `json:"avatar_url"` Username string `json:"username"` } // IssueLinks represents links of the issue. type IssueLinks struct { Self string `json:"self"` Notes string `json:"notes"` AwardEmoji string `json:"award_emoji"` Project string `json:"project"` } // Issue represents a GitLab issue. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html type Issue struct { ID int `json:"id"` IID int `json:"iid"` ProjectID int `json:"project_id"` Milestone *Milestone `json:"milestone"` Author *IssueAuthor `json:"author"` Description string `json:"description"` State string `json:"state"` Assignees []*IssueAssignee `json:"assignees"` Assignee *IssueAssignee `json:"assignee"` Upvotes int `json:"upvotes"` Downvotes int `json:"downvotes"` Labels Labels `json:"labels"` Title string `json:"title"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` ClosedAt *time.Time `json:"closed_at"` Subscribed bool `json:"subscribed"` UserNotesCount int `json:"user_notes_count"` DueDate *ISOTime `json:"due_date"` WebURL string `json:"web_url"` TimeStats *TimeStats `json:"time_stats"` Confidential bool `json:"confidential"` Weight int `json:"weight"` DiscussionLocked bool `json:"discussion_locked"` Links *IssueLinks `json:"_links"` IssueLinkID int `json:"issue_link_id"` MergeRequestCount int `json:"merge_requests_count"` } func (i Issue) String() string { return Stringify(i) } // Labels is a custom type with specific marshaling characteristics. type Labels []string // MarshalJSON implements the json.Marshaler interface. func (l *Labels) MarshalJSON() ([]byte, error) { return json.Marshal(strings.Join(*l, ",")) } // ListIssuesOptions represents the available ListIssues() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues type ListIssuesOptions struct { ListOptions State *string `url:"state,omitempty" json:"state,omitempty"` Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` Scope *string `url:"scope,omitempty" json:"scope,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` } // ListIssues gets all issues created by authenticated user. This function // takes pagination parameters page and per_page to restrict the list of issues. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues func (s *IssuesService) ListIssues(opt *ListIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { req, err := s.client.NewRequest("GET", "issues", opt, options) if err != nil { return nil, nil, err } var i []*Issue resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } // ListGroupIssuesOptions represents the available ListGroupIssues() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues type ListGroupIssuesOptions struct { ListOptions State *string `url:"state,omitempty" json:"state,omitempty"` Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` Scope *string `url:"scope,omitempty" json:"scope,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` In *string `url:"in,omitempty" json:"in,omitempty"` CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` } // ListGroupIssues gets a list of group issues. This function accepts // pagination parameters page and per_page to return the list of group issues. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues func (s *IssuesService) ListGroupIssues(pid interface{}, opt *ListGroupIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { group, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/issues", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var i []*Issue resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } // ListProjectIssuesOptions represents the available ListProjectIssues() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues type ListProjectIssuesOptions struct { ListOptions IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` State *string `url:"state,omitempty" json:"state,omitempty"` Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` Scope *string `url:"scope,omitempty" json:"scope,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` In *string `url:"in,omitempty" json:"in,omitempty"` CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` } // ListProjectIssues gets a list of project issues. This function accepts // pagination parameters page and per_page to return the list of project issues. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues func (s *IssuesService) ListProjectIssues(pid interface{}, opt *ListProjectIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var i []*Issue resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } // GetIssue gets a single project issue. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#single-issues func (s *IssuesService) GetIssue(pid interface{}, issue int, options ...OptionFunc) (*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d", pathEscape(project), issue) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { return nil, resp, err } return i, resp, err } // CreateIssueOptions represents the available CreateIssue() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues type CreateIssueOptions struct { IID *int `url:"iid,omitempty" json:"iid,omitempty"` Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` MergeRequestToResolveDiscussionsOf *int `url:"merge_request_to_resolve_discussions_of,omitempty" json:"merge_request_to_resolve_discussions_of,omitempty"` DiscussionToResolve *string `url:"discussion_to_resolve,omitempty" json:"discussion_to_resolve,omitempty"` Weight *int `url:"weight,omitempty" json:"weight,omitempty"` } // CreateIssue creates a new project issue. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues func (s *IssuesService) CreateIssue(pid interface{}, opt *CreateIssueOptions, options ...OptionFunc) (*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { return nil, resp, err } return i, resp, err } // UpdateIssueOptions represents the available UpdateIssue() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/issues.html#edit-issue type UpdateIssueOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` UpdatedAt *time.Time `url:"updated_at,omitempty" json:"updated_at,omitempty"` DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` Weight *int `url:"weight,omitempty" json:"weight,omitempty"` DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"` } // UpdateIssue updates an existing project issue. This function is also used // to mark an issue as closed. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues func (s *IssuesService) UpdateIssue(pid interface{}, issue int, opt *UpdateIssueOptions, options ...OptionFunc) (*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d", pathEscape(project), issue) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { return nil, resp, err } return i, resp, err } // DeleteIssue deletes a single project issue. // // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#delete-an-issue func (s *IssuesService) DeleteIssue(pid interface{}, issue int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/issues/%d", pathEscape(project), issue) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // MoveIssueOptions represents the available MoveIssue() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/issues.html#move-an-issue type MoveIssueOptions struct { ToProjectID *int `url:"to_project_id,omitempty" json:"to_project_id,omitempty"` } // MoveIssue updates an existing project issue. This function is also used // to mark an issue as closed. // // GitLab API docs: https://docs.gitlab.com/ee/api/issues.html#move-an-issue func (s *IssuesService) MoveIssue(pid interface{}, issue int, opt *MoveIssueOptions, options ...OptionFunc) (*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/move", pathEscape(project), issue) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { return nil, resp, err } return i, resp, err } // SubscribeToIssue subscribes the authenticated user to the given issue to // receive notifications. If the user is already subscribed to the issue, the // status code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#subscribe-to-a-merge-request func (s *IssuesService) SubscribeToIssue(pid interface{}, issue int, options ...OptionFunc) (*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/subscribe", pathEscape(project), issue) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { return nil, resp, err } return i, resp, err } // UnsubscribeFromIssue unsubscribes the authenticated user from the given // issue to not receive notifications from that merge request. If the user // is not subscribed to the issue, status code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request func (s *IssuesService) UnsubscribeFromIssue(pid interface{}, issue int, options ...OptionFunc) (*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/unsubscribe", pathEscape(project), issue) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { return nil, resp, err } return i, resp, err } // ListMergeRequestsClosingIssueOptions represents the available // ListMergeRequestsClosingIssue() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-that-will-close-issue-on-merge type ListMergeRequestsClosingIssueOptions ListOptions // ListMergeRequestsClosingIssue gets all the merge requests that will close // issue when merged. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-that-will-close-issue-on-merge func (s *IssuesService) ListMergeRequestsClosingIssue(pid interface{}, issue int, opt *ListMergeRequestsClosingIssueOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("/projects/%s/issues/%d/closed_by", pathEscape(project), issue) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var m []*MergeRequest resp, err := s.client.Do(req, &m) if err != nil { return nil, resp, err } return m, resp, err } // ListMergeRequestsRelatedToIssueOptions represents the available // ListMergeRequestsRelatedToIssue() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-related-to-issue type ListMergeRequestsRelatedToIssueOptions ListOptions // ListMergeRequestsRelatedToIssue gets all the merge requests that are // related to the issue // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-related-to-issue func (s *IssuesService) ListMergeRequestsRelatedToIssue(pid interface{}, issue int, opt *ListMergeRequestsRelatedToIssueOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("/projects/%s/issues/%d/related_merge_requests", pathEscape(project), issue, ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var m []*MergeRequest resp, err := s.client.Do(req, &m) if err != nil { return nil, resp, err } return m, resp, err } // SetTimeEstimate sets the time estimate for a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#set-a-time-estimate-for-an-issue func (s *IssuesService) SetTimeEstimate(pid interface{}, issue int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.setTimeEstimate(pid, "issues", issue, opt, options...) } // ResetTimeEstimate resets the time estimate for a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#reset-the-time-estimate-for-an-issue func (s *IssuesService) ResetTimeEstimate(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.resetTimeEstimate(pid, "issues", issue, options...) } // AddSpentTime adds spent time for a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#add-spent-time-for-an-issue func (s *IssuesService) AddSpentTime(pid interface{}, issue int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.addSpentTime(pid, "issues", issue, opt, options...) } // ResetSpentTime resets the spent time for a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#reset-spent-time-for-an-issue func (s *IssuesService) ResetSpentTime(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.resetSpentTime(pid, "issues", issue, options...) } // GetTimeSpent gets the spent time for a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/issues.html#get-time-tracking-stats func (s *IssuesService) GetTimeSpent(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.getTimeSpent(pid, "issues", issue, options...) } golang-github-xanzy-go-gitlab-0.22.2/issues_test.go000066400000000000000000000333101357140411500222400ustar00rootroot00000000000000package gitlab import ( "fmt" "log" "net/http" "reflect" "testing" "github.com/stretchr/testify/assert" ) func TestGetIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1, "description": "This is test project", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}],"merge_requests_count": 1}`) }) issue, _, err := client.Issues.GetIssue("1", 5) if err != nil { log.Fatal(err) } want := &Issue{ ID: 1, Description: "This is test project", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, MergeRequestCount: 1, } if !reflect.DeepEqual(want, issue) { t.Errorf("Issues.GetIssue returned %+v, want %+v", issue, want) } } func TestDeleteIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") fmt.Fprint(w, `{"id":1, "description": "This is test project", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}`) }) _, err := client.Issues.DeleteIssue("1", 5) if err != nil { log.Fatal(err) } } func TestMoveIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/11/move", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") mustWriteHTTPResponse(t, w, "testdata/issue_move.json") }) issue, _, err := client.Issues.MoveIssue("1", 11, &MoveIssueOptions{ToProjectID: Int(5)}) if err != nil { log.Fatal(err) } want := &Issue{ ID: 92, IID: 11, ProjectID: 5, } assert.Equal(t, want.IID, issue.IID) assert.Equal(t, want.ProjectID, issue.ProjectID) } func TestListIssues(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/issues?assignee_id=2&author_id=1") fmt.Fprint(w, `[{"id":1, "description": "This is test project", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}]`) }) listProjectIssue := &ListIssuesOptions{ AuthorID: Int(01), AssigneeID: Int(02), } issues, _, err := client.Issues.ListIssues(listProjectIssue) if err != nil { log.Fatal(err) } want := []*Issue{{ ID: 1, Description: "This is test project", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, }} if !reflect.DeepEqual(want, issues) { t.Errorf("Issues.ListIssues returned %+v, want %+v", issues, want) } } func TestListProjectIssues(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/projects/1/issues?assignee_id=2&author_id=1") fmt.Fprint(w, `[{"id":1, "description": "This is test project", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}]`) }) listProjectIssue := &ListProjectIssuesOptions{ AuthorID: Int(01), AssigneeID: Int(02), } issues, _, err := client.Issues.ListProjectIssues("1", listProjectIssue) if err != nil { log.Fatal(err) } want := []*Issue{{ ID: 1, Description: "This is test project", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, }} if !reflect.DeepEqual(want, issues) { t.Errorf("Issues.ListProjectIssues returned %+v, want %+v", issues, want) } } func TestListGroupIssues(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/groups/1/issues?assignee_id=2&author_id=1&state=Open") fmt.Fprint(w, `[{"id":1, "description": "This is test project", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}]`) }) listGroupIssue := &ListGroupIssuesOptions{ State: String("Open"), AuthorID: Int(01), AssigneeID: Int(02), } issues, _, err := client.Issues.ListGroupIssues("1", listGroupIssue) if err != nil { log.Fatal(err) } want := []*Issue{{ ID: 1, Description: "This is test project", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, }} if !reflect.DeepEqual(want, issues) { t.Errorf("Issues.ListGroupIssues returned %+v, want %+v", issues, want) } } func TestCreateIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1, "title" : "Title of issue", "description": "This is description of an issue", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}`) }) createIssueOptions := &CreateIssueOptions{ Title: String("Title of issue"), Description: String("This is description of an issue"), } issue, _, err := client.Issues.CreateIssue("1", createIssueOptions) if err != nil { log.Fatal(err) } want := &Issue{ ID: 1, Title: "Title of issue", Description: "This is description of an issue", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, } if !reflect.DeepEqual(want, issue) { t.Errorf("Issues.CreateIssue returned %+v, want %+v", issue, want) } } func TestUpdateIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"id":1, "title" : "Title of issue", "description": "This is description of an issue", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}`) }) updateIssueOpt := &UpdateIssueOptions{ Title: String("Title of issue"), Description: String("This is description of an issue"), } issue, _, err := client.Issues.UpdateIssue(1, 5, updateIssueOpt) if err != nil { log.Fatal(err) } want := &Issue{ ID: 1, Title: "Title of issue", Description: "This is description of an issue", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, } if !reflect.DeepEqual(want, issue) { t.Errorf("Issues.UpdateIssue returned %+v, want %+v", issue, want) } } func TestSubscribeToIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/subscribe", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1, "title" : "Title of issue", "description": "This is description of an issue", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}`) }) issue, _, err := client.Issues.SubscribeToIssue("1", 5) if err != nil { log.Fatal(err) } want := &Issue{ ID: 1, Title: "Title of issue", Description: "This is description of an issue", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, } if !reflect.DeepEqual(want, issue) { t.Errorf("Issues.SubscribeToIssue returned %+v, want %+v", issue, want) } } func TestUnsubscribeFromIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/unsubscribe", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1, "title" : "Title of issue", "description": "This is description of an issue", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}`) }) issue, _, err := client.Issues.UnsubscribeFromIssue("1", 5) if err != nil { log.Fatal(err) } want := &Issue{ ID: 1, Title: "Title of issue", Description: "This is description of an issue", Author: &IssueAuthor{ID: 1, Name: "snehal"}, Assignees: []*IssueAssignee{{ID: 1}}, } if !reflect.DeepEqual(want, issue) { t.Errorf("Issues.UnsubscribeFromIssue returned %+v, want %+v", issue, want) } } func TestListMergeRequestsClosingIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/closed_by", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/projects/1/issues/5/closed_by?page=1&per_page=10") fmt.Fprint(w, `[{"id":1, "title" : "test merge one"},{"id":2, "title" : "test merge two"}]`) }) listMergeRequestsClosingIssueOpt := &ListMergeRequestsClosingIssueOptions{ Page: 1, PerPage: 10, } mergeRequest, _, err := client.Issues.ListMergeRequestsClosingIssue("1", 5, listMergeRequestsClosingIssueOpt) if err != nil { log.Fatal(err) } want := []*MergeRequest{{ID: 1, Title: "test merge one"}, {ID: 2, Title: "test merge two"}} if !reflect.DeepEqual(want, mergeRequest) { t.Errorf("Issues.ListMergeRequestsClosingIssue returned %+v, want %+v", mergeRequest, want) } } func TestListMergeRequestsRelatedToIssue(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/related_merge_requests", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/projects/1/issues/5/related_merge_requests?page=1&per_page=10") fmt.Fprint(w, `[{"id":1, "title" : "test merge one"},{"id":2, "title" : "test merge two"}]`) }) listMergeRequestsRelatedToIssueOpt := &ListMergeRequestsRelatedToIssueOptions{ Page: 1, PerPage: 10, } mergeRequest, _, err := client.Issues.ListMergeRequestsRelatedToIssue("1", 5, listMergeRequestsRelatedToIssueOpt) if err != nil { log.Fatal(err) } want := []*MergeRequest{{ID: 1, Title: "test merge one"}, {ID: 2, Title: "test merge two"}} if !reflect.DeepEqual(want, mergeRequest) { t.Errorf("Issues.ListMergeRequestsClosingIssue returned %+v, want %+v", mergeRequest, want) } } func TestSetTimeEstimate(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/time_estimate", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"human_time_estimate": "3h 30m", "human_total_time_spent": null, "time_estimate": 12600, "total_time_spent": 0}`) }) setTimeEstiOpt := &SetTimeEstimateOptions{ Duration: String("3h 30m"), } timeState, _, err := client.Issues.SetTimeEstimate("1", 5, setTimeEstiOpt) if err != nil { log.Fatal(err) } want := &TimeStats{HumanTimeEstimate: "3h 30m", HumanTotalTimeSpent: "", TimeEstimate: 12600, TotalTimeSpent: 0} if !reflect.DeepEqual(want, timeState) { t.Errorf("Issues.SetTimeEstimate returned %+v, want %+v", timeState, want) } } func TestResetTimeEstimate(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/reset_time_estimate", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"human_time_estimate": null, "human_total_time_spent": null, "time_estimate": 0, "total_time_spent": 0}`) }) timeState, _, err := client.Issues.ResetTimeEstimate("1", 5) if err != nil { log.Fatal(err) } want := &TimeStats{HumanTimeEstimate: "", HumanTotalTimeSpent: "", TimeEstimate: 0, TotalTimeSpent: 0} if !reflect.DeepEqual(want, timeState) { t.Errorf("Issues.ResetTimeEstimate returned %+v, want %+v", timeState, want) } } func TestAddSpentTime(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/add_spent_time", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") testURL(t, r, "/api/v4/projects/1/issues/5/add_spent_time") fmt.Fprint(w, `{"human_time_estimate": null, "human_total_time_spent": "1h", "time_estimate": 0, "total_time_spent": 3600}`) }) addSpentTimeOpt := &AddSpentTimeOptions{ Duration: String("1h"), } timeState, _, err := client.Issues.AddSpentTime("1", 5, addSpentTimeOpt) if err != nil { log.Fatal(err) } want := &TimeStats{HumanTimeEstimate: "", HumanTotalTimeSpent: "1h", TimeEstimate: 0, TotalTimeSpent: 3600} if !reflect.DeepEqual(want, timeState) { t.Errorf("Issues.AddSpentTime returned %+v, want %+v", timeState, want) } } func TestResetSpentTime(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/reset_spent_time", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") testURL(t, r, "/api/v4/projects/1/issues/5/reset_spent_time") fmt.Fprint(w, `{"human_time_estimate": null, "human_total_time_spent": "", "time_estimate": 0, "total_time_spent": 0}`) }) timeState, _, err := client.Issues.ResetSpentTime("1", 5) if err != nil { log.Fatal(err) } want := &TimeStats{HumanTimeEstimate: "", HumanTotalTimeSpent: "", TimeEstimate: 0, TotalTimeSpent: 0} if !reflect.DeepEqual(want, timeState) { t.Errorf("Issues.ResetSpentTime returned %+v, want %+v", timeState, want) } } func TestGetTimeSpent(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/issues/5/time_stats", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testURL(t, r, "/api/v4/projects/1/issues/5/time_stats") fmt.Fprint(w, `{"human_time_estimate": "2h", "human_total_time_spent": "1h", "time_estimate": 7200, "total_time_spent": 3600}`) }) timeState, _, err := client.Issues.GetTimeSpent("1", 5) if err != nil { log.Fatal(err) } want := &TimeStats{HumanTimeEstimate: "2h", HumanTotalTimeSpent: "1h", TimeEstimate: 7200, TotalTimeSpent: 3600} if !reflect.DeepEqual(want, timeState) { t.Errorf("Issues.GetTimeSpent returned %+v, want %+v", timeState, want) } } golang-github-xanzy-go-gitlab-0.22.2/jobs.go000066400000000000000000000256251357140411500206350ustar00rootroot00000000000000// // Copyright 2017, Arkbriar // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "bytes" "fmt" "io" "time" ) // JobsService handles communication with the ci builds related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html type JobsService struct { client *Client } // Job represents a ci build. // // GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html type Job struct { Commit *Commit `json:"commit"` Coverage float64 `json:"coverage"` AllowFailure bool `json:"allow_failure"` CreatedAt *time.Time `json:"created_at"` StartedAt *time.Time `json:"started_at"` FinishedAt *time.Time `json:"finished_at"` Duration float64 `json:"duration"` ArtifactsExpireAt *time.Time `json:"artifacts_expire_at"` ID int `json:"id"` Name string `json:"name"` Pipeline struct { ID int `json:"id"` Ref string `json:"ref"` Sha string `json:"sha"` Status string `json:"status"` } `json:"pipeline"` Ref string `json:"ref"` Artifacts []struct { FileType string `json:"file_type"` Filename string `json:"filename"` Size int `json:"size"` FileFormat string `json:"file_format"` } `json:"artifacts"` ArtifactsFile struct { Filename string `json:"filename"` Size int `json:"size"` } `json:"artifacts_file"` Runner struct { ID int `json:"id"` Description string `json:"description"` Active bool `json:"active"` IsShared bool `json:"is_shared"` Name string `json:"name"` } `json:"runner"` Stage string `json:"stage"` Status string `json:"status"` Tag bool `json:"tag"` WebURL string `json:"web_url"` User *User `json:"user"` } // ListJobsOptions are options for two list apis type ListJobsOptions struct { ListOptions Scope []BuildStateValue `url:"scope[],omitempty" json:"scope,omitempty"` } // ListProjectJobs gets a list of jobs in a project. // // The scope of jobs to show, one or array of: created, pending, running, // failed, success, canceled, skipped; showing all jobs if none provided // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opts, options) if err != nil { return nil, nil, err } var jobs []Job resp, err := s.client.Do(req, &jobs) if err != nil { return nil, resp, err } return jobs, resp, err } // ListPipelineJobs gets a list of jobs for specific pipeline in a // project. If the pipeline ID is not found, it will respond with 404. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", pathEscape(project), pipelineID) req, err := s.client.NewRequest("GET", u, opts, options) if err != nil { return nil, nil, err } var jobs []*Job resp, err := s.client.Do(req, &jobs) if err != nil { return nil, resp, err } return jobs, resp, err } // GetJob gets a single job of a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job func (s *JobsService) GetJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d", pathEscape(project), jobID) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } job := new(Job) resp, err := s.client.Do(req, job) if err != nil { return nil, resp, err } return job, resp, err } // GetJobArtifacts get jobs artifacts of a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", pathEscape(project), jobID) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } artifactsBuf := new(bytes.Buffer) resp, err := s.client.Do(req, artifactsBuf) if err != nil { return nil, resp, err } return artifactsBuf, resp, err } // DownloadArtifactsFileOptions represents the available DownloadArtifactsFile() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file type DownloadArtifactsFileOptions struct { Job *string `url:"job" json:"job"` } // DownloadArtifactsFile download the artifacts file from the given // reference name and job provided the job finished successfully. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, opt *DownloadArtifactsFileOptions, options ...OptionFunc) (io.Reader, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download", pathEscape(project), refName) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } artifactsBuf := new(bytes.Buffer) resp, err := s.client.Do(req, artifactsBuf) if err != nil { return nil, resp, err } return artifactsBuf, resp, err } // DownloadSingleArtifactsFile download a file from the artifacts from the // given reference name and job provided the job finished successfully. // Only a single file is going to be extracted from the archive and streamed // to a client. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#download-a-single-artifact-file func (s *JobsService) DownloadSingleArtifactsFile(pid interface{}, jobID int, artifactPath string, options ...OptionFunc) (io.Reader, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf( "projects/%s/jobs/%d/artifacts/%s", pathEscape(project), jobID, artifactPath, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } artifactBuf := new(bytes.Buffer) resp, err := s.client.Do(req, artifactBuf) if err != nil { return nil, resp, err } return artifactBuf, resp, err } // GetTraceFile gets a trace of a specific job of a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d/trace", pathEscape(project), jobID) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } traceBuf := new(bytes.Buffer) resp, err := s.client.Do(req, traceBuf) if err != nil { return nil, resp, err } return traceBuf, resp, err } // CancelJob cancels a single job of a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d/cancel", pathEscape(project), jobID) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } job := new(Job) resp, err := s.client.Do(req, job) if err != nil { return nil, resp, err } return job, resp, err } // RetryJob retries a single job of a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#retry-a-job func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d/retry", pathEscape(project), jobID) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } job := new(Job) resp, err := s.client.Do(req, job) if err != nil { return nil, resp, err } return job, resp, err } // EraseJob erases a single job of a project, removes a job // artifacts and a job trace. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#erase-a-job func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d/erase", pathEscape(project), jobID) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } job := new(Job) resp, err := s.client.Do(req, job) if err != nil { return nil, resp, err } return job, resp, err } // KeepArtifacts prevents artifacts from being deleted when // expiration is set. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", pathEscape(project), jobID) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } job := new(Job) resp, err := s.client.Do(req, job) if err != nil { return nil, resp, err } return job, resp, err } // PlayJob triggers a manual action to start a job. // // GitLab API docs: // https://docs.gitlab.com/ce/api/jobs.html#play-a-job func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/jobs/%d/play", pathEscape(project), jobID) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } job := new(Job) resp, err := s.client.Do(req, job) if err != nil { return nil, resp, err } return job, resp, err } golang-github-xanzy-go-gitlab-0.22.2/jobs_test.go000066400000000000000000000011611357140411500216610ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestListPipelineJobs(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipelines/1/jobs", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) jobs, _, err := client.Jobs.ListPipelineJobs(1, 1, nil) if err != nil { t.Errorf("Jobs.ListPipelineJobs returned error: %v", err) } want := []*Job{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, jobs) { t.Errorf("Jobs.ListPipelineJobs returned %+v, want %+v", jobs, want) } } golang-github-xanzy-go-gitlab-0.22.2/keys.go000066400000000000000000000032521357140411500206430ustar00rootroot00000000000000// // Copyright 2018, Patrick Webster // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // KeysService handles communication with the // keys related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ee/api/keys.html type KeysService struct { client *Client } // Key represents a GitLab user's SSH key. // // GitLab API docs: // https://docs.gitlab.com/ee/api/keys.html type Key struct { ID int `json:"id"` Title string `json:"title"` Key string `json:"key"` CreatedAt *time.Time `json:"created_at"` User User `json:"user"` } // GetKeyWithUser gets a single key by id along with the associated // user information. // // GitLab API docs: // https://docs.gitlab.com/ee/api/keys.html#get-ssh-key-with-user-by-id-of-an-ssh-key func (s *KeysService) GetKeyWithUser(key int, options ...OptionFunc) (*Key, *Response, error) { u := fmt.Sprintf("keys/%d", key) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } k := new(Key) resp, err := s.client.Do(req, k) if err != nil { return nil, resp, err } return k, resp, err } golang-github-xanzy-go-gitlab-0.22.2/keys_test.go000066400000000000000000000050541357140411500217040ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestGetKeyWithUser(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/keys/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{ "id": 1, "title": "Sample key 25", "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1256k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", "user": { "id": 25, "username": "john_smith", "name": "John Smith", "email": "john@example.com", "state": "active", "bio": null, "location": null, "skype": "", "linkedin": "", "twitter": "", "website_url": "http://localhost:3000/john_smith", "organization": null, "theme_id": 2, "color_scheme_id": 1, "avatar_url": "http://www.gravatar.com/avatar/cfa35b8cd2ec278026357769582fa563?s=40\u0026d=identicon", "can_create_group": true, "can_create_project": true, "projects_limit": 10, "two_factor_enabled": false, "identities": [], "external": false, "public_email": "john@example.com" } }`) }) key, _, err := client.Keys.GetKeyWithUser(1) if err != nil { t.Errorf("Keys.GetKeyWithUser returned error: %v", err) } want := &Key{ ID: 1, Title: "Sample key 25", Key: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1256k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", User: User{ ID: 25, Username: "john_smith", Email: "john@example.com", Name: "John Smith", State: "active", Bio: "", Location: "", Skype: "", Linkedin: "", Twitter: "", WebsiteURL: "http://localhost:3000/john_smith", Organization: "", ThemeID: 2, ColorSchemeID: 1, AvatarURL: "http://www.gravatar.com/avatar/cfa35b8cd2ec278026357769582fa563?s=40\u0026d=identicon", CanCreateGroup: true, CanCreateProject: true, ProjectsLimit: 10, TwoFactorEnabled: false, Identities: []*UserIdentity{}, External: false, PublicEmail: "john@example.com", }, } if !reflect.DeepEqual(want, key) { t.Errorf("Keys.GetKeyWithUser returned %+v, want %+v", key, want) } } golang-github-xanzy-go-gitlab-0.22.2/labels.go000066400000000000000000000164331357140411500211370ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "encoding/json" "fmt" ) // LabelsService handles communication with the label related methods of the // GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html type LabelsService struct { client *Client } // Label represents a GitLab label. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html type Label struct { ID int `json:"id"` Name string `json:"name"` Color string `json:"color"` TextColor string `json:"text_color"` Description string `json:"description"` OpenIssuesCount int `json:"open_issues_count"` ClosedIssuesCount int `json:"closed_issues_count"` OpenMergeRequestsCount int `json:"open_merge_requests_count"` Subscribed bool `json:"subscribed"` Priority int `json:"priority"` IsProjectLabel bool `json:"is_project_label"` } // UnmarshalJSON implements the json.Unmarshaler interface. func (l *Label) UnmarshalJSON(data []byte) error { type alias Label if err := json.Unmarshal(data, (*alias)(l)); err != nil { return err } if l.Name == "" { var raw map[string]interface{} if err := json.Unmarshal(data, &raw); err != nil { return err } if title, ok := raw["title"].(string); ok { l.Name = title } } return nil } func (l Label) String() string { return Stringify(l) } // ListLabelsOptions represents the available ListLabels() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels type ListLabelsOptions ListOptions // ListLabels gets all labels for given project. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels func (s *LabelsService) ListLabels(pid interface{}, opt *ListLabelsOptions, options ...OptionFunc) ([]*Label, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var l []*Label resp, err := s.client.Do(req, &l) if err != nil { return nil, resp, err } return l, resp, err } // CreateLabelOptions represents the available CreateLabel() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label type CreateLabelOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Color *string `url:"color,omitempty" json:"color,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` } // CreateLabel creates a new label for given repository with given name and // color. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label func (s *LabelsService) CreateLabel(pid interface{}, opt *CreateLabelOptions, options ...OptionFunc) (*Label, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } l := new(Label) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // DeleteLabelOptions represents the available DeleteLabel() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label type DeleteLabelOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` } // DeleteLabel deletes a label given by its name. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label func (s *LabelsService) DeleteLabel(pid interface{}, opt *DeleteLabelOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // UpdateLabelOptions represents the available UpdateLabel() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label type UpdateLabelOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` NewName *string `url:"new_name,omitempty" json:"new_name,omitempty"` Color *string `url:"color,omitempty" json:"color,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` } // UpdateLabel updates an existing label with new name or now color. At least // one parameter is required, to update the label. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#edit-an-existing-label func (s *LabelsService) UpdateLabel(pid interface{}, opt *UpdateLabelOptions, options ...OptionFunc) (*Label, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } l := new(Label) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // SubscribeToLabel subscribes the authenticated user to a label to receive // notifications. If the user is already subscribed to the label, the status // code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/labels.html#subscribe-to-a-label func (s *LabelsService) SubscribeToLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Label, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } label, err := parseID(labelID) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/labels/%s/subscribe", pathEscape(project), label) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } l := new(Label) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // UnsubscribeFromLabel unsubscribes the authenticated user from a label to not // receive notifications from it. If the user is not subscribed to the label, the // status code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/labels.html#unsubscribe-from-a-label func (s *LabelsService) UnsubscribeFromLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } label, err := parseID(labelID) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/labels/%s/unsubscribe", pathEscape(project), label) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/labels_test.go000066400000000000000000000100471357140411500221710ustar00rootroot00000000000000package gitlab import ( "fmt" "log" "net/http" "reflect" "testing" ) func TestCreateLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1, "name": "My Label", "color" : "#11FF22"}`) }) // Create new label l := &CreateLabelOptions{ Name: String("My Label"), Color: String("#11FF22"), } label, _, err := client.Labels.CreateLabel("1", l) if err != nil { log.Fatal(err) } want := &Label{ID: 1, Name: "My Label", Color: "#11FF22"} if !reflect.DeepEqual(want, label) { t.Errorf("Labels.CreateLabel returned %+v, want %+v", label, want) } } func TestDeleteLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) // Delete label label := &DeleteLabelOptions{ Name: String("My Label"), } _, err := client.Labels.DeleteLabel("1", label) if err != nil { log.Fatal(err) } } func TestUpdateLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"id":1, "name": "New Label", "color" : "#11FF23" , "description":"This is updated label"}`) }) // Update label l := &UpdateLabelOptions{ Name: String("My Label"), NewName: String("New Label"), Color: String("#11FF23"), Description: String("This is updated label"), } label, resp, err := client.Labels.UpdateLabel("1", l) if resp == nil { log.Fatal(err) } if err != nil { log.Fatal(err) } want := &Label{ID: 1, Name: "New Label", Color: "#11FF23", Description: "This is updated label"} if !reflect.DeepEqual(want, label) { t.Errorf("Labels.UpdateLabel returned %+v, want %+v", label, want) } } func TestSubscribeToLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/labels/5/subscribe", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{ "id" : 5, "name" : "bug", "color" : "#d9534f", "description": "Bug reported by user", "open_issues_count": 1, "closed_issues_count": 0, "open_merge_requests_count": 1, "subscribed": true,"priority": null}`) }) label, _, err := client.Labels.SubscribeToLabel("1", "5") if err != nil { log.Fatal(err) } want := &Label{ID: 5, Name: "bug", Color: "#d9534f", Description: "Bug reported by user", OpenIssuesCount: 1, ClosedIssuesCount: 0, OpenMergeRequestsCount: 1, Subscribed: true} if !reflect.DeepEqual(want, label) { t.Errorf("Labels.SubscribeToLabel returned %+v, want %+v", label, want) } } func TestUnsubscribeFromLabel(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/labels/5/unsubscribe", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") }) _, err := client.Labels.UnsubscribeFromLabel("1", "5") if err != nil { log.Fatal(err) } } func TestListLabels(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/labels", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{ "id" : 5, "name" : "bug", "color" : "#d9534f", "description": "Bug reported by user", "open_issues_count": 1, "closed_issues_count": 0, "open_merge_requests_count": 1, "subscribed": true,"priority": null}]`) }) o := &ListLabelsOptions{ Page: 1, PerPage: 10, } label, _, err := client.Labels.ListLabels("1", o) if err != nil { t.Log(err.Error() == "invalid ID type 1.1, the ID must be an int or a string") } want := []*Label{{ID: 5, Name: "bug", Color: "#d9534f", Description: "Bug reported by user", OpenIssuesCount: 1, ClosedIssuesCount: 0, OpenMergeRequestsCount: 1, Subscribed: true}} if !reflect.DeepEqual(want, label) { t.Errorf("Labels.ListLabels returned %+v, want %+v", label, want) } } golang-github-xanzy-go-gitlab-0.22.2/license.go000066400000000000000000000050071357140411500213120ustar00rootroot00000000000000// // Copyright 2018, Patrick Webster // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab // LicenseService handles communication with the license // related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ee/api/license.html type LicenseService struct { client *Client } // License represents a GitLab license. // // GitLab API docs: // https://docs.gitlab.com/ee/api/license.html type License struct { StartsAt *ISOTime `json:"starts_at"` ExpiresAt *ISOTime `json:"expires_at"` Licensee struct { Name string `json:"Name"` Company string `json:"Company"` Email string `json:"Email"` } `json:"licensee"` UserLimit int `json:"user_limit"` ActiveUsers int `json:"active_users"` AddOns struct { GitLabFileLocks int `json:"GitLabFileLocks"` } `json:"add_ons"` } func (l License) String() string { return Stringify(l) } // GetLicense retrieves information about the current license. // // GitLab API docs: // https://docs.gitlab.com/ee/api/license.html#retrieve-information-about-the-current-license func (s *LicenseService) GetLicense() (*License, *Response, error) { req, err := s.client.NewRequest("GET", "license", nil, nil) if err != nil { return nil, nil, err } l := new(License) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // AddLicenseOptions represents the available AddLicense() options. // // https://docs.gitlab.com/ee/api/license.html#add-a-new-license type AddLicenseOptions struct { License *string `url:"license" json:"license"` } // AddLicense adds a new license. // // GitLab API docs: // https://docs.gitlab.com/ee/api/license.html#add-a-new-license func (s *LicenseService) AddLicense(opt *AddLicenseOptions, options ...OptionFunc) (*License, *Response, error) { req, err := s.client.NewRequest("POST", "license", opt, options) if err != nil { return nil, nil, err } l := new(License) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } golang-github-xanzy-go-gitlab-0.22.2/license_templates.go000066400000000000000000000054051357140411500233720ustar00rootroot00000000000000package gitlab import ( "fmt" ) // LicenseTemplate represents a license template. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/licenses.html type LicenseTemplate struct { Key string `json:"key"` Name string `json:"name"` Nickname string `json:"nickname"` Featured bool `json:"featured"` HTMLURL string `json:"html_url"` SourceURL string `json:"source_url"` Description string `json:"description"` Conditions []string `json:"conditions"` Permissions []string `json:"permissions"` Limitations []string `json:"limitations"` Content string `json:"content"` } // LicenseTemplatesService handles communication with the license templates // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/templates/licenses.html type LicenseTemplatesService struct { client *Client } // ListLicenseTemplatesOptions represents the available // ListLicenseTemplates() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/licenses.html#list-license-templates type ListLicenseTemplatesOptions struct { ListOptions Popular *bool `url:"popular,omitempty" json:"popular,omitempty"` } // ListLicenseTemplates get all license templates. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/licenses.html#list-license-templates func (s *LicenseTemplatesService) ListLicenseTemplates(opt *ListLicenseTemplatesOptions, options ...OptionFunc) ([]*LicenseTemplate, *Response, error) { req, err := s.client.NewRequest("GET", "templates/licenses", opt, options) if err != nil { return nil, nil, err } var lts []*LicenseTemplate resp, err := s.client.Do(req, <s) if err != nil { return nil, resp, err } return lts, resp, err } // GetLicenseTemplateOptions represents the available // GetLicenseTemplate() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/licenses.html#single-license-template type GetLicenseTemplateOptions struct { Project *string `url:"project,omitempty" json:"project,omitempty"` Fullname *string `url:"fullname,omitempty" json:"fullname,omitempty"` } // GetLicenseTemplate get a single license template. You can pass parameters // to replace the license placeholder. // // GitLab API docs: // https://docs.gitlab.com/ce/api/templates/licenses.html#single-license-template func (s *LicenseTemplatesService) GetLicenseTemplate(template string, opt *GetLicenseTemplateOptions, options ...OptionFunc) (*LicenseTemplate, *Response, error) { u := fmt.Sprintf("templates/licenses/%s", template) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } lt := new(LicenseTemplate) resp, err := s.client.Do(req, lt) if err != nil { return nil, resp, err } return lt, resp, err } golang-github-xanzy-go-gitlab-0.22.2/merge_request_approvals.go000066400000000000000000000302301357140411500246220ustar00rootroot00000000000000package gitlab import ( "fmt" "time" ) // MergeRequestApprovalsService handles communication with the merge request // approvals related methods of the GitLab API. This includes reading/updating // approval settings and approve/unapproving merge requests // // GitLab API docs: https://docs.gitlab.com/ee/api/merge_request_approvals.html type MergeRequestApprovalsService struct { client *Client } // MergeRequestApprovals represents GitLab merge request approvals. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals type MergeRequestApprovals struct { ID int `json:"id"` ProjectID int `json:"project_id"` Title string `json:"title"` Description string `json:"description"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` MergeStatus string `json:"merge_status"` ApprovalsBeforeMerge int `json:"approvals_before_merge"` ApprovalsRequired int `json:"approvals_required"` ApprovalsLeft int `json:"approvals_left"` ApprovedBy []*MergeRequestApproverUser `json:"approved_by"` Approvers []*MergeRequestApproverUser `json:"approvers"` ApproverGroups []*MergeRequestApproverGroup `json:"approver_groups"` SuggestedApprovers []*BasicUser `json:"suggested_approvers"` } func (m MergeRequestApprovals) String() string { return Stringify(m) } // MergeRequestApproverGroup represents GitLab project level merge request approver group. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals type MergeRequestApproverGroup struct { Group struct { ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` Description string `json:"description"` Visibility string `json:"visibility"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` FullName string `json:"full_name"` FullPath string `json:"full_path"` LFSEnabled bool `json:"lfs_enabled"` RequestAccessEnabled bool `json:"request_access_enabled"` } } // MergeRequestApprovalRule represents a GitLab merge request approval rule. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-merge-request-level-rules type MergeRequestApprovalRule struct { ID int `json:"id"` Name string `json:"name"` RuleType string `json:"rule_type"` EligibleApprovers []*BasicUser `json:"eligible_approvers"` ApprovalsRequired int `json:"approvals_required"` SourceRule *ProjectApprovalRule `json:"source_rule"` Users []*BasicUser `json:"users"` Groups []*Group `json:"groups"` ContainsHiddenGroups bool `json:"contains_hidden_groups"` } // String is a stringify for MergeRequestApprovalRule func (s MergeRequestApprovalRule) String() string { return Stringify(s) } // MergeRequestApproverUser represents GitLab project level merge request approver user. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals type MergeRequestApproverUser struct { User *BasicUser } // ApproveMergeRequestOptions represents the available ApproveMergeRequest() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request type ApproveMergeRequestOptions struct { SHA *string `url:"sha,omitempty" json:"sha,omitempty"` } // ApproveMergeRequest approves a merge request on GitLab. If a non-empty sha // is provided then it must match the sha at the HEAD of the MR. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request func (s *MergeRequestApprovalsService) ApproveMergeRequest(pid interface{}, mr int, opt *ApproveMergeRequestOptions, options ...OptionFunc) (*MergeRequestApprovals, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approve", pathEscape(project), mr) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } m := new(MergeRequestApprovals) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // UnapproveMergeRequest unapproves a previously approved merge request on GitLab. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#unapprove-merge-request func (s *MergeRequestApprovalsService) UnapproveMergeRequest(pid interface{}, mr int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/unapprove", pathEscape(project), mr) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ChangeMergeRequestApprovalConfigurationOptions represents the available // ChangeMergeRequestApprovalConfiguration() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-approval-configuration type ChangeMergeRequestApprovalConfigurationOptions struct { ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` } // ChangeApprovalConfiguration updates the approval configuration of a merge request. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-approval-configuration func (s *MergeRequestApprovalsService) ChangeApprovalConfiguration(pid interface{}, mergeRequest int, opt *ChangeMergeRequestApprovalConfigurationOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // ChangeMergeRequestAllowedApproversOptions represents the available // ChangeMergeRequestAllowedApprovers() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers-for-merge-request type ChangeMergeRequestAllowedApproversOptions struct { ApproverIDs []int `url:"approver_ids" json:"approver_ids"` ApproverGroupIDs []int `url:"approver_group_ids" json:"approver_group_ids"` } // ChangeAllowedApprovers updates the approvers for a merge request. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers-for-merge-request func (s *MergeRequestApprovalsService) ChangeAllowedApprovers(pid interface{}, mergeRequest int, opt *ChangeMergeRequestAllowedApproversOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approvers", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // GetApprovalRules requests information about a merge request’s approval rules // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-merge-request-level-rules func (s *MergeRequestApprovalsService) GetApprovalRules(pid interface{}, mergeRequest int, options ...OptionFunc) ([]*MergeRequestApprovalRule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var par []*MergeRequestApprovalRule resp, err := s.client.Do(req, &par) if err != nil { return nil, resp, err } return par, resp, err } // CreateMergeRequestApprovalRuleOptions represents the available CreateApprovalRule() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-merge-request-level-rule type CreateMergeRequestApprovalRuleOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` ApprovalProjectRuleID *int `url:"approval_project_rule_id,omitempty" json:"approval_project_rule_id,omitempty"` UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` } // CreateApprovalRule creates a new MR level approval rule. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-merge-request-level-rule func (s *MergeRequestApprovalsService) CreateApprovalRule(pid interface{}, mergeRequest int, opt *CreateMergeRequestApprovalRuleOptions, options ...OptionFunc) (*MergeRequestApprovalRule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } par := new(MergeRequestApprovalRule) resp, err := s.client.Do(req, &par) if err != nil { return nil, resp, err } return par, resp, err } // UpdateMergeRequestApprovalRuleOptions represents the available UpdateApprovalRule() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-merge-request-level-rule type UpdateMergeRequestApprovalRuleOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` } // UpdateApprovalRule updates an existing approval rule with new options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-merge-request-level-rule func (s *MergeRequestApprovalsService) UpdateApprovalRule(pid interface{}, mergeRequest int, approvalRule int, opt *UpdateMergeRequestApprovalRuleOptions, options ...OptionFunc) (*MergeRequestApprovalRule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules/%d", pathEscape(project), mergeRequest, approvalRule) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } par := new(MergeRequestApprovalRule) resp, err := s.client.Do(req, &par) if err != nil { return nil, resp, err } return par, resp, err } // DeleteApprovalRule deletes a mr level approval rule. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#delete-merge-request-level-rule func (s *MergeRequestApprovalsService) DeleteApprovalRule(pid interface{}, mergeRequest int, approvalRule int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules/%d", pathEscape(project), mergeRequest, approvalRule) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/merge_request_approvals_test.go000066400000000000000000000152551357140411500256730ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestGetApprovalRules(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/merge_requests/1/approval_rules", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[ { "id": 1, "name": "security", "rule_type": "regular", "eligible_approvers": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" }, { "id": 50, "name": "Group Member 1", "username": "group_member_1", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/group_member_1" } ], "approvals_required": 3, "source_rule": null, "users": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" } ], "groups": [ { "id": 5, "name": "group1", "path": "group1", "description": "", "visibility": "public", "lfs_enabled": false, "avatar_url": null, "web_url": "http://localhost/groups/group1", "request_access_enabled": false, "full_name": "group1", "full_path": "group1", "parent_id": null, "ldap_cn": null, "ldap_access": null } ], "contains_hidden_groups": false } ]`) }) approvals, _, err := client.MergeRequestApprovals.GetApprovalRules(1, 1) if err != nil { t.Errorf("MergeRequestApprovals.GetApprovalRules returned error: %v", err) } want := []*MergeRequestApprovalRule{ &MergeRequestApprovalRule{ ID: 1, Name: "security", RuleType: "regular", EligibleApprovers: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, &BasicUser{ ID: 50, Name: "Group Member 1", Username: "group_member_1", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/group_member_1", }, }, ApprovalsRequired: 3, Users: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, }, Groups: []*Group{ &Group{ ID: 5, Name: "group1", Path: "group1", Description: "", Visibility: Visibility(PublicVisibility), LFSEnabled: false, AvatarURL: "", WebURL: "http://localhost/groups/group1", RequestAccessEnabled: false, FullName: "group1", FullPath: "group1", }, }, }, } if !reflect.DeepEqual(want, approvals) { t.Errorf("MergeRequestApprovals.GetApprovalRules returned %+v, want %+v", approvals, want) } } func TestCreateApprovalRules(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/merge_requests/1/approval_rules", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{ "id": 1, "name": "security", "rule_type": "regular", "eligible_approvers": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" }, { "id": 50, "name": "Group Member 1", "username": "group_member_1", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/group_member_1" } ], "approvals_required": 3, "source_rule": null, "users": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" } ], "groups": [ { "id": 5, "name": "group1", "path": "group1", "description": "", "visibility": "public", "lfs_enabled": false, "avatar_url": null, "web_url": "http://localhost/groups/group1", "request_access_enabled": false, "full_name": "group1", "full_path": "group1", "parent_id": null, "ldap_cn": null, "ldap_access": null } ], "contains_hidden_groups": false }`) }) opt := &CreateMergeRequestApprovalRuleOptions{ Name: String("security"), ApprovalsRequired: Int(3), UserIDs: []int{5, 50}, GroupIDs: []int{5}, } rule, _, err := client.MergeRequestApprovals.CreateApprovalRule(1, 1, opt) if err != nil { t.Errorf("MergeRequestApprovals.CreateApprovalRule returned error: %v", err) } want := &MergeRequestApprovalRule{ ID: 1, Name: "security", RuleType: "regular", EligibleApprovers: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, &BasicUser{ ID: 50, Name: "Group Member 1", Username: "group_member_1", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/group_member_1", }, }, ApprovalsRequired: 3, Users: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, }, Groups: []*Group{ &Group{ ID: 5, Name: "group1", Path: "group1", Description: "", Visibility: Visibility(PublicVisibility), LFSEnabled: false, AvatarURL: "", WebURL: "http://localhost/groups/group1", RequestAccessEnabled: false, FullName: "group1", FullPath: "group1", }, }, } if !reflect.DeepEqual(want, rule) { t.Errorf("MergeRequestApprovals.CreateApprovalRule returned %+v, want %+v", rule, want) } } golang-github-xanzy-go-gitlab-0.22.2/merge_requests.go000066400000000000000000001004041357140411500227170ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // MergeRequestsService handles communication with the merge requests related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html type MergeRequestsService struct { client *Client timeStats *timeStatsService } // MergeRequest represents a GitLab merge request. // // GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html type MergeRequest struct { ID int `json:"id"` IID int `json:"iid"` TargetBranch string `json:"target_branch"` SourceBranch string `json:"source_branch"` ProjectID int `json:"project_id"` Title string `json:"title"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` Upvotes int `json:"upvotes"` Downvotes int `json:"downvotes"` Author *BasicUser `json:"author"` Assignee *BasicUser `json:"assignee"` Assignees []*BasicUser `json:"assignees"` SourceProjectID int `json:"source_project_id"` TargetProjectID int `json:"target_project_id"` Labels Labels `json:"labels"` Description string `json:"description"` WorkInProgress bool `json:"work_in_progress"` Milestone *Milestone `json:"milestone"` MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` MergeStatus string `json:"merge_status"` MergeError string `json:"merge_error"` MergedBy *BasicUser `json:"merged_by"` MergedAt *time.Time `json:"merged_at"` ClosedBy *BasicUser `json:"closed_by"` ClosedAt *time.Time `json:"closed_at"` Subscribed bool `json:"subscribed"` SHA string `json:"sha"` MergeCommitSHA string `json:"merge_commit_sha"` UserNotesCount int `json:"user_notes_count"` ChangesCount string `json:"changes_count"` ShouldRemoveSourceBranch bool `json:"should_remove_source_branch"` ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` WebURL string `json:"web_url"` DiscussionLocked bool `json:"discussion_locked"` Changes []struct { OldPath string `json:"old_path"` NewPath string `json:"new_path"` AMode string `json:"a_mode"` BMode string `json:"b_mode"` Diff string `json:"diff"` NewFile bool `json:"new_file"` RenamedFile bool `json:"renamed_file"` DeletedFile bool `json:"deleted_file"` } `json:"changes"` TimeStats *TimeStats `json:"time_stats"` Squash bool `json:"squash"` Pipeline *PipelineInfo `json:"pipeline"` HeadPipeline *Pipeline `json:"head_pipeline"` DiffRefs struct { BaseSha string `json:"base_sha"` HeadSha string `json:"head_sha"` StartSha string `json:"start_sha"` } `json:"diff_refs"` DivergedCommitsCount int `json:"diverged_commits_count"` RebaseInProgress bool `json:"rebase_in_progress"` ApprovalsBeforeMerge int `json:"approvals_before_merge"` Reference string `json:"reference"` TaskCompletionStatus struct { Count int `json:"count"` CompletedCount int `json:"completed_count"` } `json:"task_completion_status"` } func (m MergeRequest) String() string { return Stringify(m) } // MergeRequestDiffVersion represents Gitlab merge request version. // // Gitlab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version type MergeRequestDiffVersion struct { ID int `json:"id"` HeadCommitSHA string `json:"head_commit_sha,omitempty"` BaseCommitSHA string `json:"base_commit_sha,omitempty"` StartCommitSHA string `json:"start_commit_sha,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` MergeRequestID int `json:"merge_request_id,omitempty"` State string `json:"state,omitempty"` RealSize string `json:"real_size,omitempty"` Commits []*Commit `json:"commits,omitempty"` Diffs []*Diff `json:"diffs,omitempty"` } func (m MergeRequestDiffVersion) String() string { return Stringify(m) } // ListMergeRequestsOptions represents the available ListMergeRequests() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests type ListMergeRequestsOptions struct { ListOptions State *string `url:"state,omitempty" json:"state,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` View *string `url:"view,omitempty" json:"view,omitempty"` Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` Scope *string `url:"scope,omitempty" json:"scope,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` In *string `url:"in,omitempty" json:"in,omitempty"` WIP *string `url:"wip,omitempty" json:"wip,omitempty"` } // ListMergeRequests gets all merge requests. The state parameter can be used // to get only merge requests with a given state (opened, closed, or merged) // or all of them (all). The pagination parameters page and per_page can be // used to restrict the list of merge requests. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests func (s *MergeRequestsService) ListMergeRequests(opt *ListMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { req, err := s.client.NewRequest("GET", "merge_requests", opt, options) if err != nil { return nil, nil, err } var m []*MergeRequest resp, err := s.client.Do(req, &m) if err != nil { return nil, resp, err } return m, resp, err } // ListGroupMergeRequestsOptions represents the available ListGroupMergeRequests() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests type ListGroupMergeRequestsOptions struct { ListOptions State *string `url:"state,omitempty" json:"state,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` View *string `url:"view,omitempty" json:"view,omitempty"` Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` Scope *string `url:"scope,omitempty" json:"scope,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` } // ListGroupMergeRequests gets all merge requests for this group. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests func (s *MergeRequestsService) ListGroupMergeRequests(gid interface{}, opt *ListGroupMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/merge_requests", pathEscape(group)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var m []*MergeRequest resp, err := s.client.Do(req, &m) if err != nil { return nil, resp, err } return m, resp, err } // ListProjectMergeRequestsOptions represents the available ListMergeRequests() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests type ListProjectMergeRequestsOptions struct { ListOptions IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` State *string `url:"state,omitempty" json:"state,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` View *string `url:"view,omitempty" json:"view,omitempty"` Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` Scope *string `url:"scope,omitempty" json:"scope,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` WIP *string `url:"wip,omitempty" json:"wip,omitempty"` } // ListProjectMergeRequests gets all merge requests for this project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests func (s *MergeRequestsService) ListProjectMergeRequests(pid interface{}, opt *ListProjectMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var m []*MergeRequest resp, err := s.client.Do(req, &m) if err != nil { return nil, resp, err } return m, resp, err } // GetMergeRequestsOptions represents the available GetMergeRequests() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr type GetMergeRequestsOptions struct { RenderHTML *bool `url:"render_html,omitempty" json:"render_html,omitempty"` IncludeDivergedCommitsCount *bool `url:"include_diverged_commits_count,omitempty" json:"include_diverged_commits_count,omitempty"` IncludeRebaseInProgress *bool `url:"include_rebase_in_progress,omitempty" json:"include_rebase_in_progress,omitempty"` } // GetMergeRequest shows information about a single merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr func (s *MergeRequestsService) GetMergeRequest(pid interface{}, mergeRequest int, opt *GetMergeRequestsOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // GetMergeRequestApprovals gets information about a merge requests approvals // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals func (s *MergeRequestsService) GetMergeRequestApprovals(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequestApprovals, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } a := new(MergeRequestApprovals) resp, err := s.client.Do(req, a) if err != nil { return nil, resp, err } return a, resp, err } // GetMergeRequestCommitsOptions represents the available GetMergeRequestCommits() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits type GetMergeRequestCommitsOptions ListOptions // GetMergeRequestCommits gets a list of merge request commits. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits func (s *MergeRequestsService) GetMergeRequestCommits(pid interface{}, mergeRequest int, opt *GetMergeRequestCommitsOptions, options ...OptionFunc) ([]*Commit, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/commits", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var c []*Commit resp, err := s.client.Do(req, &c) if err != nil { return nil, resp, err } return c, resp, err } // GetMergeRequestChanges shows information about the merge request including // its files and changes. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes func (s *MergeRequestsService) GetMergeRequestChanges(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/changes", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // ListMergeRequestPipelines gets all pipelines for the provided merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-mr-pipelines func (s *MergeRequestsService) ListMergeRequestPipelines(pid interface{}, mergeRequest int, options ...OptionFunc) ([]*PipelineInfo, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/pipelines", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var p []*PipelineInfo resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // GetIssuesClosedOnMergeOptions represents the available GetIssuesClosedOnMerge() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge type GetIssuesClosedOnMergeOptions ListOptions // GetIssuesClosedOnMerge gets all the issues that would be closed by merging the // provided merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge func (s *MergeRequestsService) GetIssuesClosedOnMerge(pid interface{}, mergeRequest int, opt *GetIssuesClosedOnMergeOptions, options ...OptionFunc) ([]*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/closes_issues", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var i []*Issue resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } // CreateMergeRequestOptions represents the available CreateMergeRequest() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#create-mr type CreateMergeRequestOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` TargetProjectID *int `url:"target_project_id,omitempty" json:"target_project_id,omitempty"` MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` RemoveSourceBranch *bool `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"` Squash *bool `url:"squash,omitempty" json:"squash,omitempty"` AllowCollaboration *bool `url:"allow_collaboration,omitempty" json:"allow_collaboration,omitempty"` } // CreateMergeRequest creates a new merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#create-mr func (s *MergeRequestsService) CreateMergeRequest(pid interface{}, opt *CreateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // UpdateMergeRequestOptions represents the available UpdateMergeRequest() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#update-mr type UpdateMergeRequestOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` RemoveSourceBranch *bool `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"` Squash *bool `url:"squash,omitempty" json:"squash,omitempty"` DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"` AllowCollaboration *bool `url:"allow_collaboration,omitempty" json:"allow_collaboration,omitempty"` } // UpdateMergeRequest updates an existing project milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#update-mr func (s *MergeRequestsService) UpdateMergeRequest(pid interface{}, mergeRequest int, opt *UpdateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // DeleteMergeRequest deletes a merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#delete-a-merge-request func (s *MergeRequestsService) DeleteMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // AcceptMergeRequestOptions represents the available AcceptMergeRequest() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr type AcceptMergeRequestOptions struct { MergeCommitMessage *string `url:"merge_commit_message,omitempty" json:"merge_commit_message,omitempty"` SquashCommitMessage *string `url:"squash_commit_message,omitempty" json:"squash_commit_message,omitempty"` Squash *bool `url:"squash,omitempty" json:"squash,omitempty"` ShouldRemoveSourceBranch *bool `url:"should_remove_source_branch,omitempty" json:"should_remove_source_branch,omitempty"` MergeWhenPipelineSucceeds *bool `url:"merge_when_pipeline_succeeds,omitempty" json:"merge_when_pipeline_succeeds,omitempty"` SHA *string `url:"sha,omitempty" json:"sha,omitempty"` } // AcceptMergeRequest merges changes submitted with MR using this API. If merge // success you get 200 OK. If it has some conflicts and can not be merged - you // get 405 and error message 'Branch cannot be merged'. If merge request is // already merged or closed - you get 405 and error message 'Method Not Allowed' // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr func (s *MergeRequestsService) AcceptMergeRequest(pid interface{}, mergeRequest int, opt *AcceptMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/merge", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // CancelMergeWhenPipelineSucceeds cancels a merge when pipeline succeeds. If // you don't have permissions to accept this merge request - you'll get a 401. // If the merge request is already merged or closed - you get 405 and error // message 'Method Not Allowed'. In case the merge request is not set to be // merged when the pipeline succeeds, you'll also get a 406 error. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#cancel-merge-when-pipeline-succeeds func (s *MergeRequestsService) CancelMergeWhenPipelineSucceeds(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/cancel_merge_when_pipeline_succeeds", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("PUT", u, nil, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // RebaseMergeRequest automatically rebases the source_branch of the merge // request against its target_branch. If you don’t have permissions to push // to the merge request’s source branch, you’ll get a 403 Forbidden response. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#rebase-a-merge-request func (s *MergeRequestsService) RebaseMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/rebase", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("PUT", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // GetMergeRequestDiffVersionsOptions represents the available // GetMergeRequestDiffVersions() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions type GetMergeRequestDiffVersionsOptions ListOptions // GetMergeRequestDiffVersions get a list of merge request diff versions. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions func (s *MergeRequestsService) GetMergeRequestDiffVersions(pid interface{}, mergeRequest int, opt *GetMergeRequestDiffVersionsOptions, options ...OptionFunc) ([]*MergeRequestDiffVersion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/versions", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var v []*MergeRequestDiffVersion resp, err := s.client.Do(req, &v) if err != nil { return nil, resp, err } return v, resp, err } // GetSingleMergeRequestDiffVersion get a single MR diff version // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version func (s *MergeRequestsService) GetSingleMergeRequestDiffVersion(pid interface{}, mergeRequest, version int, options ...OptionFunc) (*MergeRequestDiffVersion, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/versions/%d", pathEscape(project), mergeRequest, version) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var v = new(MergeRequestDiffVersion) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } // SubscribeToMergeRequest subscribes the authenticated user to the given merge // request to receive notifications. If the user is already subscribed to the // merge request, the status code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#subscribe-to-a-merge-request func (s *MergeRequestsService) SubscribeToMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/subscribe", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // UnsubscribeFromMergeRequest unsubscribes the authenticated user from the // given merge request to not receive notifications from that merge request. // If the user is not subscribed to the merge request, status code 304 is // returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request func (s *MergeRequestsService) UnsubscribeFromMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/unsubscribe", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } m := new(MergeRequest) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // CreateTodo manually creates a todo for the current user on a merge request. // If there already exists a todo for the user on that merge request, // status code 304 is returned. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#create-a-todo func (s *MergeRequestsService) CreateTodo(pid interface{}, mergeRequest int, options ...OptionFunc) (*Todo, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/todo", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } t := new(Todo) resp, err := s.client.Do(req, t) if err != nil { return nil, resp, err } return t, resp, err } // SetTimeEstimate sets the time estimate for a single project merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#set-a-time-estimate-for-a-merge-request func (s *MergeRequestsService) SetTimeEstimate(pid interface{}, mergeRequest int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.setTimeEstimate(pid, "merge_requests", mergeRequest, opt, options...) } // ResetTimeEstimate resets the time estimate for a single project merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#reset-the-time-estimate-for-a-merge-request func (s *MergeRequestsService) ResetTimeEstimate(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.resetTimeEstimate(pid, "merge_requests", mergeRequest, options...) } // AddSpentTime adds spent time for a single project merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#add-spent-time-for-a-merge-request func (s *MergeRequestsService) AddSpentTime(pid interface{}, mergeRequest int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.addSpentTime(pid, "merge_requests", mergeRequest, opt, options...) } // ResetSpentTime resets the spent time for a single project merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#reset-spent-time-for-a-merge-request func (s *MergeRequestsService) ResetSpentTime(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.resetSpentTime(pid, "merge_requests", mergeRequest, options...) } // GetTimeSpent gets the spent time for a single project merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/merge_requests.html#get-time-tracking-stats func (s *MergeRequestsService) GetTimeSpent(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) { return s.timeStats.getTimeSpent(pid, "merge_requests", mergeRequest, options...) } golang-github-xanzy-go-gitlab-0.22.2/merge_requests_test.go000066400000000000000000000133211357140411500237570ustar00rootroot00000000000000package gitlab import ( "net/http" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( ajk = BasicUser{ ID: 3614858, Name: "Alex Kalderimis", Username: "alexkalderimis", State: "active", AvatarURL: "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3614858/avatar.png", WebURL: "https://gitlab.com/alexkalderimis", } tk = BasicUser{ ID: 2535118, Name: "Thong Kuah", Username: "tkuah", State: "active", AvatarURL: "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon", WebURL: "https://gitlab.com/tkuah", } getOpts = GetMergeRequestsOptions{} labels = Labels{ "GitLab Enterprise Edition", "backend", "database", "database::reviewed", "design management", "feature", "frontend", "group::knowledge", "missed:12.1", } pipelineCreation = time.Date(2019, 8, 19, 9, 50, 58, 157000000, time.UTC) pipelineUpdate = time.Date(2019, 8, 19, 19, 22, 29, 647000000, time.UTC) pipelineBasic = PipelineInfo{ ID: 77056819, SHA: "8e0b45049b6253b8984cde9241830d2851168142", Ref: "delete-designs-v2", Status: "success", WebURL: "https://gitlab.com/gitlab-org/gitlab-ee/pipelines/77056819", CreatedAt: &pipelineCreation, UpdatedAt: &pipelineUpdate, } pipelineStarted = time.Date(2019, 8, 19, 9, 51, 6, 545000000, time.UTC) pipelineFinished = time.Date(2019, 8, 19, 19, 22, 29, 632000000, time.UTC) pipelineDetailed = Pipeline{ ID: 77056819, SHA: "8e0b45049b6253b8984cde9241830d2851168142", Ref: "delete-designs-v2", Status: "success", WebURL: "https://gitlab.com/gitlab-org/gitlab-ee/pipelines/77056819", BeforeSHA: "3fe568caacb261b63090886f5b879ca0d9c6f4c3", Tag: false, User: &ajk, CreatedAt: &pipelineCreation, UpdatedAt: &pipelineUpdate, StartedAt: &pipelineStarted, FinishedAt: &pipelineFinished, Duration: 4916, Coverage: "82.68", DetailedStatus: &DetailedStatus{ Icon: "status_warning", Text: "passed", Label: "passed with warnings", Group: "success-with-warnings", Tooltip: "passed", HasDetails: true, DetailsPath: "/gitlab-org/gitlab-ee/pipelines/77056819", Favicon: "https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png", }, } ) func TestGetMergeRequest(t *testing.T) { mux, server, client := setup() defer teardown(server) path := "/api/v4/projects/namespace/name/merge_requests/123" mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/get_merge_request.json") }) mergeRequest, _, err := client.MergeRequests.GetMergeRequest("namespace/name", 123, &getOpts) require.NoError(t, err) require.Equal(t, mergeRequest.ID, 33092005) require.Equal(t, mergeRequest.SHA, "8e0b45049b6253b8984cde9241830d2851168142") require.Equal(t, mergeRequest.IID, 14656) require.Equal(t, mergeRequest.Reference, "!14656") require.Equal(t, mergeRequest.ProjectID, 278964) require.Equal(t, mergeRequest.SourceBranch, "delete-designs-v2") require.Equal(t, mergeRequest.TaskCompletionStatus.Count, 9) require.Equal(t, mergeRequest.TaskCompletionStatus.CompletedCount, 8) require.Equal(t, mergeRequest.Title, "Add deletion support for designs") require.Equal(t, mergeRequest.Description, "## What does this MR do?\r\n\r\nThis adds the capability to destroy/hide designs.") require.Equal(t, mergeRequest.WebURL, "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/14656") require.Equal(t, mergeRequest.MergeStatus, "can_be_merged") require.Equal(t, mergeRequest.Author, &ajk) require.Equal(t, mergeRequest.Assignee, &tk) require.Equal(t, mergeRequest.Assignees, []*BasicUser{&tk}) require.Equal(t, mergeRequest.Labels, labels) require.Equal(t, mergeRequest.Squash, true) require.Equal(t, mergeRequest.UserNotesCount, 245) require.Equal(t, mergeRequest.Pipeline, &pipelineBasic) require.Equal(t, mergeRequest.HeadPipeline, &pipelineDetailed) mrCreation := time.Date(2019, 7, 11, 22, 34, 43, 500000000, time.UTC) require.Equal(t, mergeRequest.CreatedAt, &mrCreation) mrUpdate := time.Date(2019, 8, 20, 9, 9, 56, 690000000, time.UTC) require.Equal(t, mergeRequest.UpdatedAt, &mrUpdate) } func TestListProjectMergeRequests(t *testing.T) { mux, server, client := setup() defer teardown(server) path := "/api/v4/projects/278964/merge_requests" mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/get_merge_requests.json") }) opts := ListProjectMergeRequestsOptions{} mergeRequests, _, err := client.MergeRequests.ListProjectMergeRequests(278964, &opts) require.NoError(t, err) require.Equal(t, 20, len(mergeRequests)) validStates := []string{"opened", "closed", "locked", "merged"} mergeStatuses := []string{"can_be_merged", "cannot_be_merged"} allCreatedBefore := time.Date(2019, 8, 21, 0, 0, 0, 0, time.UTC) allCreatedAfter := time.Date(2019, 8, 17, 0, 0, 0, 0, time.UTC) for _, mr := range mergeRequests { require.Equal(t, 278964, mr.ProjectID) require.Contains(t, validStates, mr.State) assert.Less(t, mr.CreatedAt.Unix(), allCreatedBefore.Unix()) assert.Greater(t, mr.CreatedAt.Unix(), allCreatedAfter.Unix()) assert.LessOrEqual(t, mr.CreatedAt.Unix(), mr.UpdatedAt.Unix()) assert.LessOrEqual(t, mr.TaskCompletionStatus.CompletedCount, mr.TaskCompletionStatus.Count) require.Contains(t, mergeStatuses, mr.MergeStatus) // list requests do not provide these fields: assert.Nil(t, mr.Pipeline) assert.Nil(t, mr.HeadPipeline) assert.Equal(t, "", mr.DiffRefs.HeadSha) } } golang-github-xanzy-go-gitlab-0.22.2/milestones.go000066400000000000000000000202421357140411500220500ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // MilestonesService handles communication with the milestone related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html type MilestonesService struct { client *Client } // Milestone represents a GitLab milestone. // // GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html type Milestone struct { ID int `json:"id"` IID int `json:"iid"` ProjectID int `json:"project_id"` Title string `json:"title"` Description string `json:"description"` StartDate *ISOTime `json:"start_date"` DueDate *ISOTime `json:"due_date"` State string `json:"state"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` } func (m Milestone) String() string { return Stringify(m) } // ListMilestonesOptions represents the available ListMilestones() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones type ListMilestonesOptions struct { ListOptions IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` Title *string `url:"title,omitempty" json:"title,omitempty"` State *string `url:"state,omitempty" json:"state,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` } // ListMilestones returns a list of project milestones. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones func (s *MilestonesService) ListMilestones(pid interface{}, opt *ListMilestonesOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/milestones", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var m []*Milestone resp, err := s.client.Do(req, &m) if err != nil { return nil, resp, err } return m, resp, err } // GetMilestone gets a single project milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#get-single-milestone func (s *MilestonesService) GetMilestone(pid interface{}, milestone int, options ...OptionFunc) (*Milestone, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/milestones/%d", pathEscape(project), milestone) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } m := new(Milestone) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // CreateMilestoneOptions represents the available CreateMilestone() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone type CreateMilestoneOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` } // CreateMilestone creates a new project milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone func (s *MilestonesService) CreateMilestone(pid interface{}, opt *CreateMilestoneOptions, options ...OptionFunc) (*Milestone, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/milestones", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } m := new(Milestone) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // UpdateMilestoneOptions represents the available UpdateMilestone() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#edit-milestone type UpdateMilestoneOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` } // UpdateMilestone updates an existing project milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#edit-milestone func (s *MilestonesService) UpdateMilestone(pid interface{}, milestone int, opt *UpdateMilestoneOptions, options ...OptionFunc) (*Milestone, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/milestones/%d", pathEscape(project), milestone) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } m := new(Milestone) resp, err := s.client.Do(req, m) if err != nil { return nil, resp, err } return m, resp, err } // DeleteMilestone deletes a specified project milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#delete-project-milestone func (s *MilestonesService) DeleteMilestone(pid interface{}, milestone int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/milestones/%d", pathEscape(project), milestone) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // GetMilestoneIssuesOptions represents the available GetMilestoneIssues() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone type GetMilestoneIssuesOptions ListOptions // GetMilestoneIssues gets all issues assigned to a single project milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone func (s *MilestonesService) GetMilestoneIssues(pid interface{}, milestone int, opt *GetMilestoneIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/milestones/%d/issues", pathEscape(project), milestone) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var i []*Issue resp, err := s.client.Do(req, &i) if err != nil { return nil, resp, err } return i, resp, err } // GetMilestoneMergeRequestsOptions represents the available // GetMilestoneMergeRequests() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#get-all-merge-requests-assigned-to-a-single-milestone type GetMilestoneMergeRequestsOptions ListOptions // GetMilestoneMergeRequests gets all merge requests assigned to a single // project milestone. // // GitLab API docs: // https://docs.gitlab.com/ce/api/milestones.html#get-all-merge-requests-assigned-to-a-single-milestone func (s *MilestonesService) GetMilestoneMergeRequests(pid interface{}, milestone int, opt *GetMilestoneMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/milestones/%d/merge_requests", pathEscape(project), milestone) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var mr []*MergeRequest resp, err := s.client.Do(req, &mr) if err != nil { return nil, resp, err } return mr, resp, err } golang-github-xanzy-go-gitlab-0.22.2/namespaces.go000066400000000000000000000066331357140411500220150ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // NamespacesService handles communication with the namespace related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html type NamespacesService struct { client *Client } // Namespace represents a GitLab namespace. // // GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html type Namespace struct { ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` Kind string `json:"kind"` FullPath string `json:"full_path"` ParentID int `json:"parent_id"` MembersCountWithDescendants int `json:"members_count_with_descendants"` } func (n Namespace) String() string { return Stringify(n) } // ListNamespacesOptions represents the available ListNamespaces() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces type ListNamespacesOptions struct { ListOptions Search *string `url:"search,omitempty" json:"search,omitempty"` } // ListNamespaces gets a list of projects accessible by the authenticated user. // // GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces func (s *NamespacesService) ListNamespaces(opt *ListNamespacesOptions, options ...OptionFunc) ([]*Namespace, *Response, error) { req, err := s.client.NewRequest("GET", "namespaces", opt, options) if err != nil { return nil, nil, err } var n []*Namespace resp, err := s.client.Do(req, &n) if err != nil { return nil, resp, err } return n, resp, err } // SearchNamespace gets all namespaces that match your string in their name // or path. // // GitLab API docs: // https://docs.gitlab.com/ce/api/namespaces.html#search-for-namespace func (s *NamespacesService) SearchNamespace(query string, options ...OptionFunc) ([]*Namespace, *Response, error) { var q struct { Search string `url:"search,omitempty" json:"search,omitempty"` } q.Search = query req, err := s.client.NewRequest("GET", "namespaces", &q, options) if err != nil { return nil, nil, err } var n []*Namespace resp, err := s.client.Do(req, &n) if err != nil { return nil, resp, err } return n, resp, err } // GetNamespace gets a namespace by id. // // GitLab API docs: // https://docs.gitlab.com/ce/api/namespaces.html#get-namespace-by-id func (s *NamespacesService) GetNamespace(id interface{}, options ...OptionFunc) (*Namespace, *Response, error) { namespace, err := parseID(id) if err != nil { return nil, nil, err } u := fmt.Sprintf("namespaces/%s", namespace) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } n := new(Namespace) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } golang-github-xanzy-go-gitlab-0.22.2/notes.go000066400000000000000000000467001357140411500210250ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // NotesService handles communication with the notes related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/notes.html type NotesService struct { client *Client } // Note represents a GitLab note. // // GitLab API docs: https://docs.gitlab.com/ce/api/notes.html type Note struct { ID int `json:"id"` Body string `json:"body"` Attachment string `json:"attachment"` Title string `json:"title"` FileName string `json:"file_name"` Author struct { ID int `json:"id"` Username string `json:"username"` Email string `json:"email"` Name string `json:"name"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"author"` System bool `json:"system"` ExpiresAt *time.Time `json:"expires_at"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` NoteableID int `json:"noteable_id"` NoteableType string `json:"noteable_type"` Position *NotePosition `json:"position"` Resolvable bool `json:"resolvable"` Resolved bool `json:"resolved"` ResolvedBy struct { ID int `json:"id"` Username string `json:"username"` Email string `json:"email"` Name string `json:"name"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"resolved_by"` NoteableIID int `json:"noteable_iid"` } // NotePosition represents the position attributes of a note. type NotePosition struct { BaseSHA string `json:"base_sha"` StartSHA string `json:"start_sha"` HeadSHA string `json:"head_sha"` PositionType string `json:"position_type"` NewPath string `json:"new_path,omitempty"` NewLine int `json:"new_line,omitempty"` OldPath string `json:"old_path,omitempty"` OldLine int `json:"old_line,omitempty"` Width int `json:"width,omitempty"` Height int `json:"height,omitempty"` X int `json:"x,omitempty"` Y int `json:"y,omitempty"` } func (n Note) String() string { return Stringify(n) } // ListIssueNotesOptions represents the available ListIssueNotes() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes type ListIssueNotesOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListIssueNotes gets a list of all notes for a single issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes func (s *NotesService) ListIssueNotes(pid interface{}, issue int, opt *ListIssueNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/notes", pathEscape(project), issue) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var n []*Note resp, err := s.client.Do(req, &n) if err != nil { return nil, resp, err } return n, resp, err } // GetIssueNote returns a single note for a specific project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#get-single-issue-note func (s *NotesService) GetIssueNote(pid interface{}, issue, note int, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", pathEscape(project), issue, note) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // CreateIssueNoteOptions represents the available CreateIssueNote() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note type CreateIssueNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` } // CreateIssueNote creates a new note to a single project issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note func (s *NotesService) CreateIssueNote(pid interface{}, issue int, opt *CreateIssueNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/notes", pathEscape(project), issue) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateIssueNoteOptions represents the available UpdateIssueNote() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note type UpdateIssueNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` } // UpdateIssueNote modifies existing note of an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note func (s *NotesService) UpdateIssueNote(pid interface{}, issue, note int, opt *UpdateIssueNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", pathEscape(project), issue, note) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteIssueNote deletes an existing note of an issue. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#delete-an-issue-note func (s *NotesService) DeleteIssueNote(pid interface{}, issue, note int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", pathEscape(project), issue, note) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListSnippetNotesOptions represents the available ListSnippetNotes() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes type ListSnippetNotesOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListSnippetNotes gets a list of all notes for a single snippet. Snippet // notes are comments users can post to a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes func (s *NotesService) ListSnippetNotes(pid interface{}, snippet int, opt *ListSnippetNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/notes", pathEscape(project), snippet) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var n []*Note resp, err := s.client.Do(req, &n) if err != nil { return nil, resp, err } return n, resp, err } // GetSnippetNote returns a single note for a given snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#get-single-snippet-note func (s *NotesService) GetSnippetNote(pid interface{}, snippet, note int, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", pathEscape(project), snippet, note) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // CreateSnippetNoteOptions represents the available CreateSnippetNote() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note type CreateSnippetNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` } // CreateSnippetNote creates a new note for a single snippet. Snippet notes are // comments users can post to a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note func (s *NotesService) CreateSnippetNote(pid interface{}, snippet int, opt *CreateSnippetNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/notes", pathEscape(project), snippet) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateSnippetNoteOptions represents the available UpdateSnippetNote() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note type UpdateSnippetNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` } // UpdateSnippetNote modifies existing note of a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note func (s *NotesService) UpdateSnippetNote(pid interface{}, snippet, note int, opt *UpdateSnippetNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", pathEscape(project), snippet, note) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteSnippetNote deletes an existing note of a snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#delete-a-snippet-note func (s *NotesService) DeleteSnippetNote(pid interface{}, snippet, note int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", pathEscape(project), snippet, note) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListMergeRequestNotesOptions represents the available ListMergeRequestNotes() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes type ListMergeRequestNotesOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListMergeRequestNotes gets a list of all notes for a single merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes func (s *NotesService) ListMergeRequestNotes(pid interface{}, mergeRequest int, opt *ListMergeRequestNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var n []*Note resp, err := s.client.Do(req, &n) if err != nil { return nil, resp, err } return n, resp, err } // GetMergeRequestNote returns a single note for a given merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#get-single-merge-request-note func (s *NotesService) GetMergeRequestNote(pid interface{}, mergeRequest, note int, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/notes/%d", pathEscape(project), mergeRequest, note) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // CreateMergeRequestNoteOptions represents the available // CreateMergeRequestNote() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note type CreateMergeRequestNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` } // CreateMergeRequestNote creates a new note for a single merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note func (s *NotesService) CreateMergeRequestNote(pid interface{}, mergeRequest int, opt *CreateMergeRequestNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", pathEscape(project), mergeRequest) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateMergeRequestNoteOptions represents the available // UpdateMergeRequestNote() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note type UpdateMergeRequestNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` } // UpdateMergeRequestNote modifies existing note of a merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note func (s *NotesService) UpdateMergeRequestNote(pid interface{}, mergeRequest, note int, opt *UpdateMergeRequestNoteOptions, options ...OptionFunc) (*Note, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf( "projects/%s/merge_requests/%d/notes/%d", pathEscape(project), mergeRequest, note) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteMergeRequestNote deletes an existing note of a merge request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notes.html#delete-a-merge-request-note func (s *NotesService) DeleteMergeRequestNote(pid interface{}, mergeRequest, note int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf( "projects/%s/merge_requests/%d/notes/%d", pathEscape(project), mergeRequest, note) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListEpicNotesOptions represents the available ListEpicNotes() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/notes.html#list-all-epic-notes type ListEpicNotesOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListEpicNotes gets a list of all notes for a single epic. // // GitLab API docs: // https://docs.gitlab.com/ee/api/notes.html#list-all-epic-notes func (s *NotesService) ListEpicNotes(gid interface{}, epic int, opt *ListEpicNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/notes", pathEscape(group), epic) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var n []*Note resp, err := s.client.Do(req, &n) if err != nil { return nil, resp, err } return n, resp, err } // GetEpicNote returns a single note for an epic. // // GitLab API docs: // https://docs.gitlab.com/ee/api/notes.html#get-single-epic-note func (s *NotesService) GetEpicNote(gid interface{}, epic, note int, options ...OptionFunc) (*Note, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", pathEscape(group), epic, note) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // CreateEpicNoteOptions represents the available CreateEpicNote() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/notes.html#create-new-epic-note type CreateEpicNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` } // CreateEpicNote creates a new note for a single merge request. // // GitLab API docs: // https://docs.gitlab.com/ee/api/notes.html#create-new-epic-note func (s *NotesService) CreateEpicNote(gid interface{}, epic int, opt *CreateEpicNoteOptions, options ...OptionFunc) (*Note, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/notes", pathEscape(group), epic) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // UpdateEpicNoteOptions represents the available UpdateEpicNote() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/notes.html#modify-existing-epic-note type UpdateEpicNoteOptions struct { Body *string `url:"body,omitempty" json:"body,omitempty"` } // UpdateEpicNote modifies existing note of an epic. // // https://docs.gitlab.com/ee/api/notes.html#modify-existing-epic-note func (s *NotesService) UpdateEpicNote(gid interface{}, epic, note int, opt *UpdateEpicNoteOptions, options ...OptionFunc) (*Note, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", pathEscape(group), epic, note) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } n := new(Note) resp, err := s.client.Do(req, n) if err != nil { return nil, resp, err } return n, resp, err } // DeleteEpicNote deletes an existing note of a merge request. // // https://docs.gitlab.com/ee/api/notes.html#delete-an-epic-note func (s *NotesService) DeleteEpicNote(gid interface{}, epic, note int, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", pathEscape(group), epic, note) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/notes_test.go000066400000000000000000000015371357140411500220630ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestGetEpicNote(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/1/epics/4329/notes/3", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":3,"type":null,"body":"foo bar","attachment":null,"system":false,"noteable_id":4392,"noteable_type":"Epic","resolvable":false,"noteable_iid":null}`) }) note, _, err := client.Notes.GetEpicNote("1", 4329, 3, nil) if err != nil { t.Fatal(err) } want := &Note{ ID: 3, Body: "foo bar", Attachment: "", Title: "", FileName: "", System: false, NoteableID: 4392, NoteableType: "Epic", } if !reflect.DeepEqual(note, want) { t.Errorf("Notes.GetEpicNote want %#v, got %#v", note, want) } } golang-github-xanzy-go-gitlab-0.22.2/notifications.go000066400000000000000000000171261357140411500225460ustar00rootroot00000000000000package gitlab import ( "errors" "fmt" ) // NotificationSettingsService handles communication with the notification settings // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/notification_settings.html type NotificationSettingsService struct { client *Client } // NotificationSettings represents the Gitlab notification setting. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings type NotificationSettings struct { Level NotificationLevelValue `json:"level"` NotificationEmail string `json:"notification_email"` Events *NotificationEvents `json:"events"` } // NotificationEvents represents the available notification setting events. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings type NotificationEvents struct { CloseIssue bool `json:"close_issue"` CloseMergeRequest bool `json:"close_merge_request"` FailedPipeline bool `json:"failed_pipeline"` MergeMergeRequest bool `json:"merge_merge_request"` NewIssue bool `json:"new_issue"` NewMergeRequest bool `json:"new_merge_request"` NewNote bool `json:"new_note"` ReassignIssue bool `json:"reassign_issue"` ReassignMergeRequest bool `json:"reassign_merge_request"` ReopenIssue bool `json:"reopen_issue"` ReopenMergeRequest bool `json:"reopen_merge_request"` SuccessPipeline bool `json:"success_pipeline"` } func (ns NotificationSettings) String() string { return Stringify(ns) } // GetGlobalSettings returns current notification settings and email address. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#global-notification-settings func (s *NotificationSettingsService) GetGlobalSettings(options ...OptionFunc) (*NotificationSettings, *Response, error) { u := "notification_settings" req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ns := new(NotificationSettings) resp, err := s.client.Do(req, ns) if err != nil { return nil, resp, err } return ns, resp, err } // NotificationSettingsOptions represents the available options that can be passed // to the API when updating the notification settings. type NotificationSettingsOptions struct { Level *NotificationLevelValue `url:"level,omitempty" json:"level,omitempty"` NotificationEmail *string `url:"notification_email,omitempty" json:"notification_email,omitempty"` CloseIssue *bool `url:"close_issue,omitempty" json:"close_issue,omitempty"` CloseMergeRequest *bool `url:"close_merge_request,omitempty" json:"close_merge_request,omitempty"` FailedPipeline *bool `url:"failed_pipeline,omitempty" json:"failed_pipeline,omitempty"` MergeMergeRequest *bool `url:"merge_merge_request,omitempty" json:"merge_merge_request,omitempty"` NewIssue *bool `url:"new_issue,omitempty" json:"new_issue,omitempty"` NewMergeRequest *bool `url:"new_merge_request,omitempty" json:"new_merge_request,omitempty"` NewNote *bool `url:"new_note,omitempty" json:"new_note,omitempty"` ReassignIssue *bool `url:"reassign_issue,omitempty" json:"reassign_issue,omitempty"` ReassignMergeRequest *bool `url:"reassign_merge_request,omitempty" json:"reassign_merge_request,omitempty"` ReopenIssue *bool `url:"reopen_issue,omitempty" json:"reopen_issue,omitempty"` ReopenMergeRequest *bool `url:"reopen_merge_request,omitempty" json:"reopen_merge_request,omitempty"` SuccessPipeline *bool `url:"success_pipeline,omitempty" json:"success_pipeline,omitempty"` } // UpdateGlobalSettings updates current notification settings and email address. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#update-global-notification-settings func (s *NotificationSettingsService) UpdateGlobalSettings(opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) { if opt.Level != nil && *opt.Level == GlobalNotificationLevel { return nil, nil, errors.New( "notification level 'global' is not valid for global notification settings") } u := "notification_settings" req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ns := new(NotificationSettings) resp, err := s.client.Do(req, ns) if err != nil { return nil, resp, err } return ns, resp, err } // GetSettingsForGroup returns current group notification settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings func (s *NotificationSettingsService) GetSettingsForGroup(gid interface{}, options ...OptionFunc) (*NotificationSettings, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/notification_settings", pathEscape(group)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ns := new(NotificationSettings) resp, err := s.client.Do(req, ns) if err != nil { return nil, resp, err } return ns, resp, err } // GetSettingsForProject returns current project notification settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings func (s *NotificationSettingsService) GetSettingsForProject(pid interface{}, options ...OptionFunc) (*NotificationSettings, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/notification_settings", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ns := new(NotificationSettings) resp, err := s.client.Do(req, ns) if err != nil { return nil, resp, err } return ns, resp, err } // UpdateSettingsForGroup updates current group notification settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings func (s *NotificationSettingsService) UpdateSettingsForGroup(gid interface{}, opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/notification_settings", pathEscape(group)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ns := new(NotificationSettings) resp, err := s.client.Do(req, ns) if err != nil { return nil, resp, err } return ns, resp, err } // UpdateSettingsForProject updates current project notification settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings func (s *NotificationSettingsService) UpdateSettingsForProject(pid interface{}, opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/notification_settings", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ns := new(NotificationSettings) resp, err := s.client.Do(req, ns) if err != nil { return nil, resp, err } return ns, resp, err } golang-github-xanzy-go-gitlab-0.22.2/pages_domains.go000066400000000000000000000130121357140411500224740ustar00rootroot00000000000000package gitlab import ( "fmt" "time" ) // PagesDomainsService handles communication with the pages domains // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/pages_domains.html type PagesDomainsService struct { client *Client } // PagesDomain represents a pages domain. // // GitLab API docs: https://docs.gitlab.com/ce/api/pages_domains.html type PagesDomain struct { Domain string `json:"domain"` URL string `json:"url"` ProjectID int `json:"project_id"` Verified bool `json:"verified"` VerificationCode string `json:"verification_code"` EnabledUntil *time.Time `json:"enabled_until"` Certificate struct { Expired bool `json:"expired"` Expiration *time.Time `json:"expiration"` } `json:"certificate"` } // ListPagesDomainsOptions represents the available ListPagesDomains() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#list-pages-domains type ListPagesDomainsOptions ListOptions // ListPagesDomains gets a list of project pages domains. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#list-pages-domains func (s *PagesDomainsService) ListPagesDomains(pid interface{}, opt *ListPagesDomainsOptions, options ...OptionFunc) ([]*PagesDomain, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pages/domains", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var pd []*PagesDomain resp, err := s.client.Do(req, &pd) if err != nil { return nil, resp, err } return pd, resp, err } // ListAllPagesDomains gets a list of all pages domains. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#list-all-pages-domains func (s *PagesDomainsService) ListAllPagesDomains(options ...OptionFunc) ([]*PagesDomain, *Response, error) { req, err := s.client.NewRequest("GET", "pages/domains", nil, options) if err != nil { return nil, nil, err } var pd []*PagesDomain resp, err := s.client.Do(req, &pd) if err != nil { return nil, resp, err } return pd, resp, err } // GetPagesDomain get a specific pages domain for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#single-pages-domain func (s *PagesDomainsService) GetPagesDomain(pid interface{}, domain string, options ...OptionFunc) (*PagesDomain, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pages/domains/%s", pathEscape(project), domain) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pd := new(PagesDomain) resp, err := s.client.Do(req, pd) if err != nil { return nil, resp, err } return pd, resp, err } // CreatePagesDomainOptions represents the available CreatePagesDomain() options. // // GitLab API docs: // // https://docs.gitlab.com/ce/api/pages_domains.html#create-new-pages-domain type CreatePagesDomainOptions struct { Domain *string `url:"domain,omitempty" json:"domain,omitempty"` Certificate *string `url:"certifiate,omitempty" json:"certifiate,omitempty"` Key *string `url:"key,omitempty" json:"key,omitempty"` } // CreatePagesDomain creates a new project pages domain. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#create-new-pages-domain func (s *PagesDomainsService) CreatePagesDomain(pid interface{}, opt *CreatePagesDomainOptions, options ...OptionFunc) (*PagesDomain, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pages/domains", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pd := new(PagesDomain) resp, err := s.client.Do(req, pd) if err != nil { return nil, resp, err } return pd, resp, err } // UpdatePagesDomainOptions represents the available UpdatePagesDomain() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#update-pages-domain type UpdatePagesDomainOptions struct { Cerificate *string `url:"certifiate" json:"certifiate"` Key *string `url:"key" json:"key"` } // UpdatePagesDomain updates an existing project pages domain. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#update-pages-domain func (s *PagesDomainsService) UpdatePagesDomain(pid interface{}, domain string, opt *UpdatePagesDomainOptions, options ...OptionFunc) (*PagesDomain, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pages/domains/%s", pathEscape(project), domain) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } pd := new(PagesDomain) resp, err := s.client.Do(req, pd) if err != nil { return nil, resp, err } return pd, resp, err } // DeletePagesDomain deletes an existing prject pages domain. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pages_domains.html#delete-pages-domain func (s *PagesDomainsService) DeletePagesDomain(pid interface{}, domain string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/pages/domains/%s", pathEscape(project), domain) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/pipeline_schedules.go000066400000000000000000000245171357140411500235430ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // PipelineSchedulesService handles communication with the pipeline // schedules related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipeline_schedules.html type PipelineSchedulesService struct { client *Client } // PipelineSchedule represents a pipeline schedule. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html type PipelineSchedule struct { ID int `json:"id"` Description string `json:"description"` Ref string `json:"ref"` Cron string `json:"cron"` CronTimezone string `json:"cron_timezone"` NextRunAt *time.Time `json:"next_run_at"` Active bool `json:"active"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` Owner *User `json:"owner"` LastPipeline struct { ID int `json:"id"` SHA string `json:"sha"` Ref string `json:"ref"` Status string `json:"status"` } `json:"last_pipeline"` Variables []*PipelineVariable `json:"variables"` } // ListPipelineSchedulesOptions represents the available ListPipelineTriggers() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers type ListPipelineSchedulesOptions ListOptions // ListPipelineSchedules gets a list of project triggers. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html func (s *PipelineSchedulesService) ListPipelineSchedules(pid interface{}, opt *ListPipelineSchedulesOptions, options ...OptionFunc) ([]*PipelineSchedule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ps []*PipelineSchedule resp, err := s.client.Do(req, &ps) if err != nil { return nil, resp, err } return ps, resp, err } // GetPipelineSchedule gets a pipeline schedule. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html func (s *PipelineSchedulesService) GetPipelineSchedule(pid interface{}, schedule int, options ...OptionFunc) (*PipelineSchedule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", pathEscape(project), schedule) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } p := new(PipelineSchedule) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // CreatePipelineScheduleOptions represents the available // CreatePipelineSchedule() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule type CreatePipelineScheduleOptions struct { Description *string `url:"description" json:"description"` Ref *string `url:"ref" json:"ref"` Cron *string `url:"cron" json:"cron"` CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"` Active *bool `url:"active,omitempty" json:"active,omitempty"` } // CreatePipelineSchedule creates a pipeline schedule. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule func (s *PipelineSchedulesService) CreatePipelineSchedule(pid interface{}, opt *CreatePipelineScheduleOptions, options ...OptionFunc) (*PipelineSchedule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } p := new(PipelineSchedule) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // EditPipelineScheduleOptions represents the available // EditPipelineSchedule() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule type EditPipelineScheduleOptions struct { Description *string `url:"description,omitempty" json:"description,omitempty"` Ref *string `url:"ref,omitempty" json:"ref,omitempty"` Cron *string `url:"cron,omitempty" json:"cron,omitempty"` CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"` Active *bool `url:"active,omitempty" json:"active,omitempty"` } // EditPipelineSchedule edits a pipeline schedule. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule func (s *PipelineSchedulesService) EditPipelineSchedule(pid interface{}, schedule int, opt *EditPipelineScheduleOptions, options ...OptionFunc) (*PipelineSchedule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", pathEscape(project), schedule) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } p := new(PipelineSchedule) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // TakeOwnershipOfPipelineSchedule sets the owner of the specified // pipeline schedule to the user issuing the request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#take-ownership-of-a-pipeline-schedule func (s *PipelineSchedulesService) TakeOwnershipOfPipelineSchedule(pid interface{}, schedule int, options ...OptionFunc) (*PipelineSchedule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/take_ownership", pathEscape(project), schedule) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } p := new(PipelineSchedule) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // DeletePipelineSchedule deletes a pipeline schedule. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#delete-a-pipeline-schedule func (s *PipelineSchedulesService) DeletePipelineSchedule(pid interface{}, schedule int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", pathEscape(project), schedule) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // CreatePipelineScheduleVariableOptions represents the available // CreatePipelineScheduleVariable() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule type CreatePipelineScheduleVariableOptions struct { Key *string `url:"key" json:"key"` Value *string `url:"value" json:"value"` VariableType *string `url:"variable_type,omitempty" json:"variable_type,omitempty"` } // CreatePipelineScheduleVariable creates a pipeline schedule variable. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule func (s *PipelineSchedulesService) CreatePipelineScheduleVariable(pid interface{}, schedule int, opt *CreatePipelineScheduleVariableOptions, options ...OptionFunc) (*PipelineVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables", pathEscape(project), schedule) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } p := new(PipelineVariable) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // EditPipelineScheduleVariableOptions represents the available // EditPipelineScheduleVariable() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule-variable type EditPipelineScheduleVariableOptions struct { Value *string `url:"value" json:"value"` VariableType *string `url:"variable_type,omitempty" json:"variable_type,omitempty"` } // EditPipelineScheduleVariable creates a pipeline schedule variable. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule-variable func (s *PipelineSchedulesService) EditPipelineScheduleVariable(pid interface{}, schedule int, key string, opt *EditPipelineScheduleVariableOptions, options ...OptionFunc) (*PipelineVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables/%s", pathEscape(project), schedule, key) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } p := new(PipelineVariable) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // DeletePipelineScheduleVariable creates a pipeline schedule variable. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_schedules.html#delete-a-pipeline-schedule-variable func (s *PipelineSchedulesService) DeletePipelineScheduleVariable(pid interface{}, schedule int, key string, options ...OptionFunc) (*PipelineVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables/%s", pathEscape(project), schedule, key) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, nil, err } p := new(PipelineVariable) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } golang-github-xanzy-go-gitlab-0.22.2/pipeline_triggers.go000066400000000000000000000154221357140411500234050ustar00rootroot00000000000000package gitlab import ( "fmt" "time" ) // PipelineTriggersService handles Project pipeline triggers. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html type PipelineTriggersService struct { client *Client } // PipelineTrigger represents a project pipeline trigger. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#pipeline-triggers type PipelineTrigger struct { ID int `json:"id"` Description string `json:"description"` CreatedAt *time.Time `json:"created_at"` DeletedAt *time.Time `json:"deleted_at"` LastUsed *time.Time `json:"last_used"` Token string `json:"token"` UpdatedAt *time.Time `json:"updated_at"` Owner *User `json:"owner"` } // ListPipelineTriggersOptions represents the available ListPipelineTriggers() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers type ListPipelineTriggersOptions ListOptions // ListPipelineTriggers gets a list of project triggers. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers func (s *PipelineTriggersService) ListPipelineTriggers(pid interface{}, opt *ListPipelineTriggersOptions, options ...OptionFunc) ([]*PipelineTrigger, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/triggers", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var pt []*PipelineTrigger resp, err := s.client.Do(req, &pt) if err != nil { return nil, resp, err } return pt, resp, err } // GetPipelineTrigger gets a specific pipeline trigger for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#get-trigger-details func (s *PipelineTriggersService) GetPipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*PipelineTrigger, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/triggers/%d", pathEscape(project), trigger) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pt := new(PipelineTrigger) resp, err := s.client.Do(req, pt) if err != nil { return nil, resp, err } return pt, resp, err } // AddPipelineTriggerOptions represents the available AddPipelineTrigger() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger type AddPipelineTriggerOptions struct { Description *string `url:"description,omitempty" json:"description,omitempty"` } // AddPipelineTrigger adds a pipeline trigger to a specified project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger func (s *PipelineTriggersService) AddPipelineTrigger(pid interface{}, opt *AddPipelineTriggerOptions, options ...OptionFunc) (*PipelineTrigger, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/triggers", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pt := new(PipelineTrigger) resp, err := s.client.Do(req, pt) if err != nil { return nil, resp, err } return pt, resp, err } // EditPipelineTriggerOptions represents the available EditPipelineTrigger() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger type EditPipelineTriggerOptions struct { Description *string `url:"description,omitempty" json:"description,omitempty"` } // EditPipelineTrigger edits a trigger for a specified project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger func (s *PipelineTriggersService) EditPipelineTrigger(pid interface{}, trigger int, opt *EditPipelineTriggerOptions, options ...OptionFunc) (*PipelineTrigger, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/triggers/%d", pathEscape(project), trigger) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } pt := new(PipelineTrigger) resp, err := s.client.Do(req, pt) if err != nil { return nil, resp, err } return pt, resp, err } // TakeOwnershipOfPipelineTrigger sets the owner of the specified // pipeline trigger to the user issuing the request. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#take-ownership-of-a-project-trigger func (s *PipelineTriggersService) TakeOwnershipOfPipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*PipelineTrigger, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/triggers/%d/take_ownership", pathEscape(project), trigger) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } pt := new(PipelineTrigger) resp, err := s.client.Do(req, pt) if err != nil { return nil, resp, err } return pt, resp, err } // DeletePipelineTrigger removes a trigger from a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipeline_triggers.html#remove-a-project-trigger func (s *PipelineTriggersService) DeletePipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/triggers/%d", pathEscape(project), trigger) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // RunPipelineTriggerOptions represents the available RunPipelineTrigger() options. // // GitLab API docs: // https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline type RunPipelineTriggerOptions struct { Ref *string `url:"ref" json:"ref"` Token *string `url:"token" json:"token"` Variables map[string]string `url:"variables,omitempty" json:"variables,omitempty"` } // RunPipelineTrigger starts a trigger from a project. // // GitLab API docs: // https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline func (s *PipelineTriggersService) RunPipelineTrigger(pid interface{}, opt *RunPipelineTriggerOptions, options ...OptionFunc) (*Pipeline, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/trigger/pipeline", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pt := new(Pipeline) resp, err := s.client.Do(req, pt) if err != nil { return nil, resp, err } return pt, resp, err } golang-github-xanzy-go-gitlab-0.22.2/pipeline_triggers_test.go000066400000000000000000000013571357140411500244460ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestRunPipeline(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/trigger/pipeline", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1, "status":"pending"}`) }) opt := &RunPipelineTriggerOptions{Ref: String("master")} pipeline, _, err := client.PipelineTriggers.RunPipelineTrigger(1, opt) if err != nil { t.Errorf("PipelineTriggers.RunPipelineTrigger returned error: %v", err) } want := &Pipeline{ID: 1, Status: "pending"} if !reflect.DeepEqual(want, pipeline) { t.Errorf("PipelineTriggers.RunPipelineTrigger returned %+v, want %+v", pipeline, want) } } golang-github-xanzy-go-gitlab-0.22.2/pipelines.go000066400000000000000000000213661357140411500216660ustar00rootroot00000000000000// // Copyright 2017, Igor Varavko // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // PipelinesService handles communication with the repositories related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html type PipelinesService struct { client *Client } // PipelineVariable represents a pipeline variable. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html type PipelineVariable struct { Key string `json:"key"` Value string `json:"value"` VariableType string `json:"variable_type"` } // Pipeline represents a GitLab pipeline. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html type Pipeline struct { ID int `json:"id"` Status string `json:"status"` Ref string `json:"ref"` SHA string `json:"sha"` BeforeSHA string `json:"before_sha"` Tag bool `json:"tag"` YamlErrors string `json:"yaml_errors"` User *BasicUser `json:"user"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` StartedAt *time.Time `json:"started_at"` FinishedAt *time.Time `json:"finished_at"` CommittedAt *time.Time `json:"committed_at"` Duration int `json:"duration"` Coverage string `json:"coverage"` WebURL string `json:"web_url"` DetailedStatus *DetailedStatus `json:"detailed_status"` } // DetailedStatus contains detailed information about the status of a pipeline type DetailedStatus struct { Icon string `json:"icon"` Text string `json:"text"` Label string `json:"label"` Group string `json:"group"` Tooltip string `json:"tooltip"` HasDetails bool `json:"has_details"` DetailsPath string `json:"details_path"` Illustration struct { Image string `json:"image"` } `json:"illustration"` Favicon string `json:"favicon"` } func (p Pipeline) String() string { return Stringify(p) } // PipelineInfo shows the basic entities of a pipeline, mostly used as fields // on other assets, like Commit. type PipelineInfo struct { ID int `json:"id"` Status string `json:"status"` Ref string `json:"ref"` SHA string `json:"sha"` WebURL string `json:"web_url"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` } func (p PipelineInfo) String() string { return Stringify(p) } // ListProjectPipelinesOptions represents the available ListProjectPipelines() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#list-project-pipelines type ListProjectPipelinesOptions struct { ListOptions Scope *string `url:"scope,omitempty" json:"scope,omitempty"` Status *BuildStateValue `url:"status,omitempty" json:"status,omitempty"` Ref *string `url:"ref,omitempty" json:"ref,omitempty"` SHA *string `url:"sha,omitempty" json:"sha,omitempty"` YamlErrors *bool `url:"yaml_errors,omitempty" json:"yaml_errors,omitempty"` Name *string `url:"name,omitempty" json:"name,omitempty"` Username *string `url:"username,omitempty" json:"username,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListProjectPipelines gets a list of project piplines. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#list-project-pipelines func (s *PipelinesService) ListProjectPipelines(pid interface{}, opt *ListProjectPipelinesOptions, options ...OptionFunc) ([]*PipelineInfo, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipelines", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var p []*PipelineInfo resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // GetPipeline gets a single project pipeline. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#get-a-single-pipeline func (s *PipelinesService) GetPipeline(pid interface{}, pipeline int, options ...OptionFunc) (*Pipeline, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipelines/%d", pathEscape(project), pipeline) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } p := new(Pipeline) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // GetPipelineVariables gets the variables of a single project pipeline. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#get-variables-of-a-pipeline func (s *PipelinesService) GetPipelineVariables(pid interface{}, pipeline int, options ...OptionFunc) ([]*PipelineVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipelines/%d/variables", pathEscape(project), pipeline) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var p []*PipelineVariable resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // CreatePipelineOptions represents the available CreatePipeline() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline type CreatePipelineOptions struct { Ref *string `url:"ref" json:"ref"` Variables []*PipelineVariable `url:"variables,omitempty" json:"variables,omitempty"` } // CreatePipeline creates a new project pipeline. // // GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline func (s *PipelinesService) CreatePipeline(pid interface{}, opt *CreatePipelineOptions, options ...OptionFunc) (*Pipeline, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipeline", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } p := new(Pipeline) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // RetryPipelineBuild retries failed builds in a pipeline // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipelines.html#retry-failed-builds-in-a-pipeline func (s *PipelinesService) RetryPipelineBuild(pid interface{}, pipeline int, options ...OptionFunc) (*Pipeline, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipelines/%d/retry", pathEscape(project), pipeline) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } p := new(Pipeline) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // CancelPipelineBuild cancels a pipeline builds // // GitLab API docs: //https://docs.gitlab.com/ce/api/pipelines.html#cancel-a-pipelines-builds func (s *PipelinesService) CancelPipelineBuild(pid interface{}, pipeline int, options ...OptionFunc) (*Pipeline, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/pipelines/%d/cancel", pathEscape(project), pipeline) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } p := new(Pipeline) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // DeletePipeline deletes an existing pipeline. // // GitLab API docs: // https://docs.gitlab.com/ce/api/pipelines.html#delete-a-pipeline func (s *PipelinesService) DeletePipeline(pid interface{}, pipeline int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/pipelines/%d", pathEscape(project), pipeline) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/pipelines_test.go000066400000000000000000000104221357140411500227140ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestListProjectPipelines(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipelines", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectPipelinesOptions{Ref: String("master")} piplines, _, err := client.Pipelines.ListProjectPipelines(1, opt) if err != nil { t.Errorf("Pipelines.ListProjectPipelines returned error: %v", err) } want := []*PipelineInfo{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, piplines) { t.Errorf("Pipelines.ListProjectPipelines returned %+v, want %+v", piplines, want) } } func TestGetPipeline(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipelines/5949167", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1,"status":"success"}`) }) pipeline, _, err := client.Pipelines.GetPipeline(1, 5949167) if err != nil { t.Errorf("Pipelines.GetPipeline returned error: %v", err) } want := &Pipeline{ID: 1, Status: "success"} if !reflect.DeepEqual(want, pipeline) { t.Errorf("Pipelines.GetPipeline returned %+v, want %+v", pipeline, want) } } func TestGetPipelineVariables(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipelines/5949167/variables", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"key":"RUN_NIGHTLY_BUILD","variable_type":"env_var","value":"true"},{"key":"foo","value":"bar"}]`) }) variables, _, err := client.Pipelines.GetPipelineVariables(1, 5949167) if err != nil { t.Errorf("Pipelines.GetPipelineVariables returned error: %v", err) } want := []*PipelineVariable{{Key: "RUN_NIGHTLY_BUILD", Value: "true", VariableType: "env_var"}, {Key: "foo", Value: "bar"}} if !reflect.DeepEqual(want, variables) { t.Errorf("Pipelines.GetPipelineVariables returned %+v, want %+v", variables, want) } } func TestCreatePipeline(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipeline", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1, "status":"pending"}`) }) opt := &CreatePipelineOptions{Ref: String("master")} pipeline, _, err := client.Pipelines.CreatePipeline(1, opt) if err != nil { t.Errorf("Pipelines.CreatePipeline returned error: %v", err) } want := &Pipeline{ID: 1, Status: "pending"} if !reflect.DeepEqual(want, pipeline) { t.Errorf("Pipelines.CreatePipeline returned %+v, want %+v", pipeline, want) } } func TestRetryPipelineBuild(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipelines/5949167/retry", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprintln(w, `{"id":1, "status":"pending"}`) }) pipeline, _, err := client.Pipelines.RetryPipelineBuild(1, 5949167) if err != nil { t.Errorf("Pipelines.RetryPipelineBuild returned error: %v", err) } want := &Pipeline{ID: 1, Status: "pending"} if !reflect.DeepEqual(want, pipeline) { t.Errorf("Pipelines.RetryPipelineBuild returned %+v, want %+v", pipeline, want) } } func TestCancelPipelineBuild(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipelines/5949167/cancel", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprintln(w, `{"id":1, "status":"canceled"}`) }) pipeline, _, err := client.Pipelines.CancelPipelineBuild(1, 5949167) if err != nil { t.Errorf("Pipelines.CancelPipelineBuild returned error: %v", err) } want := &Pipeline{ID: 1, Status: "canceled"} if !reflect.DeepEqual(want, pipeline) { t.Errorf("Pipelines.CancelPipelineBuild returned %+v, want %+v", pipeline, want) } } func TestDeletePipeline(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/pipelines/5949167", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) _, err := client.Pipelines.DeletePipeline("1", 5949167) if err != nil { t.Errorf("Pipelines.DeletePipeline returned error: %v", err) } } golang-github-xanzy-go-gitlab-0.22.2/project_badges.go000066400000000000000000000141621357140411500226450ustar00rootroot00000000000000package gitlab import ( "fmt" ) // ProjectBadge represents a project badge. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project type ProjectBadge struct { ID int `json:"id"` LinkURL string `json:"link_url"` ImageURL string `json:"image_url"` RenderedLinkURL string `json:"rendered_link_url"` RenderedImageURL string `json:"rendered_image_url"` // Kind represents a project badge kind. Can be empty, when used PreviewProjectBadge(). Kind string `json:"kind"` } // ProjectBadgesService handles communication with the project badges // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ee/api/project_badges.html type ProjectBadgesService struct { client *Client } // ListProjectBadgesOptions represents the available ListProjectBadges() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project type ListProjectBadgesOptions ListOptions // ListProjectBadges gets a list of a project's badges and its group badges. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project func (s *ProjectBadgesService) ListProjectBadges(pid interface{}, opt *ListProjectBadgesOptions, options ...OptionFunc) ([]*ProjectBadge, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/badges", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var pb []*ProjectBadge resp, err := s.client.Do(req, &pb) if err != nil { return nil, resp, err } return pb, resp, err } // GetProjectBadge gets a project badge. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#get-a-badge-of-a-project func (s *ProjectBadgesService) GetProjectBadge(pid interface{}, badge int, options ...OptionFunc) (*ProjectBadge, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/badges/%d", pathEscape(project), badge) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pb := new(ProjectBadge) resp, err := s.client.Do(req, pb) if err != nil { return nil, resp, err } return pb, resp, err } // AddProjectBadgeOptions represents the available AddProjectBadge() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#add-a-badge-to-a-project type AddProjectBadgeOptions struct { LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` } // AddProjectBadge adds a badge to a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#add-a-badge-to-a-project func (s *ProjectBadgesService) AddProjectBadge(pid interface{}, opt *AddProjectBadgeOptions, options ...OptionFunc) (*ProjectBadge, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/badges", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pb := new(ProjectBadge) resp, err := s.client.Do(req, pb) if err != nil { return nil, resp, err } return pb, resp, err } // EditProjectBadgeOptions represents the available EditProjectBadge() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#edit-a-badge-of-a-project type EditProjectBadgeOptions struct { LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` } // EditProjectBadge updates a badge of a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#edit-a-badge-of-a-project func (s *ProjectBadgesService) EditProjectBadge(pid interface{}, badge int, opt *EditProjectBadgeOptions, options ...OptionFunc) (*ProjectBadge, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/badges/%d", pathEscape(project), badge) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } pb := new(ProjectBadge) resp, err := s.client.Do(req, pb) if err != nil { return nil, resp, err } return pb, resp, err } // DeleteProjectBadge removes a badge from a project. Only project's // badges will be removed by using this endpoint. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#remove-a-badge-from-a-project func (s *ProjectBadgesService) DeleteProjectBadge(pid interface{}, badge int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/badges/%d", pathEscape(project), badge) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ProjectBadgePreviewOptions represents the available PreviewProjectBadge() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#preview-a-badge-from-a-project type ProjectBadgePreviewOptions struct { LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` } // PreviewProjectBadge returns how the link_url and image_url final URLs would be after // resolving the placeholder interpolation. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_badges.html#preview-a-badge-from-a-project func (s *ProjectBadgesService) PreviewProjectBadge(pid interface{}, opt *ProjectBadgePreviewOptions, options ...OptionFunc) (*ProjectBadge, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/badges/render", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } pb := new(ProjectBadge) resp, err := s.client.Do(req, &pb) if err != nil { return nil, resp, err } return pb, resp, err } golang-github-xanzy-go-gitlab-0.22.2/project_clusters.go000066400000000000000000000173261357140411500232710ustar00rootroot00000000000000// // Copyright 2019, Matej Velikonja // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // ProjectClustersService handles communication with the // project clusters related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html type ProjectClustersService struct { client *Client } // ProjectCluster represents a GitLab Project Cluster. // // GitLab API docs: https://docs.gitlab.com/ee/api/project_clusters.html type ProjectCluster struct { ID int `json:"id"` Name string `json:"name"` Domain string `json:"domain"` CreatedAt *time.Time `json:"created_at"` ProviderType string `json:"provider_type"` PlatformType string `json:"platform_type"` EnvironmentScope string `json:"environment_scope"` ClusterType string `json:"cluster_type"` User *User `json:"user"` PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"` Project *Project `json:"project"` } func (v ProjectCluster) String() string { return Stringify(v) } // PlatformKubernetes represents a GitLab Project Cluster PlatformKubernetes. type PlatformKubernetes struct { APIURL string `json:"api_url"` Token string `json:"token"` CaCert string `json:"ca_cert"` Namespace string `json:"namespace"` AuthorizationType string `json:"authorization_type"` } // ListClusters gets a list of all clusters in a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html#list-project-clusters func (s *ProjectClustersService) ListClusters(pid interface{}, options ...OptionFunc) ([]*ProjectCluster, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/clusters", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var pcs []*ProjectCluster resp, err := s.client.Do(req, &pcs) if err != nil { return nil, resp, err } return pcs, resp, err } // GetCluster gets a cluster. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html#get-a-single-project-cluster func (s *ProjectClustersService) GetCluster(pid interface{}, cluster int, options ...OptionFunc) (*ProjectCluster, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/clusters/%d", pathEscape(project), cluster) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pc := new(ProjectCluster) resp, err := s.client.Do(req, &pc) if err != nil { return nil, resp, err } return pc, resp, err } // AddClusterOptions represents the available AddCluster() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project type AddClusterOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Domain *string `url:"domain,omitempty" json:"domain,omitempty"` Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` Managed *bool `url:"managed,omitempty" json:"managed,omitempty"` EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` PlatformKubernetes *AddPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` } // AddPlatformKubernetesOptions represents the available PlatformKubernetes options for adding. type AddPlatformKubernetesOptions struct { APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` Token *string `url:"token,omitempty" json:"token,omitempty"` CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` AuthorizationType *string `url:"authorization_type,omitempty" json:"authorization_type,omitempty"` } // AddCluster adds an existing cluster to the project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project func (s *ProjectClustersService) AddCluster(pid interface{}, opt *AddClusterOptions, options ...OptionFunc) (*ProjectCluster, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/clusters/user", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pc := new(ProjectCluster) resp, err := s.client.Do(req, pc) if err != nil { return nil, resp, err } return pc, resp, err } // EditClusterOptions represents the available EditCluster() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster type EditClusterOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Domain *string `url:"domain,omitempty" json:"domain,omitempty"` EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` PlatformKubernetes *EditPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` } // EditPlatformKubernetesOptions represents the available PlatformKubernetes options for editing. type EditPlatformKubernetesOptions struct { APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` Token *string `url:"token,omitempty" json:"token,omitempty"` CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` } // EditCluster updates an existing project cluster. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster func (s *ProjectClustersService) EditCluster(pid interface{}, cluster int, opt *EditClusterOptions, options ...OptionFunc) (*ProjectCluster, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/clusters/%d", pathEscape(project), cluster) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } pc := new(ProjectCluster) resp, err := s.client.Do(req, pc) if err != nil { return nil, resp, err } return pc, resp, err } // DeleteCluster deletes an existing project cluster. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_clusters.html#delete-project-cluster func (s *ProjectClustersService) DeleteCluster(pid interface{}, cluster int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/clusters/%d", pathEscape(project), cluster) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/project_clusters_test.go000066400000000000000000000215341357140411500243240ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "testing" ) func TestListClusters(t *testing.T) { mux, server, client := setup() defer teardown(server) pid := 1234 mux.HandleFunc("/api/v4/projects/1234/clusters", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") response := `[ { "id":18, "name":"cluster-1", "domain":"example.com", "created_at":"2019-01-02T20:18:12.563Z", "provider_type":"user", "platform_type":"kubernetes", "environment_scope":"*", "cluster_type":"project_type", "user": { "id":1, "name":"Administrator", "username":"root", "state":"active", "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..", "web_url":"https://gitlab.example.com/root" }, "platform_kubernetes": { "api_url":"https://104.197.68.152", "namespace":"cluster-1-namespace", "authorization_type":"rbac", "ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----" } } ]` fmt.Fprint(w, response) }) clusters, _, err := client.ProjectCluster.ListClusters(pid) if err != nil { t.Errorf("ProjectClusters.ListClusters returned error: %v", err) } if len(clusters) != 1 { t.Errorf("expected 1 cluster; got %d", len(clusters)) } if clusters[0].ID != 18 { t.Errorf("expected clusterID 1; got %d", clusters[0].ID) } if clusters[0].Domain != "example.com" { t.Errorf("expected cluster domain example.com; got %q", clusters[0].Domain) } } func TestGetCluster(t *testing.T) { mux, server, client := setup() defer teardown(server) pid := 1234 mux.HandleFunc("/api/v4/projects/1234/clusters/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") response := `{ "id":18, "name":"cluster-1", "domain":"example.com", "created_at":"2019-01-02T20:18:12.563Z", "provider_type":"user", "platform_type":"kubernetes", "environment_scope":"*", "cluster_type":"project_type", "user": { "id":1, "name":"Administrator", "username":"root", "state":"active", "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..", "web_url":"https://gitlab.example.com/root" }, "platform_kubernetes": { "api_url":"https://104.197.68.152", "namespace":"cluster-1-namespace", "authorization_type":"rbac", "ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----" }, "project": { "id":26, "description":"", "name":"project-with-clusters-api", "name_with_namespace":"Administrator / project-with-clusters-api", "path":"project-with-clusters-api", "path_with_namespace":"root/project-with-clusters-api", "created_at":"2019-01-02T20:13:32.600Z", "default_branch":null, "tag_list":[], "ssh_url_to_repo":"ssh://gitlab.example.com/root/project-with-clusters-api.git", "http_url_to_repo":"https://gitlab.example.com/root/project-with-clusters-api.git", "web_url":"https://gitlab.example.com/root/project-with-clusters-api", "readme_url":null, "avatar_url":null, "star_count":0, "forks_count":0, "last_activity_at":"2019-01-02T20:13:32.600Z", "namespace": { "id":1, "name":"root", "path":"root", "kind":"user", "full_path":"root", "parent_id":null } } }` fmt.Fprint(w, response) }) cluster, _, err := client.ProjectCluster.GetCluster(pid, 1) if err != nil { t.Errorf("ProjectClusters.ListClusters returned error: %v", err) } if cluster.ID != 18 { t.Errorf("expected clusterID 18; got %d", cluster.ID) } if cluster.Domain != "example.com" { t.Errorf("expected cluster domain example.com; got %q", cluster.Domain) } } func TestAddCluster(t *testing.T) { mux, server, client := setup() defer teardown(server) pid := 1234 mux.HandleFunc("/api/v4/projects/1234/clusters/user", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") response := `{ "id":24, "name":"cluster-5", "domain":"example.com", "created_at":"2019-01-03T21:53:40.610Z", "provider_type":"user", "platform_type":"kubernetes", "environment_scope":"*", "cluster_type":"project_type", "user": { "id":1, "name":"Administrator", "username":"root", "state":"active", "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..", "web_url":"https://gitlab.example.com/root" }, "platform_kubernetes": { "api_url":"https://35.111.51.20", "namespace":"cluster-5-namespace", "authorization_type":"rbac", "ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----" }, "project": { "id":26, "description":"", "name":"project-with-clusters-api", "name_with_namespace":"Administrator / project-with-clusters-api", "path":"project-with-clusters-api", "path_with_namespace":"root/project-with-clusters-api", "created_at":"2019-01-02T20:13:32.600Z", "default_branch":null, "tag_list":[], "ssh_url_to_repo":"ssh:://gitlab.example.com/root/project-with-clusters-api.git", "http_url_to_repo":"https://gitlab.example.com/root/project-with-clusters-api.git", "web_url":"https://gitlab.example.com/root/project-with-clusters-api", "readme_url":null, "avatar_url":null, "star_count":0, "forks_count":0, "last_activity_at":"2019-01-02T20:13:32.600Z", "namespace": { "id":1, "name":"root", "path":"root", "kind":"user", "full_path":"root", "parent_id":null } } }` fmt.Fprint(w, response) }) cluster, _, err := client.ProjectCluster.AddCluster(pid, &AddClusterOptions{}) if err != nil { t.Errorf("ProjectClusters.AddCluster returned error: %v", err) } if cluster.ID != 24 { t.Errorf("expected ClusterID 24; got %d", cluster.ID) } } func TestEditCluster(t *testing.T) { mux, server, client := setup() defer teardown(server) pid := 1234 mux.HandleFunc("/api/v4/projects/1234/clusters/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") response := `{ "id":24, "name":"new-cluster-name", "domain":"example.com", "created_at":"2019-01-03T21:53:40.610Z", "provider_type":"user", "platform_type":"kubernetes", "environment_scope":"*", "cluster_type":"project_type", "user": { "id":1, "name":"Administrator", "username":"root", "state":"active", "avatar_url":"https://www.gravatar.com/avatar/4249f4df72b..", "web_url":"https://gitlab.example.com/root" }, "platform_kubernetes": { "api_url":"https://new-api-url.com", "namespace":"cluster-5-namespace", "authorization_type":"rbac", "ca_cert":null }, "project": { "id":26, "description":"", "name":"project-with-clusters-api", "name_with_namespace":"Administrator / project-with-clusters-api", "path":"project-with-clusters-api", "path_with_namespace":"root/project-with-clusters-api", "created_at":"2019-01-02T20:13:32.600Z", "default_branch":null, "tag_list":[], "ssh_url_to_repo":"ssh:://gitlab.example.com/root/project-with-clusters-api.git", "http_url_to_repo":"https://gitlab.example.com/root/project-with-clusters-api.git", "web_url":"https://gitlab.example.com/root/project-with-clusters-api", "readme_url":null, "avatar_url":null, "star_count":0, "forks_count":0, "last_activity_at":"2019-01-02T20:13:32.600Z", "namespace": { "id":1, "name":"root", "path":"root", "kind":"user", "full_path":"root", "parent_id":null } } }` fmt.Fprint(w, response) }) cluster, _, err := client.ProjectCluster.EditCluster(pid, 1, &EditClusterOptions{}) if err != nil { t.Errorf("ProjectClusters.EditCluster returned error: %v", err) } if cluster.ID != 24 { t.Errorf("expected ClusterID 24; got %d", cluster.ID) } } func TestDeleteCluster(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1234/clusters/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusAccepted) }) resp, err := client.ProjectCluster.DeleteCluster(1234, 1) if err != nil { t.Errorf("ProjectCluster.DeleteCluster returned error: %v", err) } want := http.StatusAccepted got := resp.StatusCode if got != want { t.Errorf("ProjectCluster.DeleteCluster returned %d, want %d", got, want) } } golang-github-xanzy-go-gitlab-0.22.2/project_import_export.go000066400000000000000000000134401357140411500243310ustar00rootroot00000000000000package gitlab import ( "bytes" "fmt" "time" ) // ProjectImportExportService handles communication with the project // import/export related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ce/user/project/settings/import_export.html type ProjectImportExportService struct { client *Client } // ImportStatus represents a project import status. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#import-status type ImportStatus struct { ID int `json:"id"` Description string `json:"description"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` CreateAt *time.Time `json:"create_at"` ImportStatus string `json:"import_status"` } func (s ImportStatus) String() string { return Stringify(s) } // ExportStatus represents a project export status. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#export-status type ExportStatus struct { ID int `json:"id"` Description string `json:"description"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` CreatedAt *time.Time `json:"created_at"` ExportStatus string `json:"export_status"` Message string `json:"message"` Links struct { APIURL string `json:"api_url"` WebURL string `json:"web_url"` } `json:"_links"` } func (s ExportStatus) String() string { return Stringify(s) } // ScheduleExportOptions represents the available ScheduleExport() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#schedule-an-export type ScheduleExportOptions struct { Description *string `url:"description,omitempty" json:"description,omitempty"` Upload struct { URL *string `url:"url,omitempty" json:"url,omitempty"` HTTPMethod *string `url:"http_method,omitempty" json:"http_method,omitempty"` } `url:"upload,omitempty" json:"upload,omitempty"` } // ScheduleExport schedules a project export. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#schedule-an-export func (s *ProjectImportExportService) ScheduleExport(pid interface{}, opt *ScheduleExportOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/export", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ExportStatus get the status of export. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#export-status func (s *ProjectImportExportService) ExportStatus(pid interface{}, options ...OptionFunc) (*ExportStatus, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/export", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } es := new(ExportStatus) resp, err := s.client.Do(req, es) if err != nil { return nil, resp, err } return es, resp, err } // ExportDownload download the finished export. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#export-download func (s *ProjectImportExportService) ExportDownload(pid interface{}, options ...OptionFunc) ([]byte, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/export/download", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var b bytes.Buffer resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b.Bytes(), resp, err } // ImportFileOptions represents the available ImportFile() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#import-a-file type ImportFileOptions struct { Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` File *string `url:"file,omitempty" json:"file,omitempty"` Path *string `url:"path,omitempty" json:"path,omitempty"` Overwrite *bool `url:"overwrite,omitempty" json:"overwrite,omitempty"` OverrideParams *CreateProjectOptions `url:"override_params,omitempty" json:"override_params,omitempty"` } // ImportFile import a file. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#import-a-file func (s *ProjectImportExportService) ImportFile(opt *ImportFileOptions, options ...OptionFunc) (*ImportStatus, *Response, error) { req, err := s.client.NewRequest("POST", "projects/import", opt, options) if err != nil { return nil, nil, err } is := new(ImportStatus) resp, err := s.client.Do(req, is) if err != nil { return nil, resp, err } return is, resp, err } // ImportStatus get the status of an import. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_import_export.html#import-status func (s *ProjectImportExportService) ImportStatus(pid interface{}, options ...OptionFunc) (*ImportStatus, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/import", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } is := new(ImportStatus) resp, err := s.client.Do(req, is) if err != nil { return nil, resp, err } return is, resp, err } golang-github-xanzy-go-gitlab-0.22.2/project_members.go000066400000000000000000000147111357140411500230520ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // ProjectMembersService handles communication with the project members // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/members.html type ProjectMembersService struct { client *Client } // ListProjectMembersOptions represents the available ListProjectMembers() and // ListAllProjectMembers() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project type ListProjectMembersOptions struct { ListOptions Query *string `url:"query,omitempty" json:"query,omitempty"` } // ListProjectMembers gets a list of a project's team members viewable by the // authenticated user. Returns only direct members and not inherited members // through ancestors groups. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project func (s *ProjectMembersService) ListProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...OptionFunc) ([]*ProjectMember, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/members", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var pm []*ProjectMember resp, err := s.client.Do(req, &pm) if err != nil { return nil, resp, err } return pm, resp, err } // ListAllProjectMembers gets a list of a project's team members viewable by the // authenticated user. Returns a list including inherited members through // ancestor groups. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members func (s *ProjectMembersService) ListAllProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...OptionFunc) ([]*ProjectMember, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/members/all", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var pm []*ProjectMember resp, err := s.client.Do(req, &pm) if err != nil { return nil, resp, err } return pm, resp, err } // GetProjectMember gets a project team member. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project func (s *ProjectMembersService) GetProjectMember(pid interface{}, user int, options ...OptionFunc) (*ProjectMember, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pm := new(ProjectMember) resp, err := s.client.Do(req, pm) if err != nil { return nil, resp, err } return pm, resp, err } // AddProjectMemberOptions represents the available AddProjectMember() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project type AddProjectMemberOptions struct { UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` } // AddProjectMember adds a user to a project team. This is an idempotent // method and can be called multiple times with the same parameters. Adding // team membership to a user that is already a member does not affect the // existing membership. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project func (s *ProjectMembersService) AddProjectMember(pid interface{}, opt *AddProjectMemberOptions, options ...OptionFunc) (*ProjectMember, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/members", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pm := new(ProjectMember) resp, err := s.client.Do(req, pm) if err != nil { return nil, resp, err } return pm, resp, err } // EditProjectMemberOptions represents the available EditProjectMember() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project type EditProjectMemberOptions struct { AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` } // EditProjectMember updates a project team member to a specified access level.. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project func (s *ProjectMembersService) EditProjectMember(pid interface{}, user int, opt *EditProjectMemberOptions, options ...OptionFunc) (*ProjectMember, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } pm := new(ProjectMember) resp, err := s.client.Do(req, pm) if err != nil { return nil, resp, err } return pm, resp, err } // DeleteProjectMember removes a user from a project team. // // GitLab API docs: // https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project func (s *ProjectMembersService) DeleteProjectMember(pid interface{}, user int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/project_snippets.go000066400000000000000000000145071357140411500232700ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "bytes" "fmt" ) // ProjectSnippetsService handles communication with the project snippets // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html type ProjectSnippetsService struct { client *Client } // ListProjectSnippetsOptions represents the available ListSnippets() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets type ListProjectSnippetsOptions ListOptions // ListSnippets gets a list of project snippets. // // GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets func (s *ProjectSnippetsService) ListSnippets(pid interface{}, opt *ListProjectSnippetsOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ps []*Snippet resp, err := s.client.Do(req, &ps) if err != nil { return nil, resp, err } return ps, resp, err } // GetSnippet gets a single project snippet // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_snippets.html#single-snippet func (s *ProjectSnippetsService) GetSnippet(pid interface{}, snippet int, options ...OptionFunc) (*Snippet, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d", pathEscape(project), snippet) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ps := new(Snippet) resp, err := s.client.Do(req, ps) if err != nil { return nil, resp, err } return ps, resp, err } // CreateProjectSnippetOptions represents the available CreateSnippet() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet type CreateProjectSnippetOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Code *string `url:"code,omitempty" json:"code,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` } // CreateSnippet creates a new project snippet. The user must have permission // to create new snippets. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet func (s *ProjectSnippetsService) CreateSnippet(pid interface{}, opt *CreateProjectSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } ps := new(Snippet) resp, err := s.client.Do(req, ps) if err != nil { return nil, resp, err } return ps, resp, err } // UpdateProjectSnippetOptions represents the available UpdateSnippet() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet type UpdateProjectSnippetOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Code *string `url:"code,omitempty" json:"code,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` } // UpdateSnippet updates an existing project snippet. The user must have // permission to change an existing snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet func (s *ProjectSnippetsService) UpdateSnippet(pid interface{}, snippet int, opt *UpdateProjectSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d", pathEscape(project), snippet) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ps := new(Snippet) resp, err := s.client.Do(req, ps) if err != nil { return nil, resp, err } return ps, resp, err } // DeleteSnippet deletes an existing project snippet. This is an idempotent // function and deleting a non-existent snippet still returns a 200 OK status // code. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_snippets.html#delete-snippet func (s *ProjectSnippetsService) DeleteSnippet(pid interface{}, snippet int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/snippets/%d", pathEscape(project), snippet) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // SnippetContent returns the raw project snippet as plain text. // // GitLab API docs: // https://docs.gitlab.com/ce/api/project_snippets.html#snippet-content func (s *ProjectSnippetsService) SnippetContent(pid interface{}, snippet int, options ...OptionFunc) ([]byte, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/snippets/%d/raw", pathEscape(project), snippet) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var b bytes.Buffer resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b.Bytes(), resp, err } golang-github-xanzy-go-gitlab-0.22.2/project_variables.go000066400000000000000000000146361357140411500233760ustar00rootroot00000000000000// // Copyright 2018, Patrick Webster // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/url" ) // ProjectVariablesService handles communication with the // project variables related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html type ProjectVariablesService struct { client *Client } // ProjectVariable represents a GitLab Project Variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html type ProjectVariable struct { Key string `json:"key"` Value string `json:"value"` VariableType VariableTypeValue `json:"variable_type"` Protected bool `json:"protected"` Masked bool `json:"masked"` EnvironmentScope string `json:"environment_scope"` } func (v ProjectVariable) String() string { return Stringify(v) } // ListProjectVariablesOptions represents the available options for listing variables // in a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#list-project-variables type ListProjectVariablesOptions ListOptions // ListVariables gets a list of all variables in a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#list-project-variables func (s *ProjectVariablesService) ListVariables(pid interface{}, opt *ListProjectVariablesOptions, options ...OptionFunc) ([]*ProjectVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/variables", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var vs []*ProjectVariable resp, err := s.client.Do(req, &vs) if err != nil { return nil, resp, err } return vs, resp, err } // GetVariable gets a variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#show-variable-details func (s *ProjectVariablesService) GetVariable(pid interface{}, key string, options ...OptionFunc) (*ProjectVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/variables/%s", pathEscape(project), url.PathEscape(key)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } v := new(ProjectVariable) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } // CreateProjectVariableOptions represents the available CreateVariable() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#create-variable type CreateProjectVariableOptions struct { Key *string `url:"key,omitempty" json:"key,omitempty"` Value *string `url:"value,omitempty" json:"value,omitempty"` VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` Masked *bool `url:"masked,omitempty" json:"masked,omitempty"` EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` } // CreateVariable creates a new project variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#create-variable func (s *ProjectVariablesService) CreateVariable(pid interface{}, opt *CreateProjectVariableOptions, options ...OptionFunc) (*ProjectVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/variables", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } v := new(ProjectVariable) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } // UpdateProjectVariableOptions represents the available UpdateVariable() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#update-variable type UpdateProjectVariableOptions struct { Value *string `url:"value,omitempty" json:"value,omitempty"` VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` Masked *bool `url:"masked,omitempty" json:"masked,omitempty"` EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` } // UpdateVariable updates a project's variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#update-variable func (s *ProjectVariablesService) UpdateVariable(pid interface{}, key string, opt *UpdateProjectVariableOptions, options ...OptionFunc) (*ProjectVariable, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/variables/%s", pathEscape(project), url.PathEscape(key)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } v := new(ProjectVariable) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } // RemoveVariable removes a project's variable. // // GitLab API docs: // https://docs.gitlab.com/ee/api/project_level_variables.html#remove-variable func (s *ProjectVariablesService) RemoveVariable(pid interface{}, key string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/variables/%s", pathEscape(project), url.PathEscape(key)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/projects.go000066400000000000000000001655031357140411500215310ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "bytes" "fmt" "io" "io/ioutil" "mime/multipart" "os" "time" ) // ProjectsService handles communication with the repositories related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html type ProjectsService struct { client *Client } // Project represents a GitLab project. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html type Project struct { ID int `json:"id"` Description string `json:"description"` DefaultBranch string `json:"default_branch"` Public bool `json:"public"` Visibility VisibilityValue `json:"visibility"` SSHURLToRepo string `json:"ssh_url_to_repo"` HTTPURLToRepo string `json:"http_url_to_repo"` WebURL string `json:"web_url"` ReadmeURL string `json:"readme_url"` TagList []string `json:"tag_list"` Owner *User `json:"owner"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` IssuesEnabled bool `json:"issues_enabled"` OpenIssuesCount int `json:"open_issues_count"` MergeRequestsEnabled bool `json:"merge_requests_enabled"` ApprovalsBeforeMerge int `json:"approvals_before_merge"` JobsEnabled bool `json:"jobs_enabled"` WikiEnabled bool `json:"wiki_enabled"` SnippetsEnabled bool `json:"snippets_enabled"` ResolveOutdatedDiffDiscussions bool `json:"resolve_outdated_diff_discussions"` ContainerRegistryEnabled bool `json:"container_registry_enabled"` CreatedAt *time.Time `json:"created_at,omitempty"` LastActivityAt *time.Time `json:"last_activity_at,omitempty"` CreatorID int `json:"creator_id"` Namespace *ProjectNamespace `json:"namespace"` ImportStatus string `json:"import_status"` ImportError string `json:"import_error"` Permissions *Permissions `json:"permissions"` Archived bool `json:"archived"` AvatarURL string `json:"avatar_url"` SharedRunnersEnabled bool `json:"shared_runners_enabled"` ForksCount int `json:"forks_count"` StarCount int `json:"star_count"` RunnersToken string `json:"runners_token"` PublicBuilds bool `json:"public_builds"` OnlyAllowMergeIfPipelineSucceeds bool `json:"only_allow_merge_if_pipeline_succeeds"` OnlyAllowMergeIfAllDiscussionsAreResolved bool `json:"only_allow_merge_if_all_discussions_are_resolved"` LFSEnabled bool `json:"lfs_enabled"` RequestAccessEnabled bool `json:"request_access_enabled"` MergeMethod MergeMethodValue `json:"merge_method"` ForkedFromProject *ForkParent `json:"forked_from_project"` Mirror bool `json:"mirror"` MirrorUserID int `json:"mirror_user_id"` MirrorTriggerBuilds bool `json:"mirror_trigger_builds"` OnlyMirrorProtectedBranches bool `json:"only_mirror_protected_branches"` MirrorOverwritesDivergedBranches bool `json:"mirror_overwrites_diverged_branches"` SharedWithGroups []struct { GroupID int `json:"group_id"` GroupName string `json:"group_name"` GroupAccessLevel int `json:"group_access_level"` } `json:"shared_with_groups"` Statistics *ProjectStatistics `json:"statistics"` Links *Links `json:"_links,omitempty"` CIConfigPath *string `json:"ci_config_path"` CustomAttributes []*CustomAttribute `json:"custom_attributes"` } // Repository represents a repository. type Repository struct { Name string `json:"name"` Description string `json:"description"` WebURL string `json:"web_url"` AvatarURL string `json:"avatar_url"` GitSSHURL string `json:"git_ssh_url"` GitHTTPURL string `json:"git_http_url"` Namespace string `json:"namespace"` Visibility VisibilityValue `json:"visibility"` PathWithNamespace string `json:"path_with_namespace"` DefaultBranch string `json:"default_branch"` Homepage string `json:"homepage"` URL string `json:"url"` SSHURL string `json:"ssh_url"` HTTPURL string `json:"http_url"` } // ProjectNamespace represents a project namespace. type ProjectNamespace struct { ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` Kind string `json:"kind"` FullPath string `json:"full_path"` } // StorageStatistics represents a statistics record for a group or project. type StorageStatistics struct { StorageSize int64 `json:"storage_size"` RepositorySize int64 `json:"repository_size"` LfsObjectsSize int64 `json:"lfs_objects_size"` JobArtifactsSize int64 `json:"job_artifacts_size"` } // ProjectStatistics represents a statistics record for a project. type ProjectStatistics struct { StorageStatistics CommitCount int `json:"commit_count"` } // Permissions represents permissions. type Permissions struct { ProjectAccess *ProjectAccess `json:"project_access"` GroupAccess *GroupAccess `json:"group_access"` } // ProjectAccess represents project access. type ProjectAccess struct { AccessLevel AccessLevelValue `json:"access_level"` NotificationLevel NotificationLevelValue `json:"notification_level"` } // GroupAccess represents group access. type GroupAccess struct { AccessLevel AccessLevelValue `json:"access_level"` NotificationLevel NotificationLevelValue `json:"notification_level"` } // ForkParent represents the parent project when this is a fork. type ForkParent struct { HTTPURLToRepo string `json:"http_url_to_repo"` ID int `json:"id"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` WebURL string `json:"web_url"` } // Links represents a project web links for self, issues, merge_requests, // repo_branches, labels, events, members. type Links struct { Self string `json:"self"` Issues string `json:"issues"` MergeRequests string `json:"merge_requests"` RepoBranches string `json:"repo_branches"` Labels string `json:"labels"` Events string `json:"events"` Members string `json:"members"` } func (s Project) String() string { return Stringify(s) } // ProjectApprovalRule represents a GitLab project approval rule. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-project-level-rules type ProjectApprovalRule struct { ID int `json:"id"` Name string `json:"name"` RuleType string `json:"rule_type"` EligibleApprovers []*BasicUser `json:"eligible_approvers"` ApprovalsRequired int `json:"approvals_required"` Users []*BasicUser `json:"users"` Groups []*Group `json:"groups"` ContainsHiddenGroups bool `json:"contains_hidden_groups"` } func (s ProjectApprovalRule) String() string { return Stringify(s) } // ListProjectsOptions represents the available ListProjects() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects type ListProjectsOptions struct { ListOptions Archived *bool `url:"archived,omitempty" json:"archived,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` Search *string `url:"search,omitempty" json:"search,omitempty"` Simple *bool `url:"simple,omitempty" json:"simple,omitempty"` Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` Membership *bool `url:"membership,omitempty" json:"membership,omitempty"` Starred *bool `url:"starred,omitempty" json:"starred,omitempty"` Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"` WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"` MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"` WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` WithProgrammingLanguage *string `url:"with_programming_language,omitempty" json:"with_programming_language,omitempty"` } // ListProjects gets a list of projects accessible by the authenticated user. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects func (s *ProjectsService) ListProjects(opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { req, err := s.client.NewRequest("GET", "projects", opt, options) if err != nil { return nil, nil, err } var p []*Project resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // ListUserProjects gets a list of projects for the given user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#list-user-projects func (s *ProjectsService) ListUserProjects(uid interface{}, opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { user, err := parseID(uid) if err != nil { return nil, nil, err } u := fmt.Sprintf("users/%s/projects", user) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var p []*Project resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // ProjectUser represents a GitLab project user. type ProjectUser struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } // ListProjectUserOptions represents the available ListProjectsUsers() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#get-project-users type ListProjectUserOptions struct { ListOptions Search *string `url:"search,omitempty" json:"search,omitempty"` } // ListProjectsUsers gets a list of users for the given project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#get-project-users func (s *ProjectsService) ListProjectsUsers(pid interface{}, opt *ListProjectUserOptions, options ...OptionFunc) ([]*ProjectUser, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/users", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var p []*ProjectUser resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // ProjectLanguages is a map of strings because the response is arbitrary // // Gitlab API docs: https://docs.gitlab.com/ce/api/projects.html#languages type ProjectLanguages map[string]float32 // GetProjectLanguages gets a list of languages used by the project // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#languages func (s *ProjectsService) GetProjectLanguages(pid interface{}, options ...OptionFunc) (*ProjectLanguages, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/languages", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } p := new(ProjectLanguages) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // GetProjectOptions represents the available GetProject() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#get-single-project type GetProjectOptions struct { Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` License *bool `url:"license,omitempty" json:"license,omitempty"` WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` } // GetProject gets a specific project, identified by project ID or // NAMESPACE/PROJECT_NAME, which is owned by the authenticated user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#get-single-project func (s *ProjectsService) GetProject(pid interface{}, opt *GetProjectOptions, options ...OptionFunc) (*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // ProjectEvent represents a GitLab project event. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#get-project-events type ProjectEvent struct { Title interface{} `json:"title"` ProjectID int `json:"project_id"` ActionName string `json:"action_name"` TargetID interface{} `json:"target_id"` TargetType interface{} `json:"target_type"` AuthorID int `json:"author_id"` AuthorUsername string `json:"author_username"` Data struct { Before string `json:"before"` After string `json:"after"` Ref string `json:"ref"` UserID int `json:"user_id"` UserName string `json:"user_name"` Repository *Repository `json:"repository"` Commits []*Commit `json:"commits"` TotalCommitsCount int `json:"total_commits_count"` } `json:"data"` TargetTitle interface{} `json:"target_title"` } func (s ProjectEvent) String() string { return Stringify(s) } // GetProjectEventsOptions represents the available GetProjectEvents() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#get-project-events type GetProjectEventsOptions ListOptions // GetProjectEvents gets the events for the specified project. Sorted from // newest to latest. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#get-project-events func (s *ProjectsService) GetProjectEvents(pid interface{}, opt *GetProjectEventsOptions, options ...OptionFunc) ([]*ProjectEvent, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/events", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var p []*ProjectEvent resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // CreateProjectOptions represents the available CreateProject() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#create-project type CreateProjectOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Path *string `url:"path,omitempty" json:"path,omitempty"` DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` NamespaceID *int `url:"namespace_id,omitempty" json:"namespace_id,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"` CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` InitializeWithReadme *bool `url:"initialize_with_readme,omitempty" json:"initialize_with_readme,omitempty"` TemplateName *string `url:"template_name,omitempty" json:"template_name,omitempty"` UseCustomTemplate *bool `url:"use_custom_template,omitempty" json:"use_custom_template,omitempty"` GroupWithProjectTemplatesID *int `url:"group_with_project_templates_id,omitempty" json:"group_with_project_templates_id,omitempty"` BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` } // CreateProject creates a new project owned by the authenticated user. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project func (s *ProjectsService) CreateProject(opt *CreateProjectOptions, options ...OptionFunc) (*Project, *Response, error) { req, err := s.client.NewRequest("POST", "projects", opt, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // CreateProjectForUserOptions represents the available CreateProjectForUser() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#create-project-for-user type CreateProjectForUserOptions CreateProjectOptions // CreateProjectForUser creates a new project owned by the specified user. // Available only for admins. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#create-project-for-user func (s *ProjectsService) CreateProjectForUser(user int, opt *CreateProjectForUserOptions, options ...OptionFunc) (*Project, *Response, error) { u := fmt.Sprintf("projects/user/%d", user) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // EditProjectOptions represents the available EditProject() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project type EditProjectOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Path *string `url:"path,omitempty" json:"path,omitempty"` DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` ExternalAuthorizationClassificationLabel *string `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"` Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` MirrorUserID *int `url:"mirror_user_id,omitempty" json:"mirror_user_id,omitempty"` OnlyMirrorProtectedBranches *bool `url:"only_mirror_protected_branches,omitempty" json:"only_mirror_protected_branches,omitempty"` MirrorOverwritesDivergedBranches *bool `url:"mirror_overwrites_diverged_branches,omitempty" json:"mirror_overwrites_diverged_branches,omitempty"` PackagesEnabled *bool `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"` BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` } // EditProject updates an existing project. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project func (s *ProjectsService) EditProject(pid interface{}, opt *EditProjectOptions, options ...OptionFunc) (*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // ForkProjectOptions represents the available ForkProject() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project type ForkProjectOptions struct { Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` Name *string `url:"name,omitempty" json:"name,omitempty" ` Path *string `url:"path,omitempty" json:"path,omitempty"` } // ForkProject forks a project into the user namespace of the authenticated // user. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project func (s *ProjectsService) ForkProject(pid interface{}, opt *ForkProjectOptions, options ...OptionFunc) (*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/fork", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // StarProject stars a given the project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#star-a-project func (s *ProjectsService) StarProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/star", pathEscape(project)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // UnstarProject unstars a given project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#unstar-a-project func (s *ProjectsService) UnstarProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/unstar", pathEscape(project)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // ArchiveProject archives the project if the user is either admin or the // project owner of this project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#archive-a-project func (s *ProjectsService) ArchiveProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/archive", pathEscape(project)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // UnarchiveProject unarchives the project if the user is either admin or // the project owner of this project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#unarchive-a-project func (s *ProjectsService) UnarchiveProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/unarchive", pathEscape(project)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } p := new(Project) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // DeleteProject removes a project including all associated resources // (issues, merge requests etc.) // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#remove-project func (s *ProjectsService) DeleteProject(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ShareWithGroupOptions represents options to share project with groups // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group type ShareWithGroupOptions struct { GroupID *int `url:"group_id" json:"group_id"` GroupAccess *AccessLevelValue `url:"group_access" json:"group_access"` ExpiresAt *string `url:"expires_at" json:"expires_at"` } // ShareProjectWithGroup allows to share a project with a group. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group func (s *ProjectsService) ShareProjectWithGroup(pid interface{}, opt *ShareWithGroupOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/share", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteSharedProjectFromGroup allows to unshare a project from a group. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#delete-a-shared-project-link-within-a-group func (s *ProjectsService) DeleteSharedProjectFromGroup(pid interface{}, groupID int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/share/%d", pathEscape(project), groupID) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ProjectMember represents a project member. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#list-project-team-members type ProjectMember struct { ID int `json:"id"` Username string `json:"username"` Email string `json:"email"` Name string `json:"name"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` ExpiresAt *ISOTime `json:"expires_at"` AccessLevel AccessLevelValue `json:"access_level"` } // ProjectHook represents a project hook. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#list-project-hooks type ProjectHook struct { ID int `json:"id"` URL string `json:"url"` ProjectID int `json:"project_id"` PushEvents bool `json:"push_events"` IssuesEvents bool `json:"issues_events"` ConfidentialIssuesEvents bool `json:"confidential_issues_events"` MergeRequestsEvents bool `json:"merge_requests_events"` TagPushEvents bool `json:"tag_push_events"` NoteEvents bool `json:"note_events"` JobEvents bool `json:"job_events"` PipelineEvents bool `json:"pipeline_events"` WikiPageEvents bool `json:"wiki_page_events"` EnableSSLVerification bool `json:"enable_ssl_verification"` CreatedAt *time.Time `json:"created_at"` } // ListProjectHooksOptions represents the available ListProjectHooks() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-project-hooks type ListProjectHooksOptions ListOptions // ListProjectHooks gets a list of project hooks. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#list-project-hooks func (s *ProjectsService) ListProjectHooks(pid interface{}, opt *ListProjectHooksOptions, options ...OptionFunc) ([]*ProjectHook, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/hooks", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ph []*ProjectHook resp, err := s.client.Do(req, &ph) if err != nil { return nil, resp, err } return ph, resp, err } // GetProjectHook gets a specific hook for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#get-project-hook func (s *ProjectsService) GetProjectHook(pid interface{}, hook int, options ...OptionFunc) (*ProjectHook, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ph := new(ProjectHook) resp, err := s.client.Do(req, ph) if err != nil { return nil, resp, err } return ph, resp, err } // AddProjectHookOptions represents the available AddProjectHook() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#add-project-hook type AddProjectHookOptions struct { URL *string `url:"url,omitempty" json:"url,omitempty"` PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` Token *string `url:"token,omitempty" json:"token,omitempty"` } // AddProjectHook adds a hook to a specified project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#add-project-hook func (s *ProjectsService) AddProjectHook(pid interface{}, opt *AddProjectHookOptions, options ...OptionFunc) (*ProjectHook, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/hooks", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } ph := new(ProjectHook) resp, err := s.client.Do(req, ph) if err != nil { return nil, resp, err } return ph, resp, err } // EditProjectHookOptions represents the available EditProjectHook() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#edit-project-hook type EditProjectHookOptions struct { URL *string `url:"url,omitempty" json:"url,omitempty"` PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` Token *string `url:"token,omitempty" json:"token,omitempty"` } // EditProjectHook edits a hook for a specified project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#edit-project-hook func (s *ProjectsService) EditProjectHook(pid interface{}, hook int, opt *EditProjectHookOptions, options ...OptionFunc) (*ProjectHook, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ph := new(ProjectHook) resp, err := s.client.Do(req, ph) if err != nil { return nil, resp, err } return ph, resp, err } // DeleteProjectHook removes a hook from a project. This is an idempotent // method and can be called multiple times. Either the hook is available or not. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#delete-project-hook func (s *ProjectsService) DeleteProjectHook(pid interface{}, hook int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ProjectForkRelation represents a project fork relationship. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#admin-fork-relation type ProjectForkRelation struct { ID int `json:"id"` ForkedToProjectID int `json:"forked_to_project_id"` ForkedFromProjectID int `json:"forked_from_project_id"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` } // CreateProjectForkRelation creates a forked from/to relation between // existing projects. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#create-a-forked-fromto-relation-between-existing-projects. func (s *ProjectsService) CreateProjectForkRelation(pid int, fork int, options ...OptionFunc) (*ProjectForkRelation, *Response, error) { u := fmt.Sprintf("projects/%d/fork/%d", pid, fork) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } pfr := new(ProjectForkRelation) resp, err := s.client.Do(req, pfr) if err != nil { return nil, resp, err } return pfr, resp, err } // DeleteProjectForkRelation deletes an existing forked from relationship. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#delete-an-existing-forked-from-relationship func (s *ProjectsService) DeleteProjectForkRelation(pid int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("projects/%d/fork", pid) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ProjectFile represents an uploaded project file // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file type ProjectFile struct { Alt string `json:"alt"` URL string `json:"url"` Markdown string `json:"markdown"` } // UploadFile upload a file from disk // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file func (s *ProjectsService) UploadFile(pid interface{}, file string, options ...OptionFunc) (*ProjectFile, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/uploads", pathEscape(project)) f, err := os.Open(file) if err != nil { return nil, nil, err } defer f.Close() b := &bytes.Buffer{} w := multipart.NewWriter(b) fw, err := w.CreateFormFile("file", file) if err != nil { return nil, nil, err } _, err = io.Copy(fw, f) if err != nil { return nil, nil, err } w.Close() req, err := s.client.NewRequest("", u, nil, options) if err != nil { return nil, nil, err } req.Body = ioutil.NopCloser(b) req.ContentLength = int64(b.Len()) req.Header.Set("Content-Type", w.FormDataContentType()) req.Method = "POST" uf := &ProjectFile{} resp, err := s.client.Do(req, uf) if err != nil { return nil, resp, err } return uf, resp, nil } // ListProjectForks gets a list of project forks. // // GitLab API docs: // https://docs.gitlab.com/ce/api/projects.html#list-forks-of-a-project func (s *ProjectsService) ListProjectForks(pid interface{}, opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/forks", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var forks []*Project resp, err := s.client.Do(req, &forks) if err != nil { return nil, resp, err } return forks, resp, err } // ProjectPushRules represents a project push rule. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#push-rules type ProjectPushRules struct { ID int `json:"id"` ProjectID int `json:"project_id"` CommitMessageRegex string `json:"commit_message_regex"` BranchNameRegex string `json:"branch_name_regex"` DenyDeleteTag bool `json:"deny_delete_tag"` CreatedAt *time.Time `json:"created_at"` MemberCheck bool `json:"member_check"` PreventSecrets bool `json:"prevent_secrets"` AuthorEmailRegex string `json:"author_email_regex"` FileNameRegex string `json:"file_name_regex"` MaxFileSize int `json:"max_file_size"` } // GetProjectPushRules gets the push rules of a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#get-project-push-rules func (s *ProjectsService) GetProjectPushRules(pid interface{}, options ...OptionFunc) (*ProjectPushRules, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ppr := new(ProjectPushRules) resp, err := s.client.Do(req, ppr) if err != nil { return nil, resp, err } return ppr, resp, err } // AddProjectPushRuleOptions represents the available AddProjectPushRule() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule type AddProjectPushRuleOptions struct { DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"` MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"` PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"` CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"` BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"` AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"` FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"` MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"` } // AddProjectPushRule adds a push rule to a specified project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule func (s *ProjectsService) AddProjectPushRule(pid interface{}, opt *AddProjectPushRuleOptions, options ...OptionFunc) (*ProjectPushRules, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } ppr := new(ProjectPushRules) resp, err := s.client.Do(req, ppr) if err != nil { return nil, resp, err } return ppr, resp, err } // EditProjectPushRuleOptions represents the available EditProjectPushRule() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule type EditProjectPushRuleOptions struct { AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"` BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"` CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"` FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"` DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"` MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"` PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"` MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"` } // EditProjectPushRule edits a push rule for a specified project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule func (s *ProjectsService) EditProjectPushRule(pid interface{}, opt *EditProjectPushRuleOptions, options ...OptionFunc) (*ProjectPushRules, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ppr := new(ProjectPushRules) resp, err := s.client.Do(req, ppr) if err != nil { return nil, resp, err } return ppr, resp, err } // DeleteProjectPushRule removes a push rule from a project. This is an // idempotent method and can be called multiple times. Either the push rule is // available or not. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#delete-project-push-rule func (s *ProjectsService) DeleteProjectPushRule(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ProjectApprovals represents GitLab project level merge request approvals. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals type ProjectApprovals struct { Approvers []*MergeRequestApproverUser `json:"approvers"` ApproverGroups []*MergeRequestApproverGroup `json:"approver_groups"` ApprovalsBeforeMerge int `json:"approvals_before_merge"` ResetApprovalsOnPush bool `json:"reset_approvals_on_push"` DisableOverridingApproversPerMergeRequest bool `json:"disable_overriding_approvers_per_merge_request"` MergeRequestsAuthorApproval bool `json:"merge_requests_author_approval"` MergeRequestsDisableCommittersApproval bool `json:"merge_requests_disable_committers_approval"` } // GetApprovalConfiguration get the approval configuration for a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-configuration func (s *ProjectsService) GetApprovalConfiguration(pid interface{}, options ...OptionFunc) (*ProjectApprovals, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/approvals", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pa := new(ProjectApprovals) resp, err := s.client.Do(req, pa) if err != nil { return nil, resp, err } return pa, resp, err } // ChangeApprovalConfigurationOptions represents the available // ApprovalConfiguration() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration type ChangeApprovalConfigurationOptions struct { ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` ResetApprovalsOnPush *bool `url:"reset_approvals_on_push,omitempty" json:"reset_approvals_on_push,omitempty"` DisableOverridingApproversPerMergeRequest *bool `url:"disable_overriding_approvers_per_merge_request,omitempty" json:"disable_overriding_approvers_per_merge_request,omitempty"` MergeRequestsAuthorApproval *bool `url:"merge_requests_author_approval,omitempty" json:"merge_requests_author_approval,omitempty"` MergeRequestsDisableCommittersApproval *bool `url:"merge_requests_disable_committers_approval,omitempty" json:"merge_requests_disable_committers_approval,omitempty"` } // ChangeApprovalConfiguration updates the approval configuration for a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration func (s *ProjectsService) ChangeApprovalConfiguration(pid interface{}, opt *ChangeApprovalConfigurationOptions, options ...OptionFunc) (*ProjectApprovals, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/approvals", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pa := new(ProjectApprovals) resp, err := s.client.Do(req, pa) if err != nil { return nil, resp, err } return pa, resp, err } // GetProjectApprovalRules looks up the list of project level approvers. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-project-level-rules func (s *ProjectsService) GetProjectApprovalRules(pid interface{}, options ...OptionFunc) ([]*ProjectApprovalRule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/approval_rules", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var par []*ProjectApprovalRule resp, err := s.client.Do(req, &par) if err != nil { return nil, resp, err } return par, resp, err } // CreateProjectLevelRuleOptions represents the available CreateProjectApprovalRule() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-project-level-rules type CreateProjectLevelRuleOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` } // CreateProjectApprovalRule creates a new project-level approval rule. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-project-level-rules func (s *ProjectsService) CreateProjectApprovalRule(pid interface{}, opt *CreateProjectLevelRuleOptions, options ...OptionFunc) (*ProjectApprovalRule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/approval_rules", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } par := new(ProjectApprovalRule) resp, err := s.client.Do(req, &par) if err != nil { return nil, resp, err } return par, resp, err } // UpdateProjectLevelRuleOptions represents the available UpdateProjectApprovalRule() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-project-level-rules type UpdateProjectLevelRuleOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` } // UpdateProjectApprovalRule updates an existing approval rule with new options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-project-level-rules func (s *ProjectsService) UpdateProjectApprovalRule(pid interface{}, approvalRule int, opt *UpdateProjectLevelRuleOptions, options ...OptionFunc) (*ProjectApprovalRule, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/approval_rules/%d", pathEscape(project), approvalRule) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } par := new(ProjectApprovalRule) resp, err := s.client.Do(req, &par) if err != nil { return nil, resp, err } return par, resp, err } // DeleteProjectApprovalRule deletes a project-level approval rule. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#delete-project-level-rules func (s *ProjectsService) DeleteProjectApprovalRule(pid interface{}, approvalRule int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/approval_rules/%d", pathEscape(project), approvalRule) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ChangeAllowedApproversOptions represents the available ChangeAllowedApprovers() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers type ChangeAllowedApproversOptions struct { ApproverIDs []int `url:"approver_ids,omitempty" json:"approver_ids,omitempty"` ApproverGroupIDs []int `url:"approver_group_ids,omitempty" json:"approver_group_ids,omitempty"` } // ChangeAllowedApprovers updates the list of approvers and approver groups. // // GitLab API docs: // https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers func (s *ProjectsService) ChangeAllowedApprovers(pid interface{}, opt *ChangeAllowedApproversOptions, options ...OptionFunc) (*ProjectApprovals, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/approvers", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } pa := new(ProjectApprovals) resp, err := s.client.Do(req, pa) if err != nil { return nil, resp, err } return pa, resp, err } // StartMirroringProject start the pull mirroring process for a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/projects.html#start-the-pull-mirroring-process-for-a-project-starter func (s *ProjectsService) StartMirroringProject(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/mirror/pull", pathEscape(project)) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, err } resp, err := s.client.Do(req, nil) if err != nil { return resp, err } return resp, err } golang-github-xanzy-go-gitlab-0.22.2/projects_test.go000066400000000000000000000535311357140411500225650ustar00rootroot00000000000000package gitlab import ( "fmt" "io/ioutil" "net/http" "os" "reflect" "strings" "testing" ) func TestListProjects(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectsOptions{ ListOptions: ListOptions{2, 3}, Archived: Bool(true), OrderBy: String("name"), Sort: String("asc"), Search: String("query"), Simple: Bool(true), Visibility: Visibility(PublicVisibility), } projects, _, err := client.Projects.ListProjects(opt) if err != nil { t.Errorf("Projects.ListProjects returned error: %v", err) } want := []*Project{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Projects.ListProjects returned %+v, want %+v", projects, want) } } func TestListUserProjects(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/users/1/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectsOptions{ ListOptions: ListOptions{2, 3}, Archived: Bool(true), OrderBy: String("name"), Sort: String("asc"), Search: String("query"), Simple: Bool(true), Visibility: Visibility(PublicVisibility), } projects, _, err := client.Projects.ListUserProjects(1, opt) if err != nil { t.Errorf("Projects.ListUserProjects returned error: %v", err) } want := []*Project{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Projects.ListUserProjects returned %+v, want %+v", projects, want) } } func TestListProjectsUsersByID(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/", func(w http.ResponseWriter, r *http.Request) { testURL(t, r, "/api/v4/projects/1/users?page=2&per_page=3&search=query") testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectUserOptions{ ListOptions: ListOptions{2, 3}, Search: String("query"), } projects, _, err := client.Projects.ListProjectsUsers(1, opt) if err != nil { t.Errorf("Projects.ListProjectsUsers returned error: %v", err) } want := []*ProjectUser{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Projects.ListProjectsUsers returned %+v, want %+v", projects, want) } } func TestListProjectsUsersByName(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/", func(w http.ResponseWriter, r *http.Request) { testURL(t, r, "/api/v4/projects/namespace%2Fname/users?page=2&per_page=3&search=query") testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectUserOptions{ ListOptions: ListOptions{2, 3}, Search: String("query"), } projects, _, err := client.Projects.ListProjectsUsers("namespace/name", opt) if err != nil { t.Errorf("Projects.ListProjectsUsers returned error: %v", err) } want := []*ProjectUser{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Projects.ListProjectsUsers returned %+v, want %+v", projects, want) } } func TestListOwnedProjects(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectsOptions{ ListOptions: ListOptions{2, 3}, Archived: Bool(true), OrderBy: String("name"), Sort: String("asc"), Search: String("query"), Simple: Bool(true), Owned: Bool(true), Visibility: Visibility(PublicVisibility), } projects, _, err := client.Projects.ListProjects(opt) if err != nil { t.Errorf("Projects.ListOwnedProjects returned error: %v", err) } want := []*Project{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Projects.ListOwnedProjects returned %+v, want %+v", projects, want) } } func TestListStarredProjects(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectsOptions{ ListOptions: ListOptions{2, 3}, Archived: Bool(true), OrderBy: String("name"), Sort: String("asc"), Search: String("query"), Simple: Bool(true), Starred: Bool(true), Visibility: Visibility(PublicVisibility), } projects, _, err := client.Projects.ListProjects(opt) if err != nil { t.Errorf("Projects.ListStarredProjects returned error: %v", err) } want := []*Project{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Projects.ListStarredProjects returned %+v, want %+v", projects, want) } } func TestGetProjectByID(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1}`) }) want := &Project{ID: 1} project, _, err := client.Projects.GetProject(1, nil) if err != nil { t.Fatalf("Projects.GetProject returns an error: %v", err) } if !reflect.DeepEqual(want, project) { t.Errorf("Projects.GetProject returned %+v, want %+v", project, want) } } func TestGetProjectByName(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/", func(w http.ResponseWriter, r *http.Request) { testURL(t, r, "/api/v4/projects/namespace%2Fname") testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1}`) }) want := &Project{ID: 1} project, _, err := client.Projects.GetProject("namespace/name", nil) if err != nil { t.Fatalf("Projects.GetProject returns an error: %v", err) } if !reflect.DeepEqual(want, project) { t.Errorf("Projects.GetProject returned %+v, want %+v", project, want) } } func TestGetProjectWithOptions(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{ "id":1, "statistics": { "commit_count": 37, "storage_size": 1038090, "repository_size": 1038090, "lfs_objects_size": 0, "job_artifacts_size": 0 }}`) }) want := &Project{ID: 1, Statistics: &ProjectStatistics{ CommitCount: 37, StorageStatistics: StorageStatistics{ StorageSize: 1038090, RepositorySize: 1038090, LfsObjectsSize: 0, JobArtifactsSize: 0, }, }} project, _, err := client.Projects.GetProject(1, &GetProjectOptions{Statistics: Bool(true)}) if err != nil { t.Fatalf("Projects.GetProject returns an error: %v", err) } if !reflect.DeepEqual(want, project) { t.Errorf("Projects.GetProject returned %+v, want %+v", project, want) } } func TestCreateProject(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"id":1}`) }) opt := &CreateProjectOptions{ Name: String("n"), MergeMethod: MergeMethod(RebaseMerge), } project, _, err := client.Projects.CreateProject(opt) if err != nil { t.Errorf("Projects.CreateProject returned error: %v", err) } want := &Project{ID: 1} if !reflect.DeepEqual(want, project) { t.Errorf("Projects.CreateProject returned %+v, want %+v", project, want) } } func TestUploadFile(t *testing.T) { mux, server, client := setup() defer teardown(server) tf, _ := ioutil.TempFile(os.TempDir(), "test") defer os.Remove(tf.Name()) mux.HandleFunc("/api/v4/projects/1/uploads", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) if false == strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data;") { t.Fatalf("Prokects.UploadFile request content-type %+v want multipart/form-data;", r.Header.Get("Content-Type")) } if r.ContentLength == -1 { t.Fatalf("Prokects.UploadFile request content-length is -1") } fmt.Fprint(w, `{ "alt": "dk", "url": "/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.md", "markdown": "![dk](/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png)" }`) }) want := &ProjectFile{ Alt: "dk", URL: "/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.md", Markdown: "![dk](/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png)", } file, _, err := client.Projects.UploadFile(1, tf.Name()) if err != nil { t.Fatalf("Prokects.UploadFile returns an error: %v", err) } if !reflect.DeepEqual(want, file) { t.Errorf("Prokects.UploadFile returned %+v, want %+v", file, want) } } func TestListProjectForks(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/", func(w http.ResponseWriter, r *http.Request) { testURL(t, r, "/api/v4/projects/namespace%2Fname/forks?archived=true&order_by=name&page=2&per_page=3&search=query&simple=true&sort=asc&visibility=public") testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListProjectsOptions{} opt.ListOptions = ListOptions{2, 3} opt.Archived = Bool(true) opt.OrderBy = String("name") opt.Sort = String("asc") opt.Search = String("query") opt.Simple = Bool(true) opt.Visibility = Visibility(PublicVisibility) projects, _, err := client.Projects.ListProjectForks("namespace/name", opt) if err != nil { t.Errorf("Projects.ListProjectForks returned error: %v", err) } want := []*Project{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, projects) { t.Errorf("Projects.ListProjects returned %+v, want %+v", projects, want) } } func TestShareProjectWithGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/share", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") }) opt := &ShareWithGroupOptions{ GroupID: Int(1), GroupAccess: AccessLevel(AccessLevelValue(50)), } _, err := client.Projects.ShareProjectWithGroup(1, opt) if err != nil { t.Errorf("Projects.ShareProjectWithGroup returned error: %v", err) } } func TestDeleteSharedProjectFromGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/share/2", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) _, err := client.Projects.DeleteSharedProjectFromGroup(1, 2) if err != nil { t.Errorf("Projects.DeleteSharedProjectFromGroup returned error: %v", err) } } func TestGetApprovalConfiguration(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/approvals", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{ "approvers": [], "approver_groups": [], "approvals_before_merge": 3, "reset_approvals_on_push": false, "disable_overriding_approvers_per_merge_request": false, "merge_requests_author_approval": true, "merge_requests_disable_committers_approval": true }`) }) approvals, _, err := client.Projects.GetApprovalConfiguration(1) if err != nil { t.Errorf("Projects.GetApprovalConfiguration returned error: %v", err) } want := &ProjectApprovals{ Approvers: []*MergeRequestApproverUser{}, ApproverGroups: []*MergeRequestApproverGroup{}, ApprovalsBeforeMerge: 3, ResetApprovalsOnPush: false, DisableOverridingApproversPerMergeRequest: false, MergeRequestsAuthorApproval: true, MergeRequestsDisableCommittersApproval: true, } if !reflect.DeepEqual(want, approvals) { t.Errorf("Projects.GetApprovalConfiguration returned %+v, want %+v", approvals, want) } } func TestChangeApprovalConfiguration(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/approvals", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") testBody(t, r, `{"approvals_before_merge":3}`) fmt.Fprint(w, `{ "approvers": [], "approver_groups": [], "approvals_before_merge": 3, "reset_approvals_on_push": false, "disable_overriding_approvers_per_merge_request": false, "merge_requests_author_approval": true, "merge_requests_disable_committers_approval": true }`) }) opt := &ChangeApprovalConfigurationOptions{ ApprovalsBeforeMerge: Int(3), } approvals, _, err := client.Projects.ChangeApprovalConfiguration(1, opt) if err != nil { t.Errorf("Projects.ChangeApprovalConfigurationOptions returned error: %v", err) } want := &ProjectApprovals{ Approvers: []*MergeRequestApproverUser{}, ApproverGroups: []*MergeRequestApproverGroup{}, ApprovalsBeforeMerge: 3, ResetApprovalsOnPush: false, DisableOverridingApproversPerMergeRequest: false, MergeRequestsAuthorApproval: true, MergeRequestsDisableCommittersApproval: true, } if !reflect.DeepEqual(want, approvals) { t.Errorf("Projects.ChangeApprovalConfigurationOptions returned %+v, want %+v", approvals, want) } } func TestChangeAllowedApprovers(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/approvers", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testBody(t, r, `{"approver_ids":[1],"approver_group_ids":[2]}`) fmt.Fprint(w, `{ "approvers": [{"user":{"id":1}}], "approver_groups": [{"group":{"id":2}}] }`) }) opt := &ChangeAllowedApproversOptions{ ApproverIDs: []int{1}, ApproverGroupIDs: []int{2}, } approvals, _, err := client.Projects.ChangeAllowedApprovers(1, opt) if err != nil { t.Errorf("Projects.ChangeApproversConfigurationOptions returned error: %v", err) } want := &ProjectApprovals{ Approvers: []*MergeRequestApproverUser{ &MergeRequestApproverUser{ User: &BasicUser{ ID: 1, }, }, }, ApproverGroups: []*MergeRequestApproverGroup{ &MergeRequestApproverGroup{ Group: struct { ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` Description string `json:"description"` Visibility string `json:"visibility"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` FullName string `json:"full_name"` FullPath string `json:"full_path"` LFSEnabled bool `json:"lfs_enabled"` RequestAccessEnabled bool `json:"request_access_enabled"` }{ ID: 2, }, }, }, } if !reflect.DeepEqual(want, approvals) { t.Errorf("Projects.ChangeAllowedApprovers returned %+v, want %+v", approvals, want) } } func TestForkProject(t *testing.T) { mux, server, client := setup() defer teardown(server) namespace := "mynamespace" name := "myreponame" path := "myrepopath" mux.HandleFunc("/api/v4/projects/1/fork", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") testBody(t, r, fmt.Sprintf(`{"namespace":"%s","name":"%s","path":"%s"}`, namespace, name, path)) fmt.Fprint(w, `{"id":2}`) }) project, _, err := client.Projects.ForkProject(1, &ForkProjectOptions{ Namespace: String(namespace), Name: String(name), Path: String(path), }) if err != nil { t.Errorf("Projects.ForkProject returned error: %v", err) } want := &Project{ID: 2} if !reflect.DeepEqual(want, project) { t.Errorf("Projects.ForProject returned %+v, want %+v", project, want) } } func TestGetProjectApprovalRules(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/approval_rules", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[ { "id": 1, "name": "security", "rule_type": "regular", "eligible_approvers": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" }, { "id": 50, "name": "Group Member 1", "username": "group_member_1", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/group_member_1" } ], "approvals_required": 3, "users": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" } ], "groups": [ { "id": 5, "name": "group1", "path": "group1", "description": "", "visibility": "public", "lfs_enabled": false, "avatar_url": null, "web_url": "http://localhost/groups/group1", "request_access_enabled": false, "full_name": "group1", "full_path": "group1", "parent_id": null, "ldap_cn": null, "ldap_access": null } ], "contains_hidden_groups": false } ]`) }) approvals, _, err := client.Projects.GetProjectApprovalRules(1) if err != nil { t.Errorf("Projects.GetProjectApprovalRules returned error: %v", err) } want := []*ProjectApprovalRule{ &ProjectApprovalRule{ ID: 1, Name: "security", RuleType: "regular", EligibleApprovers: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, &BasicUser{ ID: 50, Name: "Group Member 1", Username: "group_member_1", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/group_member_1", }, }, ApprovalsRequired: 3, Users: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, }, Groups: []*Group{ &Group{ ID: 5, Name: "group1", Path: "group1", Description: "", Visibility: Visibility(PublicVisibility), LFSEnabled: false, AvatarURL: "", WebURL: "http://localhost/groups/group1", RequestAccessEnabled: false, FullName: "group1", FullPath: "group1", }, }, }, } if !reflect.DeepEqual(want, approvals) { t.Errorf("Projects.GetProjectApprovalRules returned %+v, want %+v", approvals, want) } } func TestCreateProjectApprovalRule(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/approval_rules", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{ "id": 1, "name": "security", "rule_type": "regular", "eligible_approvers": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" }, { "id": 50, "name": "Group Member 1", "username": "group_member_1", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/group_member_1" } ], "approvals_required": 3, "users": [ { "id": 5, "name": "John Doe", "username": "jdoe", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon", "web_url": "http://localhost/jdoe" } ], "groups": [ { "id": 5, "name": "group1", "path": "group1", "description": "", "visibility": "public", "lfs_enabled": false, "avatar_url": null, "web_url": "http://localhost/groups/group1", "request_access_enabled": false, "full_name": "group1", "full_path": "group1", "parent_id": null, "ldap_cn": null, "ldap_access": null } ], "contains_hidden_groups": false }`) }) opt := &CreateProjectLevelRuleOptions{ Name: String("security"), ApprovalsRequired: Int(3), UserIDs: []int{5, 50}, GroupIDs: []int{5}, } rule, _, err := client.Projects.CreateProjectApprovalRule(1, opt) if err != nil { t.Errorf("Projects.CreateProjectApprovalRule returned error: %v", err) } want := &ProjectApprovalRule{ ID: 1, Name: "security", RuleType: "regular", EligibleApprovers: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, &BasicUser{ ID: 50, Name: "Group Member 1", Username: "group_member_1", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/group_member_1", }, }, ApprovalsRequired: 3, Users: []*BasicUser{ &BasicUser{ ID: 5, Name: "John Doe", Username: "jdoe", State: "active", AvatarURL: "https://www.gravatar.com/avatar/0?s=80&d=identicon", WebURL: "http://localhost/jdoe", }, }, Groups: []*Group{ &Group{ ID: 5, Name: "group1", Path: "group1", Description: "", Visibility: Visibility(PublicVisibility), LFSEnabled: false, AvatarURL: "", WebURL: "http://localhost/groups/group1", RequestAccessEnabled: false, FullName: "group1", FullPath: "group1", }, }, } if !reflect.DeepEqual(want, rule) { t.Errorf("Projects.CreateProjectApprovalRule returned %+v, want %+v", rule, want) } } golang-github-xanzy-go-gitlab-0.22.2/protected_branches.go000066400000000000000000000125461357140411500235340ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen, Michael Lihs // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/url" ) // ProtectedBranchesService handles communication with the protected branch // related methods of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#protected-branches-api type ProtectedBranchesService struct { client *Client } // BranchAccessDescription represents the access description for a protected // branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#protected-branches-api type BranchAccessDescription struct { AccessLevel AccessLevelValue `json:"access_level"` AccessLevelDescription string `json:"access_level_description"` } // ProtectedBranch represents a protected branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches type ProtectedBranch struct { Name string `json:"name"` PushAccessLevels []*BranchAccessDescription `json:"push_access_levels"` MergeAccessLevels []*BranchAccessDescription `json:"merge_access_levels"` } // ListProtectedBranchesOptions represents the available ListProtectedBranches() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches type ListProtectedBranchesOptions ListOptions // ListProtectedBranches gets a list of protected branches from a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches func (s *ProtectedBranchesService) ListProtectedBranches(pid interface{}, opt *ListProtectedBranchesOptions, options ...OptionFunc) ([]*ProtectedBranch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/protected_branches", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var p []*ProtectedBranch resp, err := s.client.Do(req, &p) if err != nil { return nil, resp, err } return p, resp, err } // GetProtectedBranch gets a single protected branch or wildcard protected branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#get-a-single-protected-branch-or-wildcard-protected-branch func (s *ProtectedBranchesService) GetProtectedBranch(pid interface{}, branch string, options ...OptionFunc) (*ProtectedBranch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/protected_branches/%s", pathEscape(project), url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } p := new(ProtectedBranch) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // ProtectRepositoryBranchesOptions represents the available // ProtectRepositoryBranches() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches type ProtectRepositoryBranchesOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` PushAccessLevel *AccessLevelValue `url:"push_access_level,omitempty" json:"push_access_level,omitempty"` MergeAccessLevel *AccessLevelValue `url:"merge_access_level,omitempty" json:"merge_access_level,omitempty"` } // ProtectRepositoryBranches protects a single repository branch or several // project repository branches using a wildcard protected branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches func (s *ProtectedBranchesService) ProtectRepositoryBranches(pid interface{}, opt *ProtectRepositoryBranchesOptions, options ...OptionFunc) (*ProtectedBranch, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/protected_branches", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } p := new(ProtectedBranch) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // UnprotectRepositoryBranches unprotects the given protected branch or wildcard // protected branch. // // GitLab API docs: // https://docs.gitlab.com/ce/api/protected_branches.html#unprotect-repository-branches func (s *ProtectedBranchesService) UnprotectRepositoryBranches(pid interface{}, branch string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/protected_branches/%s", pathEscape(project), url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/protected_tags.go000066400000000000000000000103611357140411500226760ustar00rootroot00000000000000package gitlab import ( "fmt" ) // ProtectedTagsService handles communication with the protected tag methods // of the GitLab API. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html type ProtectedTagsService struct { client *Client } // ProtectedTag represents a protected tag. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html type ProtectedTag struct { Name string `json:"name"` CreateAccessLevels []*TagAccessDescription `json:"create_access_levels"` } // TagAccessDescription reperesents the access decription for a protected tag. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html type TagAccessDescription struct { AccessLevel AccessLevelValue `json:"access_level"` AccessLevelDescription string `json:"access_level_description"` } // ListProtectedTagsOptions represents the available ListProtectedTags() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags type ListProtectedTagsOptions ListOptions // ListProtectedTags returns a list of protected tags from a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags func (s *ProtectedTagsService) ListProtectedTags(pid interface{}, opt *ListProtectedTagsOptions, options ...OptionFunc) ([]*ProtectedTag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/protected_tags", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var pts []*ProtectedTag resp, err := s.client.Do(req, &pts) if err != nil { return nil, resp, err } return pts, resp, err } // GetProtectedTag returns a single protected tag or wildcard protected tag. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html#get-a-single-protected-tag-or-wildcard-protected-tag func (s *ProtectedTagsService) GetProtectedTag(pid interface{}, tag string, options ...OptionFunc) (*ProtectedTag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/protected_tags/%s", pathEscape(project), pathEscape(tag)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } pt := new(ProtectedTag) resp, err := s.client.Do(req, pt) if err != nil { return nil, resp, err } return pt, resp, err } // ProtectRepositoryTagsOptions represents the available ProtectRepositoryTags() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags type ProtectRepositoryTagsOptions struct { Name *string `url:"name" json:"name"` CreateAccessLevel *AccessLevelValue `url:"create_access_level,omitempty" json:"create_access_level,omitempty"` } // ProtectRepositoryTags protects a single repository tag or several project // repository tags using a wildcard protected tag. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags func (s *ProtectedTagsService) ProtectRepositoryTags(pid interface{}, opt *ProtectRepositoryTagsOptions, options ...OptionFunc) (*ProtectedTag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/protected_tags", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } pt := new(ProtectedTag) resp, err := s.client.Do(req, pt) if err != nil { return nil, resp, err } return pt, resp, err } // UnprotectRepositoryTags unprotects the given protected tag or wildcard // protected tag. // // GitLab API docs: // https://docs.gitlab.com/ee/api/protected_tags.html#unprotect-repository-tags func (s *ProtectedTagsService) UnprotectRepositoryTags(pid interface{}, tag string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/protected_tags/%s", pathEscape(project), pathEscape(tag)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/protected_tags_test.go000066400000000000000000000125001357140411500237320ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestListProtectedTags(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"name":"1.0.0", "create_access_levels": [{"access_level": 40, "access_level_description": "Maintainers"}]},{"name":"*-release", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}]`) }) expected := []*ProtectedTag{ { Name: "1.0.0", CreateAccessLevels: []*TagAccessDescription{ { AccessLevel: 40, AccessLevelDescription: "Maintainers", }, }, }, { Name: "*-release", CreateAccessLevels: []*TagAccessDescription{ { AccessLevel: 30, AccessLevelDescription: "Developers + Maintainers", }, }, }, } opt := &ListProtectedTagsOptions{} tags, _, err := client.ProtectedTags.ListProtectedTags(1, opt) assert.NoError(t, err, "failed to get response") assert.Equal(t, expected, tags) } func TestListProtectedTags_WithServerError(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") w.WriteHeader(http.StatusInternalServerError) }) opt := &ListProtectedTagsOptions{} tags, resp, err := client.ProtectedTags.ListProtectedTags(1, opt) assert.Error(t, err) assert.Nil(t, tags) assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) } func TestGetProtectedTag(t *testing.T) { mux, server, client := setup() defer teardown(server) tagName := "my-awesome-tag" mux.HandleFunc(fmt.Sprintf("/api/v4/projects/1/protected_tags/%s", tagName), func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}`) }) expected := &ProtectedTag{ Name: tagName, CreateAccessLevels: []*TagAccessDescription{ { AccessLevel: 30, AccessLevelDescription: "Developers + Maintainers", }, }, } tag, _, err := client.ProtectedTags.GetProtectedTag(1, tagName) assert.NoError(t, err, "failed to get response") assert.Equal(t, expected, tag) } func TestGetProtectedTag_WithServerError(t *testing.T) { mux, server, client := setup() defer teardown(server) tagName := "my-awesome-tag" mux.HandleFunc(fmt.Sprintf("/api/v4/projects/1/protected_tags/%s", tagName), func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") w.WriteHeader(http.StatusInternalServerError) }) tag, resp, err := client.ProtectedTags.GetProtectedTag(1, tagName) assert.Error(t, err) assert.Nil(t, tag) assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) } func TestProtectRepositoryTags(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}`) }) expected := &ProtectedTag{ Name: "my-awesome-tag", CreateAccessLevels: []*TagAccessDescription{ { AccessLevel: 30, AccessLevelDescription: "Developers + Maintainers", }, }, } opt := &ProtectRepositoryTagsOptions{Name: String("my-awesome-tag"), CreateAccessLevel: AccessLevel(30)} tag, _, err := client.ProtectedTags.ProtectRepositoryTags(1, opt) assert.NoError(t, err, "failed to get response") assert.Equal(t, expected, tag) } func TestProtectRepositoryTags_WithServerError(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, `{"message":"some error"}`) }) opt := &ProtectRepositoryTagsOptions{Name: String("my-awesome-tag"), CreateAccessLevel: AccessLevel(30)} tag, resp, err := client.ProtectedTags.ProtectRepositoryTags(1, opt) assert.Nil(t, tag) assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) assert.Error(t, err) } func TestUnprotectRepositoryTags(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/protected_tags/my-awesome-tag", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) resp, err := client.ProtectedTags.UnprotectRepositoryTags(1, "my-awesome-tag") assert.NoError(t, err, "failed to get response") assert.Equal(t, http.StatusOK, resp.StatusCode) } func TestUnprotectRepositoryTags_WithServerError(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/protected_tags/my-awesome-tag", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, `{"message": "some error"}`) }) resp, err := client.ProtectedTags.UnprotectRepositoryTags(1, "my-awesome-tag") assert.Error(t, err) assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) } golang-github-xanzy-go-gitlab-0.22.2/registry.go000066400000000000000000000150201357140411500215340ustar00rootroot00000000000000package gitlab import ( "fmt" "time" ) // ContainerRegistryService handles communication with the container registry // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html type ContainerRegistryService struct { client *Client } // RegistryRepository represents a GitLab content registry repository. // // GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html type RegistryRepository struct { ID int `json:"id"` Name string `json:"name"` Path string `json:"path"` Location string `json:"location"` CreatedAt *time.Time `json:"created_at"` } func (s RegistryRepository) String() string { return Stringify(s) } // RegistryRepositoryTag represents a GitLab registry image tag. // // GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html type RegistryRepositoryTag struct { Name string `json:"name"` Path string `json:"path"` Location string `json:"location"` Revision string `json:"revision"` ShortRevision string `json:"short_revision"` Digest string `json:"digest"` CreatedAt *time.Time `json:"created_at"` TotalSize int `json:"total_size"` } func (s RegistryRepositoryTag) String() string { return Stringify(s) } // ListRegistryRepositoriesOptions represents the available // ListRegistryRepositories() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repositories type ListRegistryRepositoriesOptions ListOptions // ListRegistryRepositories gets a list of registry repositories in a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repositories func (s *ContainerRegistryService) ListRegistryRepositories(pid interface{}, opt *ListRegistryRepositoriesOptions, options ...OptionFunc) ([]*RegistryRepository, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/registry/repositories", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var repos []*RegistryRepository resp, err := s.client.Do(req, &repos) if err != nil { return nil, resp, err } return repos, resp, err } // DeleteRegistryRepository deletes a repository in a registry. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#delete-registry-repository func (s *ContainerRegistryService) DeleteRegistryRepository(pid interface{}, repository int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/registry/repositories/%d", pathEscape(project), repository) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListRegistryRepositoryTagsOptions represents the available // ListRegistryRepositoryTags() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#list-repository-tags type ListRegistryRepositoryTagsOptions ListOptions // ListRegistryRepositoryTags gets a list of tags for given registry repository. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#list-repository-tags func (s *ContainerRegistryService) ListRegistryRepositoryTags(pid interface{}, repository int, opt *ListRegistryRepositoryTagsOptions, options ...OptionFunc) ([]*RegistryRepositoryTag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags", pathEscape(project), repository, ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var tags []*RegistryRepositoryTag resp, err := s.client.Do(req, &tags) if err != nil { return nil, resp, err } return tags, resp, err } // GetRegistryRepositoryTagDetail get details of a registry repository tag // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#get-details-of-a-repository-tag func (s *ContainerRegistryService) GetRegistryRepositoryTagDetail(pid interface{}, repository int, tagName string, options ...OptionFunc) (*RegistryRepositoryTag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags/%s", pathEscape(project), repository, tagName, ) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } tag := new(RegistryRepositoryTag) resp, err := s.client.Do(req, &tag) if err != nil { return nil, resp, err } return tag, resp, err } // DeleteRegistryRepositoryTag deletes a registry repository tag. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#delete-a-repository-tag func (s *ContainerRegistryService) DeleteRegistryRepositoryTag(pid interface{}, repository int, tagName string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags/%s", pathEscape(project), repository, tagName, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteRegistryRepositoryTagsOptions represents the available // DeleteRegistryRepositoryTags() options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#delete-repository-tags-in-bulk type DeleteRegistryRepositoryTagsOptions struct { NameRegexp *string `url:"name_regex,omitempty" json:"name_regex,omitempty"` KeepN *int `url:"keep_n,omitempty" json:"keep_n,omitempty"` OlderThan *string `url:"older_than,omitempty" json:"older_than,omitempty"` } // DeleteRegistryRepositoryTags deletes repository tags in bulk based on // given criteria. // // GitLab API docs: // https://docs.gitlab.com/ee/api/container_registry.html#delete-repository-tags-in-bulk func (s *ContainerRegistryService) DeleteRegistryRepositoryTags(pid interface{}, repository int, opt *DeleteRegistryRepositoryTagsOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags", pathEscape(project), repository, ) req, err := s.client.NewRequest("DELETE", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/releaselinks.go000066400000000000000000000114041357140411500223470ustar00rootroot00000000000000package gitlab import ( "fmt" ) // ReleaseLinksService handles communication with the release link methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html type ReleaseLinksService struct { client *Client } // ReleaseLink represents a release link. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html type ReleaseLink struct { ID int `json:"id"` Name string `json:"name"` URL string `json:"url"` External bool `json:"external"` } // ListReleaseLinksOptions represents ListReleaseLinks() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#get-links type ListReleaseLinksOptions ListOptions // ListReleaseLinks gets assets as links from a Release. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#get-links func (s *ReleaseLinksService) ListReleaseLinks(pid interface{}, tagName string, opt *ListReleaseLinksOptions, options ...OptionFunc) ([]*ReleaseLink, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s/assets/links", pathEscape(project), tagName) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var rls []*ReleaseLink resp, err := s.client.Do(req, &rls) if err != nil { return nil, resp, err } return rls, resp, err } // GetReleaseLink returns a link from release assets. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#get-a-link func (s *ReleaseLinksService) GetReleaseLink(pid interface{}, tagName string, link int, options ...OptionFunc) (*ReleaseLink, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s/assets/links/%d", pathEscape(project), tagName, link) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } rl := new(ReleaseLink) resp, err := s.client.Do(req, rl) if err != nil { return nil, resp, err } return rl, resp, err } // CreateReleaseLinkOptions represents CreateReleaseLink() options. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#create-a-link type CreateReleaseLinkOptions struct { Name *string `url:"name" json:"name"` URL *string `url:"url" json:"url"` } // CreateReleaseLink creates a link. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#create-a-link func (s *ReleaseLinksService) CreateReleaseLink(pid interface{}, tagName string, opt *CreateReleaseLinkOptions, options ...OptionFunc) (*ReleaseLink, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s/assets/links", pathEscape(project), tagName) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } rl := new(ReleaseLink) resp, err := s.client.Do(req, rl) if err != nil { return nil, resp, err } return rl, resp, err } // UpdateReleaseLinkOptions represents UpdateReleaseLink() options. // // You have to specify at least one of Name of URL. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#update-a-link type UpdateReleaseLinkOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` URL *string `url:"url,omitempty" json:"url,omitempty"` } // UpdateReleaseLink updates an asset link. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#update-a-link func (s *ReleaseLinksService) UpdateReleaseLink(pid interface{}, tagName string, link int, opt *UpdateReleaseLinkOptions, options ...OptionFunc) (*ReleaseLink, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s/assets/links/%d", pathEscape(project), tagName, link) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } rl := new(ReleaseLink) resp, err := s.client.Do(req, rl) if err != nil { return nil, resp, err } return rl, resp, err } // DeleteReleaseLink deletes a link from release. // // GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#delete-a-link func (s *ReleaseLinksService) DeleteReleaseLink(pid interface{}, tagName string, link int, options ...OptionFunc) (*ReleaseLink, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s/assets/links/%d", pathEscape(project), tagName, link, ) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, nil, err } rl := new(ReleaseLink) resp, err := s.client.Do(req, rl) if err != nil { return nil, resp, err } return rl, resp, err } golang-github-xanzy-go-gitlab-0.22.2/releaselinks_test.go000066400000000000000000000071301357140411500234070ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "testing" ) const exampleReleaseLinkList = `[ { "id": 2, "name": "awesome-v0.2.msi", "url": "http://192.168.10.15:3000/msi", "external": true }, { "id": 1, "name": "awesome-v0.2.dmg", "url": "http://192.168.10.15:3000", "external": true } ]` func TestReleaseLinksService_ListReleaseLinks(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1/assets/links", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, exampleReleaseLinkList) }) releaseLinks, _, err := client.ReleaseLinks.ListReleaseLinks( 1, "v0.1", &ListReleaseLinksOptions{}, ) if err != nil { t.Error(err) } if len(releaseLinks) != 2 { t.Error("expected 2 links") } if releaseLinks[0].Name != "awesome-v0.2.msi" { t.Errorf("release link name, expected '%s', got '%s'", "awesome-v0.2.msi", releaseLinks[0].Name) } } const exampleReleaseLink = `{ "id":1, "name":"awesome-v0.2.dmg", "url":"http://192.168.10.15:3000", "external":true }` func TestReleaseLinksService_CreateReleaseLink(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1/assets/links", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, exampleReleaseLink) }) releaseLink, _, err := client.ReleaseLinks.CreateReleaseLink( 1, "v0.1", &CreateReleaseLinkOptions{ Name: String("awesome-v0.2.dmg"), URL: String("http://192.168.10.15:3000"), }) if err != nil { t.Error(err) } if releaseLink.Name != "awesome-v0.2.dmg" { t.Errorf("release link name, expected '%s', got '%s'", "awesome-v0.2.dmg", releaseLink.Name) } } func TestReleaseLinksService_GetReleaseLink(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1/assets/links/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, exampleReleaseLink) }) releaseLink, _, err := client.ReleaseLinks.GetReleaseLink(1, "v0.1", 1) if err != nil { t.Error(err) } if releaseLink.Name != "awesome-v0.2.dmg" { t.Errorf("release link name, expected '%s', got '%s'", "awesome-v0.2.dmg", releaseLink.Name) } } func TestReleaseLinksService_UpdateReleaseLink(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1/assets/links/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, exampleReleaseLink) }) releaseLink, _, err := client.ReleaseLinks.UpdateReleaseLink( 1, "v0.1", 1, &UpdateReleaseLinkOptions{ Name: String("awesome-v0.2.dmg"), }) if err != nil { t.Error(err) } if releaseLink.Name != "awesome-v0.2.dmg" { t.Errorf("release link name, expected '%s', got '%s'", "awesome-v0.2.dmg", releaseLink.Name) } } func TestReleaseLinksService_DeleteReleaseLink(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1/assets/links/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") fmt.Fprint(w, exampleReleaseLink) }) releaseLink, _, err := client.ReleaseLinks.DeleteReleaseLink(1, "v0.1", 1) if err != nil { t.Error(err) } if releaseLink.Name != "awesome-v0.2.dmg" { t.Errorf("release link name, expected '%s', got '%s'", "awesome-v0.2.dmg", releaseLink.Name) } } golang-github-xanzy-go-gitlab-0.22.2/releases.go000066400000000000000000000135241357140411500214760ustar00rootroot00000000000000package gitlab import ( "fmt" "time" ) // ReleasesService handles communication with the releases methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/releases/index.html type ReleasesService struct { client *Client } // Release represents a project release. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#list-releases type Release struct { TagName string `json:"tag_name"` Name string `json:"name"` Description string `json:"description,omitempty"` DescriptionHTML string `json:"description_html,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` Author struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"author"` Commit Commit `json:"commit"` Assets struct { Count int `json:"count"` Sources []struct { Format string `json:"format"` URL string `json:"url"` } `json:"sources"` Links []*ReleaseLink `json:"links"` } `json:"assets"` } // ListReleasesOptions represents ListReleases() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#list-releases type ListReleasesOptions ListOptions // ListReleases gets a pagenated of releases accessible by the authenticated user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#list-releases func (s *ReleasesService) ListReleases(pid interface{}, opt *ListReleasesOptions, options ...OptionFunc) ([]*Release, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var rs []*Release resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err } return rs, resp, err } // GetRelease returns a single release, identified by a tag name. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#get-a-release-by-a-tag-name func (s *ReleasesService) GetRelease(pid interface{}, tagName string, options ...OptionFunc) (*Release, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } r := new(Release) resp, err := s.client.Do(req, r) if err != nil { return nil, resp, err } return r, resp, err } // ReleaseAssets represents release assets in CreateRelease() options // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#create-a-release type ReleaseAssets struct { Links []*ReleaseAssetLink `url:"links" json:"links"` } // ReleaseAssetLink represents release asset link in CreateRelease() options // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#create-a-release type ReleaseAssetLink struct { Name string `url:"name" json:"name"` URL string `url:"url" json:"url"` } // CreateReleaseOptions represents CreateRelease() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#create-a-release type CreateReleaseOptions struct { Name *string `url:"name" json:"name"` TagName *string `url:"tag_name" json:"tag_name"` Description *string `url:"description" json:"description"` Ref *string `url:"ref,omitempty" json:"ref,omitempty"` Assets *ReleaseAssets `url:"assets,omitempty" json:"assets,omitempty"` } // CreateRelease creates a release. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#create-a-release func (s *ReleasesService) CreateRelease(pid interface{}, opts *CreateReleaseOptions, options ...OptionFunc) (*Release, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opts, options) if err != nil { return nil, nil, err } r := new(Release) resp, err := s.client.Do(req, r) if err != nil { return nil, resp, err } return r, resp, err } // UpdateReleaseOptions represents UpdateRelease() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#update-a-release type UpdateReleaseOptions struct { Name *string `url:"name" json:"name"` Description *string `url:"description" json:"description"` } // UpdateRelease updates a release. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#update-a-release func (s *ReleasesService) UpdateRelease(pid interface{}, tagName string, opts *UpdateReleaseOptions, options ...OptionFunc) (*Release, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName) req, err := s.client.NewRequest("PUT", u, opts, options) if err != nil { return nil, nil, err } r := new(Release) resp, err := s.client.Do(req, &r) if err != nil { return nil, resp, err } return r, resp, err } // DeleteRelease deletes a release. // // GitLab API docs: // https://docs.gitlab.com/ce/api/releases/index.html#delete-a-release func (s *ReleasesService) DeleteRelease(pid interface{}, tagName string, options ...OptionFunc) (*Release, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, nil, err } r := new(Release) resp, err := s.client.Do(req, r) if err != nil { return nil, resp, err } return r, resp, err } golang-github-xanzy-go-gitlab-0.22.2/releases_test.go000066400000000000000000000216371357140411500225410ustar00rootroot00000000000000package gitlab import ( "fmt" "io/ioutil" "net/http" "strings" "testing" ) const exampleReleaseListRsp = `[ { "tag_name": "v0.2", "description": "description", "name": "Awesome app v0.2 beta", "description_html": "html", "created_at": "2019-01-03T01:56:19.539Z", "author": { "id": 1, "name": "Administrator", "username": "root", "state": "active", "avatar_url": "https://www.gravatar.com/avatar", "web_url": "http://localhost:3000/root" }, "commit": { "id": "079e90101242458910cccd35eab0e211dfc359c0", "short_id": "079e9010", "title": "Update README.md", "created_at": "2019-01-03T01:55:38.000Z", "parent_ids": [ "f8d3d94cbd347e924aa7b715845e439d00e80ca4" ], "message": "Update README.md", "author_name": "Administrator", "author_email": "admin@example.com", "authored_date": "2019-01-03T01:55:38.000Z", "committer_name": "Administrator", "committer_email": "admin@example.com", "committed_date": "2019-01-03T01:55:38.000Z" }, "assets": { "count": 4, "sources": [ { "format": "zip", "url": "http://localhost:3000/archive/v0.2/awesome-app-v0.2.zip" }, { "format": "tar.gz", "url": "http://localhost:3000/archive/v0.2/awesome-app-v0.2.tar.gz" } ], "links": [ { "id": 2, "name": "awesome-v0.2.msi", "url": "http://192.168.10.15:3000/msi", "external": true }, { "id": 1, "name": "awesome-v0.2.dmg", "url": "http://192.168.10.15:3000", "external": true } ] } }, { "tag_name": "v0.1", "description": "description", "name": "Awesome app v0.1 alpha", "description_html": "description_html", "created_at": "2019-01-03T01:55:18.203Z", "author": { "id": 1, "name": "Administrator", "username": "root", "state": "active", "avatar_url": "https://www.gravatar.com/avatar", "web_url": "http://localhost:3000/root" }, "commit": { "id": "f8d3d94cbd347e924aa7b715845e439d00e80ca4", "short_id": "f8d3d94c", "title": "Initial commit", "created_at": "2019-01-03T01:53:28.000Z", "parent_ids": [], "message": "Initial commit", "author_name": "Administrator", "author_email": "admin@example.com", "authored_date": "2019-01-03T01:53:28.000Z", "committer_name": "Administrator", "committer_email": "admin@example.com", "committed_date": "2019-01-03T01:53:28.000Z" }, "assets": { "count": 2, "sources": [ { "format": "zip", "url": "http://localhost:3000/archive/v0.1/awesome-app-v0.1.zip" }, { "format": "tar.gz", "url": "http://localhost:3000/archive/v0.1/awesome-app-v0.1.tar.gz" } ], "links": [] } } ]` func TestReleasesService_ListReleases(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, exampleReleaseListRsp) }) opt := &ListReleasesOptions{} releases, _, err := client.Releases.ListReleases(1, opt) if err != nil { t.Error(err) } if len(releases) != 2 { t.Error("expected 2 releases") } } const exampleReleaseRsp = `{ "tag_name": "v0.1", "description": "description", "name": "Awesome app v0.1 alpha", "description_html": "description_html", "created_at": "2019-01-03T01:55:18.203Z", "author": { "id": 1, "name": "Administrator", "username": "root", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/", "web_url": "http://localhost:3000/root" }, "commit": { "id": "f8d3d94cbd347e924aa7b715845e439d00e80ca4", "short_id": "f8d3d94c", "title": "Initial commit", "created_at": "2019-01-03T01:53:28.000Z", "parent_ids": [], "message": "Initial commit", "author_name": "Administrator", "author_email": "admin@example.com", "authored_date": "2019-01-03T01:53:28.000Z", "committer_name": "Administrator", "committer_email": "admin@example.com", "committed_date": "2019-01-03T01:53:28.000Z" }, "assets": { "count": 2, "sources": [ { "format": "zip", "url": "http://localhost:3000/archive/v0.1/awesome-app-v0.1.zip" }, { "format": "tar.gz", "url": "http://localhost:3000/archive/v0.1/awesome-app-v0.1.tar.gz" } ], "links": [] } }` func TestReleasesService_GetRelease(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, exampleReleaseRsp) }) release, _, err := client.Releases.GetRelease(1, "v0.1") if err != nil { t.Error(err) } if release.TagName != "v0.1" { t.Errorf("expected tag v0.1, got %s", release.TagName) } } func TestReleasesService_CreateRelease(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") b, err := ioutil.ReadAll(r.Body) if err != nil { t.Fatalf("unable to read request body") } if !strings.Contains(string(b), "v0.1") { t.Errorf("expected request body to contain v0.1, got %s", string(b)) } if strings.Contains(string(b), "assets") { t.Errorf("expected request body not to have assets, got %s", string(b)) } fmt.Fprint(w, exampleReleaseRsp) }) opts := &CreateReleaseOptions{ Name: String("name"), TagName: String("v0.1"), Description: String("Description"), } release, _, err := client.Releases.CreateRelease(1, opts) if err != nil { t.Error(err) } if release.TagName != "v0.1" { t.Errorf("expected tag v0.1, got %s", release.TagName) } } func TestReleasesService_CreateReleaseWithAsset(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") b, err := ioutil.ReadAll(r.Body) if err != nil { t.Fatalf("unable to read request body") } if !strings.Contains(string(b), "v0.1") { t.Errorf("expected request body to contain v0.1, got %s", string(b)) } if !strings.Contains(string(b), "assets") { t.Errorf("expected request body to have assets, got %s", string(b)) } fmt.Fprint(w, exampleReleaseRsp) }) opts := &CreateReleaseOptions{ Name: String("name"), TagName: String("v0.1"), Description: String("Description"), Assets: &ReleaseAssets{ Links: []*ReleaseAssetLink{ {"sldkf", "sldkfj"}, }, }, } release, _, err := client.Releases.CreateRelease(1, opts) if err != nil { t.Error(err) } if release.TagName != "v0.1" { t.Errorf("expected tag v0.1, got %s", release.TagName) } } func TestReleasesService_UpdateRelease(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, exampleReleaseRsp) }) opts := &UpdateReleaseOptions{ Name: String("name"), Description: String("Description"), } release, _, err := client.Releases.UpdateRelease(1, "v0.1", opts) if err != nil { t.Error(err) } if release.TagName != "v0.1" { t.Errorf("expected tag v0.1, got %s", release.TagName) } } func TestReleasesService_DeleteRelease(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/releases/v0.1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") fmt.Fprint(w, exampleReleaseRsp) }) release, _, err := client.Releases.DeleteRelease(1, "v0.1") if err != nil { t.Error(err) } if release.TagName != "v0.1" { t.Errorf("expected tag v0.1, got %s", release.TagName) } } golang-github-xanzy-go-gitlab-0.22.2/repositories.go000066400000000000000000000223151357140411500224200ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "bytes" "fmt" "io" "net/url" ) // RepositoriesService handles communication with the repositories related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html type RepositoriesService struct { client *Client } // TreeNode represents a GitLab repository file or directory. // // GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html type TreeNode struct { ID string `json:"id"` Name string `json:"name"` Type string `json:"type"` Path string `json:"path"` Mode string `json:"mode"` } func (t TreeNode) String() string { return Stringify(t) } // ListTreeOptions represents the available ListTree() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree type ListTreeOptions struct { ListOptions Path *string `url:"path,omitempty" json:"path,omitempty"` Ref *string `url:"ref,omitempty" json:"ref,omitempty"` Recursive *bool `url:"recursive,omitempty" json:"recursive,omitempty"` } // ListTree gets a list of repository files and directories in a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree func (s *RepositoriesService) ListTree(pid interface{}, opt *ListTreeOptions, options ...OptionFunc) ([]*TreeNode, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/tree", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var t []*TreeNode resp, err := s.client.Do(req, &t) if err != nil { return nil, resp, err } return t, resp, err } // Blob gets information about blob in repository like size and content. Note // that blob content is Base64 encoded. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#get-a-blob-from-repository func (s *RepositoriesService) Blob(pid interface{}, sha string, options ...OptionFunc) ([]byte, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/blobs/%s", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var b bytes.Buffer resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b.Bytes(), resp, err } // RawBlobContent gets the raw file contents for a blob by blob SHA. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#raw-blob-content func (s *RepositoriesService) RawBlobContent(pid interface{}, sha string, options ...OptionFunc) ([]byte, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/blobs/%s/raw", pathEscape(project), url.PathEscape(sha)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var b bytes.Buffer resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b.Bytes(), resp, err } // ArchiveOptions represents the available Archive() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#get-file-archive type ArchiveOptions struct { Format *string `url:"-" json:"-"` SHA *string `url:"sha,omitempty" json:"sha,omitempty"` } // Archive gets an archive of the repository. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#get-file-archive func (s *RepositoriesService) Archive(pid interface{}, opt *ArchiveOptions, options ...OptionFunc) ([]byte, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/archive", pathEscape(project)) // Set an optional format for the archive. if opt != nil && opt.Format != nil { u = fmt.Sprintf("%s.%s", u, *opt.Format) } req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var b bytes.Buffer resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b.Bytes(), resp, err } // StreamArchive streams an archive of the repository to the provided // io.Writer. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#get-file-archive func (s *RepositoriesService) StreamArchive(pid interface{}, w io.Writer, opt *ArchiveOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/repository/archive", pathEscape(project)) // Set an optional format for the archive. if opt != nil && opt.Format != nil { u = fmt.Sprintf("%s.%s", u, *opt.Format) } req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, w) } // Compare represents the result of a comparison of branches, tags or commits. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits type Compare struct { Commit *Commit `json:"commit"` Commits []*Commit `json:"commits"` Diffs []*Diff `json:"diffs"` CompareTimeout bool `json:"compare_timeout"` CompareSameRef bool `json:"compare_same_ref"` } func (c Compare) String() string { return Stringify(c) } // CompareOptions represents the available Compare() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits type CompareOptions struct { From *string `url:"from,omitempty" json:"from,omitempty"` To *string `url:"to,omitempty" json:"to,omitempty"` Straight *bool `url:"straight,omitempty" json:"straight,omitempty"` } // Compare compares branches, tags or commits. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits func (s *RepositoriesService) Compare(pid interface{}, opt *CompareOptions, options ...OptionFunc) (*Compare, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/compare", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } c := new(Compare) resp, err := s.client.Do(req, c) if err != nil { return nil, resp, err } return c, resp, err } // Contributor represents a GitLap contributor. // // GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors type Contributor struct { Name string `json:"name"` Email string `json:"email"` Commits int `json:"commits"` Additions int `json:"additions"` Deletions int `json:"deletions"` } func (c Contributor) String() string { return Stringify(c) } // ListContributorsOptions represents the available ListContributors() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors type ListContributorsOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // Contributors gets the repository contributors list. // // GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors func (s *RepositoriesService) Contributors(pid interface{}, opt *ListContributorsOptions, options ...OptionFunc) ([]*Contributor, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/contributors", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var c []*Contributor resp, err := s.client.Do(req, &c) if err != nil { return nil, resp, err } return c, resp, err } // MergeBaseOptions represents the available MergeBase() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#merge-base type MergeBaseOptions struct { Ref []string `url:"refs[],omitempty" json:"refs,omitempty"` } // MergeBase gets the common ancestor for 2 refs (commit SHAs, branch // names or tags). // // GitLab API docs: // https://docs.gitlab.com/ce/api/repositories.html#merge-base func (s *RepositoriesService) MergeBase(pid interface{}, opt *MergeBaseOptions, options ...OptionFunc) (*Commit, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/merge_base", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } c := new(Commit) resp, err := s.client.Do(req, c) if err != nil { return nil, resp, err } return c, resp, err } golang-github-xanzy-go-gitlab-0.22.2/repository_files.go000066400000000000000000000223671357140411500233010ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "bytes" "fmt" "net/url" "strconv" ) // RepositoryFilesService handles communication with the repository files // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html type RepositoryFilesService struct { client *Client } // File represents a GitLab repository file. // // GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html type File struct { FileName string `json:"file_name"` FilePath string `json:"file_path"` Size int `json:"size"` Encoding string `json:"encoding"` Content string `json:"content"` Ref string `json:"ref"` BlobID string `json:"blob_id"` CommitID string `json:"commit_id"` SHA256 string `json:"content_sha256"` } func (r File) String() string { return Stringify(r) } // GetFileOptions represents the available GetFile() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository type GetFileOptions struct { Ref *string `url:"ref,omitempty" json:"ref,omitempty"` } // GetFile allows you to receive information about a file in repository like // name, size, content. Note that file content is Base64 encoded. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository func (s *RepositoryFilesService) GetFile(pid interface{}, fileName string, opt *GetFileOptions, options ...OptionFunc) (*File, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf( "projects/%s/repository/files/%s", pathEscape(project), url.PathEscape(fileName), ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } f := new(File) resp, err := s.client.Do(req, f) if err != nil { return nil, resp, err } return f, resp, err } // GetFileMetaDataOptions represents the available GetFileMetaData() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository type GetFileMetaDataOptions struct { Ref *string `url:"ref,omitempty" json:"ref,omitempty"` } // GetFileMetaData allows you to receive meta information about a file in // repository like name, size. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository func (s *RepositoryFilesService) GetFileMetaData(pid interface{}, fileName string, opt *GetFileMetaDataOptions, options ...OptionFunc) (*File, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf( "projects/%s/repository/files/%s", pathEscape(project), url.PathEscape(fileName), ) req, err := s.client.NewRequest("HEAD", u, opt, options) if err != nil { return nil, nil, err } resp, err := s.client.Do(req, nil) if err != nil { return nil, resp, err } f := &File{ BlobID: resp.Header.Get("X-Gitlab-Blob-Id"), CommitID: resp.Header.Get("X-Gitlab-Last-Commit-Id"), Encoding: resp.Header.Get("X-Gitlab-Encoding"), FileName: resp.Header.Get("X-Gitlab-File-Name"), FilePath: resp.Header.Get("X-Gitlab-File-Path"), Ref: resp.Header.Get("X-Gitlab-Ref"), SHA256: resp.Header.Get("X-Gitlab-Content-Sha256"), } if sizeString := resp.Header.Get("X-Gitlab-Size"); sizeString != "" { f.Size, err = strconv.Atoi(sizeString) if err != nil { return nil, resp, err } } return f, resp, err } // GetRawFileOptions represents the available GetRawFile() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository type GetRawFileOptions struct { Ref *string `url:"ref,omitempty" json:"ref,omitempty"` } // GetRawFile allows you to receive the raw file in repository. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository func (s *RepositoryFilesService) GetRawFile(pid interface{}, fileName string, opt *GetRawFileOptions, options ...OptionFunc) ([]byte, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf( "projects/%s/repository/files/%s/raw", pathEscape(project), url.PathEscape(fileName), ) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var f bytes.Buffer resp, err := s.client.Do(req, &f) if err != nil { return nil, resp, err } return f.Bytes(), resp, err } // FileInfo represents file details of a GitLab repository file. // // GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html type FileInfo struct { FilePath string `json:"file_path"` Branch string `json:"branch"` } func (r FileInfo) String() string { return Stringify(r) } // CreateFileOptions represents the available CreateFile() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository type CreateFileOptions struct { Branch *string `url:"branch,omitempty" json:"branch,omitempty"` Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"` AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` Content *string `url:"content,omitempty" json:"content,omitempty"` CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` } // CreateFile creates a new file in a repository. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository func (s *RepositoryFilesService) CreateFile(pid interface{}, fileName string, opt *CreateFileOptions, options ...OptionFunc) (*FileInfo, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf( "projects/%s/repository/files/%s", pathEscape(project), url.PathEscape(fileName), ) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } f := new(FileInfo) resp, err := s.client.Do(req, f) if err != nil { return nil, resp, err } return f, resp, err } // UpdateFileOptions represents the available UpdateFile() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository type UpdateFileOptions struct { Branch *string `url:"branch,omitempty" json:"branch,omitempty"` Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"` AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` Content *string `url:"content,omitempty" json:"content,omitempty"` CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` LastCommitID *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"` } // UpdateFile updates an existing file in a repository // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository func (s *RepositoryFilesService) UpdateFile(pid interface{}, fileName string, opt *UpdateFileOptions, options ...OptionFunc) (*FileInfo, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf( "projects/%s/repository/files/%s", pathEscape(project), url.PathEscape(fileName), ) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } f := new(FileInfo) resp, err := s.client.Do(req, f) if err != nil { return nil, resp, err } return f, resp, err } // DeleteFileOptions represents the available DeleteFile() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository type DeleteFileOptions struct { Branch *string `url:"branch,omitempty" json:"branch,omitempty"` AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` } // DeleteFile deletes an existing file in a repository // // GitLab API docs: // https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository func (s *RepositoryFilesService) DeleteFile(pid interface{}, fileName string, opt *DeleteFileOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf( "projects/%s/repository/files/%s", pathEscape(project), url.PathEscape(fileName), ) req, err := s.client.NewRequest("DELETE", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/resource_label_events.go000066400000000000000000000147301357140411500242450ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // ResourceLabelEventsService handles communication with the event related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ee/api/resource_label_events.html type ResourceLabelEventsService struct { client *Client } // LabelEvent represents a resource label event. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-issue-label-event type LabelEvent struct { ID int `json:"id"` Action string `json:"action"` CreatedAt *time.Time `json:"created_at"` ResourceType string `json:"resource_type"` ResourceID int `json:"resource_id"` User struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"user"` Label struct { ID int `json:"id"` Name string `json:"name"` Color string `json:"color"` TextColor string `json:"text_color"` Description string `json:"description"` } `json:"label"` } // ListLabelEventsOptions represents the options for all resource label events // list methods. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#list-project-issue-label-events type ListLabelEventsOptions struct { ListOptions } // ListIssueLabelEvents retrieves resource label events for the // specified project and issue. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#list-project-issue-label-events func (s *ResourceLabelEventsService) ListIssueLabelEvents(pid interface{}, issue int, opt *ListLabelEventsOptions, options ...OptionFunc) ([]*LabelEvent, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/resource_label_events", pathEscape(project), issue) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ls []*LabelEvent resp, err := s.client.Do(req, &ls) if err != nil { return nil, resp, err } return ls, resp, err } // GetIssueLabelEvent gets a single issue-label-event. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-issue-label-event func (s *ResourceLabelEventsService) GetIssueLabelEvent(pid interface{}, issue int, event int, options ...OptionFunc) (*LabelEvent, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/issues/%d/resource_label_events/%d", pathEscape(project), issue, event) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } l := new(LabelEvent) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // ListGroupEpicLabelEvents retrieves resource label events for the specified // group and epic. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#list-group-epic-label-events func (s *ResourceLabelEventsService) ListGroupEpicLabelEvents(gid interface{}, epic int, opt *ListLabelEventsOptions, options ...OptionFunc) ([]*LabelEvent, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/resource_label_events", pathEscape(group), epic) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ls []*LabelEvent resp, err := s.client.Do(req, &ls) if err != nil { return nil, resp, err } return ls, resp, err } // GetGroupEpicLabelEvent gets a single group epic label event. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-epic-label-event func (s *ResourceLabelEventsService) GetGroupEpicLabelEvent(gid interface{}, epic int, event int, options ...OptionFunc) (*LabelEvent, *Response, error) { group, err := parseID(gid) if err != nil { return nil, nil, err } u := fmt.Sprintf("groups/%s/epics/%d/resource_label_events/%d", pathEscape(group), epic, event) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } l := new(LabelEvent) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } // ListMergeLabelEvents retrieves resource label events for the specified // project and merge request. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#list-project-merge-request-label-events func (s *ResourceLabelEventsService) ListMergeLabelEvents(pid interface{}, request int, opt *ListLabelEventsOptions, options ...OptionFunc) ([]*LabelEvent, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/resource_label_events", pathEscape(project), request) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ls []*LabelEvent resp, err := s.client.Do(req, &ls) if err != nil { return nil, resp, err } return ls, resp, err } // GetMergeRequestLabelEvent gets a single merge request label event. // // GitLab API docs: // https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-merge-request-label-event func (s *ResourceLabelEventsService) GetMergeRequestLabelEvent(pid interface{}, request int, event int, options ...OptionFunc) (*LabelEvent, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/merge_requests/%d/resource_label_events/%d", pathEscape(project), request, event) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } l := new(LabelEvent) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, err } golang-github-xanzy-go-gitlab-0.22.2/runners.go000066400000000000000000000315021357140411500213630ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // RunnersService handles communication with the runner related methods of the // GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/runners.html type RunnersService struct { client *Client } // Runner represents a GitLab CI Runner. // // GitLab API docs: https://docs.gitlab.com/ce/api/runners.html type Runner struct { ID int `json:"id"` Description string `json:"description"` Active bool `json:"active"` IsShared bool `json:"is_shared"` IPAddress string `json:"ip_address"` Name string `json:"name"` Online bool `json:"online"` Status string `json:"status"` Token string `json:"token"` } // RunnerDetails represents the GitLab CI runner details. // // GitLab API docs: https://docs.gitlab.com/ce/api/runners.html type RunnerDetails struct { Active bool `json:"active"` Architecture string `json:"architecture"` Description string `json:"description"` ID int `json:"id"` IPAddress string `json:"ip_address"` IsShared bool `json:"is_shared"` ContactedAt *time.Time `json:"contacted_at"` Name string `json:"name"` Online bool `json:"online"` Status string `json:"status"` Platform string `json:"platform"` Projects []struct { ID int `json:"id"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` } `json:"projects"` Token string `json:"token"` Revision string `json:"revision"` TagList []string `json:"tag_list"` Version string `json:"version"` Locked bool `json:"locked"` AccessLevel string `json:"access_level"` MaximumTimeout int `json:"maximum_timeout"` Groups []struct { ID int `json:"id"` Name string `json:"name"` WebURL string `json:"web_url"` } `json:"groups"` } // ListRunnersOptions represents the available ListRunners() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#list-owned-runners type ListRunnersOptions struct { ListOptions Scope *string `url:"scope,omitempty" json:"scope,omitempty"` Type *string `url:"type,omitempty" json:"type,omitempty"` Status *string `url:"status,omitempty" json:"status,omitempty"` TagList []string `url:"tag_list,comma,omitempty" json:"tag_list,omitempty"` } // ListRunners gets a list of runners accessible by the authenticated user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#list-owned-runners func (s *RunnersService) ListRunners(opt *ListRunnersOptions, options ...OptionFunc) ([]*Runner, *Response, error) { req, err := s.client.NewRequest("GET", "runners", opt, options) if err != nil { return nil, nil, err } var rs []*Runner resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err } return rs, resp, err } // ListAllRunners gets a list of all runners in the GitLab instance. Access is // restricted to users with admin privileges. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#list-all-runners func (s *RunnersService) ListAllRunners(opt *ListRunnersOptions, options ...OptionFunc) ([]*Runner, *Response, error) { req, err := s.client.NewRequest("GET", "runners/all", opt, options) if err != nil { return nil, nil, err } var rs []*Runner resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err } return rs, resp, err } // GetRunnerDetails returns details for given runner. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#get-runner-39-s-details func (s *RunnersService) GetRunnerDetails(rid interface{}, options ...OptionFunc) (*RunnerDetails, *Response, error) { runner, err := parseID(rid) if err != nil { return nil, nil, err } u := fmt.Sprintf("runners/%s", runner) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var rs *RunnerDetails resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err } return rs, resp, err } // UpdateRunnerDetailsOptions represents the available UpdateRunnerDetails() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details type UpdateRunnerDetailsOptions struct { Description *string `url:"description,omitempty" json:"description,omitempty"` Active *bool `url:"active,omitempty" json:"active,omitempty"` TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"` RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"` Locked *bool `url:"locked,omitempty" json:"locked,omitempty"` AccessLevel *string `url:"access_level,omitempty" json:"access_level,omitempty"` MaximumTimeout *int `url:"maximum_timeout,omitempty" json:"maximum_timeout,omitempty"` } // UpdateRunnerDetails updates details for a given runner. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details func (s *RunnersService) UpdateRunnerDetails(rid interface{}, opt *UpdateRunnerDetailsOptions, options ...OptionFunc) (*RunnerDetails, *Response, error) { runner, err := parseID(rid) if err != nil { return nil, nil, err } u := fmt.Sprintf("runners/%s", runner) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } var rs *RunnerDetails resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err } return rs, resp, err } // RemoveRunner removes a runner. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#remove-a-runner func (s *RunnersService) RemoveRunner(rid interface{}, options ...OptionFunc) (*Response, error) { runner, err := parseID(rid) if err != nil { return nil, err } u := fmt.Sprintf("runners/%s", runner) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ListRunnerJobsOptions represents the available ListRunnerJobs() // options. Status can be one of: running, success, failed, canceled. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#list-runners-jobs type ListRunnerJobsOptions struct { ListOptions Status *string `url:"status,omitempty" json:"status,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListRunnerJobs gets a list of jobs that are being processed or were processed by specified Runner. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#list-runner-39-s-jobs func (s *RunnersService) ListRunnerJobs(rid interface{}, opt *ListRunnerJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) { runner, err := parseID(rid) if err != nil { return nil, nil, err } u := fmt.Sprintf("runners/%s/jobs", runner) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var rs []*Job resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err } return rs, resp, err } // ListProjectRunnersOptions represents the available ListProjectRunners() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#list-project-s-runners type ListProjectRunnersOptions ListRunnersOptions // ListProjectRunners gets a list of runners accessible by the authenticated user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#list-project-s-runners func (s *RunnersService) ListProjectRunners(pid interface{}, opt *ListProjectRunnersOptions, options ...OptionFunc) ([]*Runner, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/runners", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var rs []*Runner resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err } return rs, resp, err } // EnableProjectRunnerOptions represents the available EnableProjectRunner() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#enable-a-runner-in-project type EnableProjectRunnerOptions struct { RunnerID int `json:"runner_id"` } // EnableProjectRunner enables an available specific runner in the project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#enable-a-runner-in-project func (s *RunnersService) EnableProjectRunner(pid interface{}, opt *EnableProjectRunnerOptions, options ...OptionFunc) (*Runner, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/runners", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } var r *Runner resp, err := s.client.Do(req, &r) if err != nil { return nil, resp, err } return r, resp, err } // DisableProjectRunner disables a specific runner from project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#disable-a-runner-from-project func (s *RunnersService) DisableProjectRunner(pid interface{}, runner int, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/runners/%d", pathEscape(project), runner) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // RegisterNewRunnerOptions represents the available RegisterNewRunner() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#register-a-new-runner type RegisterNewRunnerOptions struct { Token *string `url:"token" json:"token"` Description *string `url:"description,omitempty" json:"description,omitempty"` Info *string `url:"info,omitempty" json:"info,omitempty"` Active *bool `url:"active,omitempty" json:"active,omitempty"` Locked *bool `url:"locked,omitempty" json:"locked,omitempty"` RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"` TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"` MaximumTimeout *int `url:"maximum_timeout,omitempty" json:"maximum_timeout,omitempty"` } // RegisterNewRunner registers a new Runner for the instance. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#register-a-new-runner func (s *RunnersService) RegisterNewRunner(opt *RegisterNewRunnerOptions, options ...OptionFunc) (*Runner, *Response, error) { req, err := s.client.NewRequest("POST", "runners", opt, options) if err != nil { return nil, nil, err } var r *Runner resp, err := s.client.Do(req, &r) if err != nil { return nil, resp, err } return r, resp, err } // DeleteRegisteredRunnerOptions represents the available // DeleteRegisteredRunner() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#delete-a-registered-runner type DeleteRegisteredRunnerOptions struct { Token *string `url:"token" json:"token"` } // DeleteRegisteredRunner registers a new Runner for the instance. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#delete-a-registered-runner func (s *RunnersService) DeleteRegisteredRunner(opt *DeleteRegisteredRunnerOptions, options ...OptionFunc) (*Response, error) { req, err := s.client.NewRequest("DELETE", "runners", opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // VerifyRegisteredRunnerOptions represents the available // VerifyRegisteredRunner() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#verify-authentication-for-a-registered-runner type VerifyRegisteredRunnerOptions struct { Token *string `url:"token" json:"token"` } // VerifyRegisteredRunner registers a new Runner for the instance. // // GitLab API docs: // https://docs.gitlab.com/ce/api/runners.html#verify-authentication-for-a-registered-runner func (s *RunnersService) VerifyRegisteredRunner(opt *VerifyRegisteredRunnerOptions, options ...OptionFunc) (*Response, error) { req, err := s.client.NewRequest("POST", "runners/verify", opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/runners_test.go000066400000000000000000000166011357140411500224250ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/http" "reflect" "testing" "time" ) func TestDisableRunner(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/runners/2", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusNoContent) }) _, err := client.Runners.DisableProjectRunner(1, 2, nil) if err != nil { t.Fatalf("Runners.DisableProjectRunner returns an error: %v", err) } } func TestListRunnersJobs(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/runners/1/jobs", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"id":1},{"id":2}]`) }) opt := &ListRunnerJobsOptions{} jobs, _, err := client.Runners.ListRunnerJobs(1, opt) if err != nil { t.Fatalf("Runners.ListRunnersJobs returns an error: %v", err) } want := []*Job{{ID: 1}, {ID: 2}} if !reflect.DeepEqual(want, jobs) { t.Errorf("Runners.ListRunnersJobs returned %+v, want %+v", jobs, want) } } func TestRemoveRunner(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/runners/1", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusNoContent) }) _, err := client.Runners.RemoveRunner(1, nil) if err != nil { t.Fatalf("Runners.RemoveARunner returns an error: %v", err) } } const exampleDetailRsp = `{ "active": true, "architecture": null, "description": "test-1-20150125-test", "id": 6, "is_shared": false, "contacted_at": "2016-01-25T16:39:48.066Z", "name": null, "online": true, "status": "online", "platform": null, "projects": [ { "id": 1, "name": "GitLab Community Edition", "name_with_namespace": "GitLab.org / GitLab Community Edition", "path": "gitlab-ce", "path_with_namespace": "gitlab-org/gitlab-ce" } ], "token": "205086a8e3b9a2b818ffac9b89d102", "revision": null, "tag_list": [ "ruby", "mysql" ], "version": null, "access_level": "ref_protected", "maximum_timeout": 3600, "locked": false }` func TestUpdateRunnersDetails(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/runners/6", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, exampleDetailRsp) }) opt := &UpdateRunnerDetailsOptions{} details, _, err := client.Runners.UpdateRunnerDetails(6, opt, nil) if err != nil { t.Fatalf("Runners.UpdateRunnersDetails returns an error: %v", err) } want := expectedParsedDetails() if !reflect.DeepEqual(want, details) { t.Errorf("Runners.UpdateRunnersDetails returned %+v, want %+v", details, want) } } func TestGetRunnerDetails(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/runners/6", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, exampleDetailRsp) }) details, _, err := client.Runners.GetRunnerDetails(6, nil) if err != nil { t.Fatalf("Runners.GetRunnerDetails returns an error: %v", err) } want := expectedParsedDetails() if !reflect.DeepEqual(want, details) { t.Errorf("Runners.UpdateRunnersDetails returned %+v, want %+v", details, want) } } // helper function returning expected result for string: &exampleDetailRsp func expectedParsedDetails() *RunnerDetails { proj := struct { ID int `json:"id"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` }{ID: 1, Name: "GitLab Community Edition", NameWithNamespace: "GitLab.org / GitLab Community Edition", Path: "gitlab-ce", PathWithNamespace: "gitlab-org/gitlab-ce"} timestamp, _ := time.Parse("2006-01-02T15:04:05.000Z", "2016-01-25T16:39:48.066Z") return &RunnerDetails{ Active: true, Description: "test-1-20150125-test", ID: 6, IsShared: false, ContactedAt: ×tamp, Online: true, Status: "online", Token: "205086a8e3b9a2b818ffac9b89d102", TagList: []string{"ruby", "mysql"}, AccessLevel: "ref_protected", Projects: []struct { ID int `json:"id"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` }{proj}, MaximumTimeout: 3600, Locked: false, } } // helper function returning expected result for string: &exampleRegisterNewRunner func expectedParsedNewRunner() *Runner { return &Runner{ ID: 12345, Token: "6337ff461c94fd3fa32ba3b1ff4125", } } const exampleRegisterNewRunner = `{ "id": 12345, "token": "6337ff461c94fd3fa32ba3b1ff4125" }` func TestRegisterNewRunner(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/runners", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusCreated) fmt.Fprint(w, exampleRegisterNewRunner) }) opt := &RegisterNewRunnerOptions{} runner, resp, err := client.Runners.RegisterNewRunner(opt, nil) if err != nil { t.Fatalf("Runners.RegisterNewRunner returns an error: %v", err) } want := expectedParsedNewRunner() if !reflect.DeepEqual(want, runner) { t.Errorf("Runners.RegisterNewRunner returned %+v, want %+v", runner, want) } wantCode := 201 if !reflect.DeepEqual(wantCode, resp.StatusCode) { t.Errorf("Runners.DeleteRegisteredRunner returned status code %+v, want %+v", resp.StatusCode, wantCode) } } func TestDeleteRegisteredRunner(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/runners", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") w.WriteHeader(http.StatusNoContent) }) opt := &DeleteRegisteredRunnerOptions{} resp, err := client.Runners.DeleteRegisteredRunner(opt, nil) if err != nil { t.Fatalf("Runners.DeleteRegisteredRunner returns an error: %v", err) } want := 204 if !reflect.DeepEqual(want, resp.StatusCode) { t.Errorf("Runners.DeleteRegisteredRunner returned returned status code %+v, want %+v", resp.StatusCode, want) } } func TestVerifyRegisteredRunner(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/runners/verify", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusOK) }) opt := &VerifyRegisteredRunnerOptions{} resp, err := client.Runners.VerifyRegisteredRunner(opt, nil) if err != nil { t.Fatalf("Runners.VerifyRegisteredRunner returns an error: %v", err) } want := 200 if !reflect.DeepEqual(want, resp.StatusCode) { t.Errorf("Runners.VerifyRegisteredRunner returned returned status code %+v, want %+v", resp.StatusCode, want) } } golang-github-xanzy-go-gitlab-0.22.2/search.go000066400000000000000000000322701357140411500211370ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" ) // SearchService handles communication with the search related methods of the // GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html type SearchService struct { client *Client } // SearchOptions represents the available options for all search methods. // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html type SearchOptions ListOptions type searchOptions struct { SearchOptions Scope string `url:"scope" json:"scope"` Search string `url:"search" json:"search"` } // Projects searches the expression within projects // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-projects func (s *SearchService) Projects(query string, opt *SearchOptions, options ...OptionFunc) ([]*Project, *Response, error) { var ps []*Project resp, err := s.search("projects", query, &ps, opt, options...) return ps, resp, err } // ProjectsByGroup searches the expression within projects for // the specified group // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#group-search-api func (s *SearchService) ProjectsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Project, *Response, error) { var ps []*Project resp, err := s.searchByGroup(gid, "projects", query, &ps, opt, options...) return ps, resp, err } // Issues searches the expression within issues // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues func (s *SearchService) Issues(query string, opt *SearchOptions, options ...OptionFunc) ([]*Issue, *Response, error) { var is []*Issue resp, err := s.search("issues", query, &is, opt, options...) return is, resp, err } // IssuesByGroup searches the expression within issues for // the specified group // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues func (s *SearchService) IssuesByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Issue, *Response, error) { var is []*Issue resp, err := s.searchByGroup(gid, "issues", query, &is, opt, options...) return is, resp, err } // IssuesByProject searches the expression within issues for // the specified project // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues func (s *SearchService) IssuesByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Issue, *Response, error) { var is []*Issue resp, err := s.searchByProject(pid, "issues", query, &is, opt, options...) return is, resp, err } // MergeRequests searches the expression within merge requests // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-merge_requests func (s *SearchService) MergeRequests(query string, opt *SearchOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { var ms []*MergeRequest resp, err := s.search("merge_requests", query, &ms, opt, options...) return ms, resp, err } // MergeRequestsByGroup searches the expression within merge requests for // the specified group // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-merge_requests func (s *SearchService) MergeRequestsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { var ms []*MergeRequest resp, err := s.searchByGroup(gid, "merge_requests", query, &ms, opt, options...) return ms, resp, err } // MergeRequestsByProject searches the expression within merge requests for // the specified project // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-merge_requests func (s *SearchService) MergeRequestsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { var ms []*MergeRequest resp, err := s.searchByProject(pid, "merge_requests", query, &ms, opt, options...) return ms, resp, err } // Milestones searches the expression within milestones // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones func (s *SearchService) Milestones(query string, opt *SearchOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { var ms []*Milestone resp, err := s.search("milestones", query, &ms, opt, options...) return ms, resp, err } // MilestonesByGroup searches the expression within milestones for // the specified group // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones func (s *SearchService) MilestonesByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { var ms []*Milestone resp, err := s.searchByGroup(gid, "milestones", query, &ms, opt, options...) return ms, resp, err } // MilestonesByProject searches the expression within milestones for // the specified project // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones func (s *SearchService) MilestonesByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { var ms []*Milestone resp, err := s.searchByProject(pid, "milestones", query, &ms, opt, options...) return ms, resp, err } // SnippetTitles searches the expression within snippet titles // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-snippet_titles func (s *SearchService) SnippetTitles(query string, opt *SearchOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { var ss []*Snippet resp, err := s.search("snippet_titles", query, &ss, opt, options...) return ss, resp, err } // SnippetBlobs searches the expression within snippet blobs // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-snippet_blobs func (s *SearchService) SnippetBlobs(query string, opt *SearchOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { var ss []*Snippet resp, err := s.search("snippet_blobs", query, &ss, opt, options...) return ss, resp, err } // NotesByProject searches the expression within notes for the specified // project // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-notes func (s *SearchService) NotesByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Note, *Response, error) { var ns []*Note resp, err := s.searchByProject(pid, "notes", query, &ns, opt, options...) return ns, resp, err } // WikiBlobs searches the expression within all wiki blobs // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs func (s *SearchService) WikiBlobs(query string, opt *SearchOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { var ws []*Wiki resp, err := s.search("wiki_blobs", query, &ws, opt, options...) return ws, resp, err } // WikiBlobsByGroup searches the expression within wiki blobs for // specified group // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs func (s *SearchService) WikiBlobsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { var ws []*Wiki resp, err := s.searchByGroup(gid, "wiki_blobs", query, &ws, opt, options...) return ws, resp, err } // WikiBlobsByProject searches the expression within wiki blobs for // the specified project // // GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs func (s *SearchService) WikiBlobsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { var ws []*Wiki resp, err := s.searchByProject(pid, "wiki_blobs", query, &ws, opt, options...) return ws, resp, err } // Commits searches the expression within all commits // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits func (s *SearchService) Commits(query string, opt *SearchOptions, options ...OptionFunc) ([]*Commit, *Response, error) { var cs []*Commit resp, err := s.search("commits", query, &cs, opt, options...) return cs, resp, err } // CommitsByGroup searches the expression within commits for the specified // group // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits func (s *SearchService) CommitsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Commit, *Response, error) { var cs []*Commit resp, err := s.searchByGroup(gid, "commits", query, &cs, opt, options...) return cs, resp, err } // CommitsByProject searches the expression within commits for the // specified project // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits func (s *SearchService) CommitsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Commit, *Response, error) { var cs []*Commit resp, err := s.searchByProject(pid, "commits", query, &cs, opt, options...) return cs, resp, err } // Blob represents a single blob. type Blob struct { Basename string `json:"basename"` Data string `json:"data"` Filename string `json:"filename"` ID int `json:"id"` Ref string `json:"ref"` Startline int `json:"startline"` ProjectID int `json:"project_id"` } // Blobs searches the expression within all blobs // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs func (s *SearchService) Blobs(query string, opt *SearchOptions, options ...OptionFunc) ([]*Blob, *Response, error) { var bs []*Blob resp, err := s.search("blobs", query, &bs, opt, options...) return bs, resp, err } // BlobsByGroup searches the expression within blobs for the specified // group // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs func (s *SearchService) BlobsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Blob, *Response, error) { var bs []*Blob resp, err := s.searchByGroup(gid, "blobs", query, &bs, opt, options...) return bs, resp, err } // BlobsByProject searches the expression within blobs for the specified // project // // GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs func (s *SearchService) BlobsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Blob, *Response, error) { var bs []*Blob resp, err := s.searchByProject(pid, "blobs", query, &bs, opt, options...) return bs, resp, err } // Users searches the expression within all users // // GitLab API docs: https://docs.gitlab.com/ee/api/search.html#scope-users func (s *SearchService) Users(query string, opt *SearchOptions, options ...OptionFunc) ([]*User, *Response, error) { var ret []*User resp, err := s.search("users", query, &ret, opt, options...) return ret, resp, err } // UsersByGroup searches the expression within users for the specified // group // // GitLab API docs: https://docs.gitlab.com/ee/api/search.html#scope-users-1 func (s *SearchService) UsersByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*User, *Response, error) { var ret []*User resp, err := s.searchByGroup(gid, "users", query, &ret, opt, options...) return ret, resp, err } // UsersByProject searches the expression within users for the // specified project // // GitLab API docs: https://docs.gitlab.com/ee/api/search.html#scope-users-2 func (s *SearchService) UsersByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*User, *Response, error) { var ret []*User resp, err := s.searchByProject(pid, "users", query, &ret, opt, options...) return ret, resp, err } func (s *SearchService) search(scope, query string, result interface{}, opt *SearchOptions, options ...OptionFunc) (*Response, error) { opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} req, err := s.client.NewRequest("GET", "search", opts, options) if err != nil { return nil, err } return s.client.Do(req, result) } func (s *SearchService) searchByGroup(gid interface{}, scope, query string, result interface{}, opt *SearchOptions, options ...OptionFunc) (*Response, error) { group, err := parseID(gid) if err != nil { return nil, err } u := fmt.Sprintf("groups/%s/-/search", pathEscape(group)) opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} req, err := s.client.NewRequest("GET", u, opts, options) if err != nil { return nil, err } return s.client.Do(req, result) } func (s *SearchService) searchByProject(pid interface{}, scope, query string, result interface{}, opt *SearchOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/-/search", pathEscape(project)) opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} req, err := s.client.NewRequest("GET", u, opts, options) if err != nil { return nil, err } return s.client.Do(req, result) } golang-github-xanzy-go-gitlab-0.22.2/search_test.go000066400000000000000000000037731357140411500222040ustar00rootroot00000000000000package gitlab import ( "net/http" "testing" "github.com/stretchr/testify/require" ) func TestSearchService_Users(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/search", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/search_users.json") }) opts := &SearchOptions{PerPage: 2} users, _, err := client.Search.Users("doe", opts) require.NoError(t, err) want := []*User{{ ID: 1, Username: "user1", Name: "John Doe1", State: "active", AvatarURL: "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", }} require.Equal(t, want, users) } func TestSearchService_UsersByGroup(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/groups/3/-/search", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/search_users.json") }) opts := &SearchOptions{PerPage: 2} users, _, err := client.Search.UsersByGroup("3", "doe", opts) require.NoError(t, err) want := []*User{{ ID: 1, Username: "user1", Name: "John Doe1", State: "active", AvatarURL: "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", }} require.Equal(t, want, users) } func TestSearchService_UsersByProject(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/6/-/search", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/search_users.json") }) opts := &SearchOptions{PerPage: 2} users, _, err := client.Search.UsersByProject("6", "doe", opts) require.NoError(t, err) want := []*User{{ ID: 1, Username: "user1", Name: "John Doe1", State: "active", AvatarURL: "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", }} require.Equal(t, want, users) } golang-github-xanzy-go-gitlab-0.22.2/services.go000066400000000000000000000707221357140411500215210ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "encoding/json" "fmt" "strconv" "time" ) // ServicesService handles communication with the services related methods of // the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/services.html type ServicesService struct { client *Client } // Service represents a GitLab service. // // GitLab API docs: https://docs.gitlab.com/ce/api/services.html type Service struct { ID int `json:"id"` Title string `json:"title"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` Active bool `json:"active"` PushEvents bool `json:"push_events"` IssuesEvents bool `json:"issues_events"` ConfidentialIssuesEvents bool `json:"confidential_issues_events"` MergeRequestsEvents bool `json:"merge_requests_events"` TagPushEvents bool `json:"tag_push_events"` NoteEvents bool `json:"note_events"` ConfidentialNoteEvents bool `json:"confidential_note_events"` PipelineEvents bool `json:"pipeline_events"` JobEvents bool `json:"job_events"` WikiPageEvents bool `json:"wiki_page_events"` } // SetGitLabCIServiceOptions represents the available SetGitLabCIService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service type SetGitLabCIServiceOptions struct { Token *string `url:"token,omitempty" json:"token,omitempty"` ProjectURL *string `url:"project_url,omitempty" json:"project_url,omitempty"` } // SetGitLabCIService sets GitLab CI service for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service func (s *ServicesService) SetGitLabCIService(pid interface{}, opt *SetGitLabCIServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteGitLabCIService deletes GitLab CI service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-gitlab-ci-service func (s *ServicesService) DeleteGitLabCIService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // GithubService represents Github service settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#github-premium type GithubService struct { Service Properties *GithubServiceProperties `json:"properties"` } // GithubServiceProperties represents Github specific properties. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#github-premium type GithubServiceProperties struct { RepositoryURL string `json:"repository_url,omitempty"` StaticContext string `json:"static_context,omitempty"` } // GetGithubService gets Github service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#get-github-service-settings func (s *ServicesService) GetGithubService(pid interface{}, options ...OptionFunc) (*GithubService, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/services/github", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } svc := new(GithubService) resp, err := s.client.Do(req, svc) if err != nil { return nil, resp, err } return svc, resp, err } // SetGithubServiceOptions represents the available SetGithubService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#createedit-github-service type SetGithubServiceOptions struct { Token *string `url:"token,omitempty" json:"token,omitempty"` RepositoryURL *string `url:"repository_url,omitempty" json:"repository_url,omitempty"` StaticContext *bool `url:"static_context,omitempty" json:"static_context,omitempty"` } // SetGithubService sets Github service for a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#createedit-github-service func (s *ServicesService) SetGithubService(pid interface{}, opt *SetGithubServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/github", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteGithubService deletes Github service for a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-github-service func (s *ServicesService) DeleteGithubService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/github", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // SetHipChatServiceOptions represents the available SetHipChatService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service type SetHipChatServiceOptions struct { Token *string `url:"token,omitempty" json:"token,omitempty" ` Room *string `url:"room,omitempty" json:"room,omitempty"` } // SetHipChatService sets HipChat service for a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service func (s *ServicesService) SetHipChatService(pid interface{}, opt *SetHipChatServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteHipChatService deletes HipChat service for project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-hipchat-service func (s *ServicesService) DeleteHipChatService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DroneCIService represents Drone CI service settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#drone-ci type DroneCIService struct { Service Properties *DroneCIServiceProperties `json:"properties"` } // DroneCIServiceProperties represents Drone CI specific properties. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#drone-ci type DroneCIServiceProperties struct { Token string `json:"token"` DroneURL string `json:"drone_url"` EnableSSLVerification bool `json:"enable_ssl_verification"` } // GetDroneCIService gets Drone CI service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#get-drone-ci-service-settings func (s *ServicesService) GetDroneCIService(pid interface{}, options ...OptionFunc) (*DroneCIService, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } svc := new(DroneCIService) resp, err := s.client.Do(req, svc) if err != nil { return nil, resp, err } return svc, resp, err } // SetDroneCIServiceOptions represents the available SetDroneCIService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service type SetDroneCIServiceOptions struct { Token *string `url:"token" json:"token" ` DroneURL *string `url:"drone_url" json:"drone_url"` EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` } // SetDroneCIService sets Drone CI service for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service func (s *ServicesService) SetDroneCIService(pid interface{}, opt *SetDroneCIServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteDroneCIService deletes Drone CI service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-drone-ci-service func (s *ServicesService) DeleteDroneCIService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // SlackService represents Slack service settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#slack type SlackService struct { Service Properties *SlackServiceProperties `json:"properties"` } // SlackServiceProperties represents Slack specific properties. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#slack type SlackServiceProperties struct { WebHook string `json:"webhook,omitempty"` Username string `json:"username,omitempty"` Channel string `json:"channel,omitempty"` NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines,omitempty"` NotifyOnlyDefaultBranch BoolValue `json:"notify_only_default_branch,omitempty"` BranchesToBeNotified string `json:"branches_to_be_notified,omitempty"` ConfidentialIssueChannel string `json:"confidential_issue_channel,omitempty"` ConfidentialNoteChannel string `json:"confidential_note_channel,omitempty"` DeploymentChannel string `json:"deployment_channel,omitempty"` IssueChannel string `json:"issue_channel,omitempty"` MergeRequestChannel string `json:"merge_request_channel,omitempty"` NoteChannel string `json:"note_channel,omitempty"` TagPushChannel string `json:"tag_push_channel,omitempty"` PipelineChannel string `json:"pipeline_channel,omitempty"` PushChannel string `json:"push_channel,omitempty"` WikiPageChannel string `json:"wiki_page_channel,omitempty"` } // GetSlackService gets Slack service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#get-slack-service-settings func (s *ServicesService) GetSlackService(pid interface{}, options ...OptionFunc) (*SlackService, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } svc := new(SlackService) resp, err := s.client.Do(req, svc) if err != nil { return nil, resp, err } return svc, resp, err } // SetSlackServiceOptions represents the available SetSlackService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-slack-service type SetSlackServiceOptions struct { WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"` Username *string `url:"username,omitempty" json:"username,omitempty"` Channel *string `url:"channel,omitempty" json:"channel,omitempty"` NotifyOnlyBrokenPipelines *bool `url:"notify_only_broken_pipelines,omitempty" json:"notify_only_broken_pipelines,omitempty"` NotifyOnlyDefaultBranch *bool `url:"notify_only_default_branch,omitempty" json:"notify_only_default_branch,omitempty"` BranchesToBeNotified *string `url:"branches_to_be_notified,omitempty" json:"branches_to_be_notified,omitempty"` ConfidentialIssueChannel *string `url:"confidential_issue_channel,omitempty" json:"confidential_issue_channel,omitempty"` ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` // TODO: Currently, GitLab ignores this option (not implemented yet?), so // there is no way to set it. Uncomment when this is fixed. // See: https://gitlab.com/gitlab-org/gitlab-ce/issues/49730 //ConfidentialNoteChannel *string `json:"confidential_note_channel,omitempty"` ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` DeploymentChannel *string `url:"deployment_channel,omitempty" json:"deployment_channel,omitempty"` DeploymentEvents *bool `url:"deployment_events,omitempty" json:"deployment_events,omitempty"` IssueChannel *string `url:"issue_channel,omitempty" json:"issue_channel,omitempty"` IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` MergeRequestChannel *string `url:"merge_request_channel,omitempty" json:"merge_request_channel,omitempty"` MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` TagPushChannel *string `url:"tag_push_channel,omitempty" json:"tag_push_channel,omitempty"` TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` NoteChannel *string `url:"note_channel,omitempty" json:"note_channel,omitempty"` NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` PipelineChannel *string `url:"pipeline_channel,omitempty" json:"pipeline_channel,omitempty"` PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` PushChannel *string `url:"push_channel,omitempty" json:"push_channel,omitempty"` PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` WikiPageChannel *string `url:"wiki_page_channel,omitempty" json:"wiki_page_channel,omitempty"` WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` } // SetSlackService sets Slack service for a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-slack-service func (s *ServicesService) SetSlackService(pid interface{}, opt *SetSlackServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteSlackService deletes Slack service for project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-slack-service func (s *ServicesService) DeleteSlackService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // JiraService represents Jira service settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#jira type JiraService struct { Service Properties *JiraServiceProperties `json:"properties"` } // JiraServiceProperties represents Jira specific properties. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#jira type JiraServiceProperties struct { URL string `json:"url,omitempty"` APIURL string `json:"api_url,omitempty"` ProjectKey string `json:"project_key,omitempty" ` Username string `json:"username,omitempty" ` Password string `json:"password,omitempty" ` JiraIssueTransitionID string `json:"jira_issue_transition_id,omitempty"` } // UnmarshalJSON decodes the Jira Service Properties. // // This allows support of JiraIssueTransitionID for both type string (>11.9) and float64 (<11.9) func (p *JiraServiceProperties) UnmarshalJSON(b []byte) error { type Alias JiraServiceProperties raw := struct { *Alias JiraIssueTransitionID interface{} `json:"jira_issue_transition_id"` }{ Alias: (*Alias)(p), } if err := json.Unmarshal(b, &raw); err != nil { return err } switch id := raw.JiraIssueTransitionID.(type) { case nil: // No action needed. case string: p.JiraIssueTransitionID = id case float64: p.JiraIssueTransitionID = strconv.Itoa(int(id)) default: return fmt.Errorf("failed to unmarshal JiraTransitionID of type: %T", id) } return nil } // GetJiraService gets Jira service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#get-jira-service-settings func (s *ServicesService) GetJiraService(pid interface{}, options ...OptionFunc) (*JiraService, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } svc := new(JiraService) resp, err := s.client.Do(req, svc) if err != nil { return nil, resp, err } return svc, resp, err } // SetJiraServiceOptions represents the available SetJiraService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-jira-service type SetJiraServiceOptions struct { URL *string `url:"url,omitempty" json:"url,omitempty"` APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` ProjectKey *string `url:"project_key,omitempty" json:"project_key,omitempty" ` Username *string `url:"username,omitempty" json:"username,omitempty" ` Password *string `url:"password,omitempty" json:"password,omitempty" ` JiraIssueTransitionID *string `url:"jira_issue_transition_id,omitempty" json:"jira_issue_transition_id,omitempty"` } // SetJiraService sets Jira service for a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#edit-jira-service func (s *ServicesService) SetJiraService(pid interface{}, opt *SetJiraServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteJiraService deletes Jira service for project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-jira-service func (s *ServicesService) DeleteJiraService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // JenkinsCIService represents Jenkins CI service settings. // // GitLab API docs: // https://docs.gitlab.com/ee/api/services.html#jenkins-ci type JenkinsCIService struct { Service Properties *JenkinsCIServiceProperties `json:"properties"` } // JenkinsCIServiceProperties represents Jenkins CI specific properties. // // GitLab API docs: // https://docs.gitlab.com/ee/api/services.html#jenkins-ci type JenkinsCIServiceProperties struct { URL string `json:"jenkins_url,omitempty"` ProjectName string `json:"project_name,omitempty"` Username string `json:"username,omitempty"` } // GetJenkinsCIService gets Jenkins CI service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ee/api/services.html#get-jenkins-ci-service-settings func (s *ServicesService) GetJenkinsCIService(pid interface{}, options ...OptionFunc) (*JenkinsCIService, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } svc := new(JenkinsCIService) resp, err := s.client.Do(req, svc) if err != nil { return nil, resp, err } return svc, resp, err } // SetJenkinsCIServiceOptions represents the available SetJenkinsCIService() // options. // // GitLab API docs: // https://docs.gitlab.com/ee/api/services.html#jenkins-ci type SetJenkinsCIServiceOptions struct { URL *string `url:"jenkins_url,omitempty" json:"jenkins_url,omitempty"` ProjectName *string `url:"project_name,omitempty" json:"project_name,omitempty"` Username *string `url:"username,omitempty" json:"username,omitempty"` Password *string `url:"password,omitempty" json:"password,omitempty"` } // SetJenkinsCIService sets Jenkins service for a project // // GitLab API docs: // https://docs.gitlab.com/ee/api/services.html#create-edit-jenkins-ci-service func (s *ServicesService) SetJenkinsCIService(pid interface{}, opt *SetJenkinsCIServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteJenkinsCIService deletes Jenkins CI service for project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-jira-service func (s *ServicesService) DeleteJenkinsCIService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // MicrosoftTeamsService represents Microsoft Teams service settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#microsoft-teams type MicrosoftTeamsService struct { Service Properties *MicrosoftTeamsServiceProperties `json:"properties"` } // MicrosoftTeamsServiceProperties represents Microsoft Teams specific properties. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#microsoft-teams type MicrosoftTeamsServiceProperties struct { WebHook string `json:"webhook"` } // GetMicrosoftTeamsService gets MicrosoftTeams service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#get-microsoft-teams-service-settings func (s *ServicesService) GetMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*MicrosoftTeamsService, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } svc := new(MicrosoftTeamsService) resp, err := s.client.Do(req, svc) if err != nil { return nil, resp, err } return svc, resp, err } // SetMicrosoftTeamsServiceOptions represents the available SetMicrosoftTeamsService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service type SetMicrosoftTeamsServiceOptions struct { WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"` } // SetMicrosoftTeamsService sets Microsoft Teams service for a project // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service func (s *ServicesService) SetMicrosoftTeamsService(pid interface{}, opt *SetMicrosoftTeamsServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteMicrosoftTeamsService deletes Microsoft Teams service for project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-microsoft-teams-service func (s *ServicesService) DeleteMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ExternalWikiService represents External Wiki service settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#external-wiki type ExternalWikiService struct { Service Properties *ExternalWikiServiceProperties `json:"properties"` } // ExternalWikiServiceProperties represents External Wiki specific properties. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#external-wiki type ExternalWikiServiceProperties struct { ExternalWikiURL string `json:"external_wiki_url"` } // GetExternalWikiService gets External Wiki service settings for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#get-external-wiki-service-settings func (s *ServicesService) GetExternalWikiService(pid interface{}, options ...OptionFunc) (*ExternalWikiService, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } svc := new(ExternalWikiService) resp, err := s.client.Do(req, svc) if err != nil { return nil, resp, err } return svc, resp, err } // SetExternalWikiServiceOptions represents the available SetExternalWikiService() // options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#createedit-external-wiki-service type SetExternalWikiServiceOptions struct { ExternalWikiURL *string `url:"external_wiki_url,omitempty" json:"external_wiki_url,omitempty"` } // SetExternalWikiService sets External Wiki service for a project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#createedit-external-wiki-service func (s *ServicesService) SetExternalWikiService(pid interface{}, opt *SetExternalWikiServiceOptions, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteExternalWikiService deletes External Wiki service for project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#delete-external-wiki-service func (s *ServicesService) DeleteExternalWikiService(pid interface{}, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/services_test.go000066400000000000000000000130751357140411500225560ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestGetDroneCIService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/drone-ci", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1}`) }) want := &DroneCIService{Service: Service{ID: 1}} service, _, err := client.Services.GetDroneCIService(1) if err != nil { t.Fatalf("Services.GetDroneCIService returns an error: %v", err) } if !reflect.DeepEqual(want, service) { t.Errorf("Services.GetDroneCIService returned %+v, want %+v", service, want) } } func TestSetDroneCIService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/drone-ci", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") }) opt := &SetDroneCIServiceOptions{String("t"), String("u"), Bool(true)} _, err := client.Services.SetDroneCIService(1, opt) if err != nil { t.Fatalf("Services.SetDroneCIService returns an error: %v", err) } } func TestDeleteDroneCIService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/drone-ci", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) _, err := client.Services.DeleteDroneCIService(1) if err != nil { t.Fatalf("Services.DeleteDroneCIService returns an error: %v", err) } } func TestGetSlackService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/slack", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1}`) }) want := &SlackService{Service: Service{ID: 1}} service, _, err := client.Services.GetSlackService(1) if err != nil { t.Fatalf("Services.GetSlackService returns an error: %v", err) } if !reflect.DeepEqual(want, service) { t.Errorf("Services.GetSlackService returned %+v, want %+v", service, want) } } func TestSetSlackService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/slack", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") }) opt := &SetSlackServiceOptions{ WebHook: String("webhook_uri"), Username: String("username"), Channel: String("#development"), } _, err := client.Services.SetSlackService(1, opt) if err != nil { t.Fatalf("Services.SetSlackService returns an error: %v", err) } } func TestDeleteSlackService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/slack", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) _, err := client.Services.DeleteSlackService(1) if err != nil { t.Fatalf("Services.DeleteSlackService returns an error: %v", err) } } func TestGetJiraService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/0/services/jira", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1, "properties": {"jira_issue_transition_id": "2"}}`) }) mux.HandleFunc("/api/v4/projects/1/services/jira", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1, "properties": {"jira_issue_transition_id": 2}}`) }) mux.HandleFunc("/api/v4/projects/2/services/jira", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1, "properties": {"jira_issue_transition_id": "2,3"}}`) }) mux.HandleFunc("/api/v4/projects/3/services/jira", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1, "properties": {}}`) }) want := []*JiraService{ &JiraService{ Service: Service{ID: 1}, Properties: &JiraServiceProperties{ JiraIssueTransitionID: "2", }, }, &JiraService{ Service: Service{ID: 1}, Properties: &JiraServiceProperties{ JiraIssueTransitionID: "2", }, }, &JiraService{ Service: Service{ID: 1}, Properties: &JiraServiceProperties{ JiraIssueTransitionID: "2,3", }, }, &JiraService{ Service: Service{ID: 1}, Properties: &JiraServiceProperties{}, }, } for testcase := 0; testcase < len(want); testcase++ { service, _, err := client.Services.GetJiraService(testcase) if err != nil { t.Fatalf("Services.GetJiraService returns an error: %v", err) } if !reflect.DeepEqual(want[testcase], service) { t.Errorf("Services.GetJiraService returned %+v, want %+v", service, want[testcase]) } } } func TestSetJiraService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/jira", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") }) opt := &SetJiraServiceOptions{ URL: String("asd"), APIURL: String("asd"), ProjectKey: String("as"), Username: String("aas"), Password: String("asd"), JiraIssueTransitionID: String("2,3"), } _, err := client.Services.SetJiraService(1, opt) if err != nil { t.Fatalf("Services.SetJiraService returns an error: %v", err) } } func TestDeleteJiraService(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/services/jira", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) _, err := client.Services.DeleteJiraService(1) if err != nil { t.Fatalf("Services.DeleteJiraService returns an error: %v", err) } } golang-github-xanzy-go-gitlab-0.22.2/settings.go000066400000000000000000001212101357140411500215230ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import "time" // SettingsService handles communication with the application SettingsService // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/settings.html type SettingsService struct { client *Client } // Settings represents the GitLab application settings. // // GitLab API docs: https://docs.gitlab.com/ce/api/settings.html type Settings struct { ID int `json:"id"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` AdminNotificationEmail string `json:"admin_notification_email"` AfterSignOutPath string `json:"after_sign_out_path"` AfterSignUpText string `json:"after_sign_up_text"` AkismetAPIKey string `json:"akismet_api_key"` AkismetEnabled bool `json:"akismet_enabled"` AllowGroupOwnersToManageLDAP bool `json:"allow_group_owners_to_manage_ldap"` AllowLocalRequestsFromHooksAndServices bool `json:"allow_local_requests_from_hooks_and_services"` AllowLocalRequestsFromSystemHooks bool `json:"allow_local_requests_from_system_hooks"` AllowLocalRequestsFromWebHooksAndServices bool `json:"allow_local_requests_from_web_hooks_and_services"` ArchiveBuildsInHumanReadable string `json:"archive_builds_in_human_readable"` AssetProxyEnabled bool `json:"asset_proxy_enabled"` AssetProxySecretKey string `json:"asset_proxy_secret_key"` AssetProxyURL string `json:"asset_proxy_url"` AssetProxyWhitelist []string `json:"asset_proxy_whitelist"` AuthorizedKeysEnabled bool `json:"authorized_keys_enabled_enabled"` AutoDevOpsDomain string `json:"auto_devops_domain"` AutoDevOpsEnabled bool `json:"auto_devops_enabled"` CheckNamespacePlan bool `json:"check_namespace_plan"` CommitEmailHostname string `json:"commit_email_hostname"` ContainerRegistryTokenExpireDelay int `json:"container_registry_token_expire_delay"` DefaultArtifactsExpireIn string `json:"default_artifacts_expire_in"` DefaultBranchProtection int `json:"default_branch_protection"` DefaultGroupVisibility *VisibilityValue `json:"default_group_visibility"` DefaultProjectCreation int `json:"default_project_creation"` DefaultProjectsLimit int `json:"default_projects_limit"` DefaultProjectVisibility *VisibilityValue `json:"default_project_visibility"` DefaultSnippetVisibility *VisibilityValue `json:"default_snippet_visibility"` DiffMaxPatchBytes int `json:"diff_max_patch_bytes"` DisabledOauthSignInSources []string `json:"disabled_oauth_sign_in_sources"` DNSRebindingProtectionEnabled bool `json:"dns_rebinding_protection_enabled"` DomainBlacklist []string `json:"domain_blacklist"` DomainBlacklistEnabled bool `json:"domain_blacklist_enabled"` DomainWhitelist []string `json:"domain_whitelist"` DSAKeyRestriction int `json:"dsa_key_restriction"` ECDSAKeyRestriction int `json:"ecdsa_key_restriction"` Ed25519KeyRestriction int `json:"ed25519_key_restriction"` ElasticsearchAWSAccessKey string `json:"elasticsearch_aws_access_key"` ElasticsearchAWS bool `json:"elasticsearch_aws"` ElasticsearchAWSRegion string `json:"elasticsearch_aws_region"` ElasticsearchAWSSecretAccessKey string `json:"elasticsearch_aws_secret_access_key"` ElasticsearchIndexing bool `json:"elasticsearch_indexing"` ElasticsearchLimitIndexing bool `json:"elasticsearch_limit_indexing"` ElasticsearchNamespaceIDs []int `json:"elasticsearch_namespace_ids"` ElasticsearchProjectIDs []int `json:"elasticsearch_project_ids"` ElasticsearchSearch bool `json:"elasticsearch_search"` ElasticsearchURL []string `json:"elasticsearch_url"` EmailAdditionalText string `json:"email_additional_text"` EmailAuthorInBody bool `json:"email_author_in_body"` EnabledGitAccessProtocol string `json:"enabled_git_access_protocol"` EnforceTerms bool `json:"enforce_terms"` ExternalAuthClientCert string `json:"external_auth_client_cert"` ExternalAuthClientKeyPass string `json:"external_auth_client_key_pass"` ExternalAuthClientKey string `json:"external_auth_client_key"` ExternalAuthorizationServiceDefaultLabel string `json:"external_authorization_service_default_label"` ExternalAuthorizationServiceEnabled bool `json:"external_authorization_service_enabled"` ExternalAuthorizationServiceTimeout float64 `json:"external_authorization_service_timeout"` ExternalAuthorizationServiceURL string `json:"external_authorization_service_url"` FileTemplateProjectID int `json:"file_template_project_id"` FirstDayOfWeek int `json:"first_day_of_week"` GeoNodeAllowedIPs string `json:"geo_node_allowed_ips"` GeoStatusTimeout int `json:"geo_status_timeout"` GitalyTimeoutDefault int `json:"gitaly_timeout_default"` GitalyTimeoutFast int `json:"gitaly_timeout_fast"` GitalyTimeoutMedium int `json:"gitaly_timeout_medium"` GrafanaEnabled bool `json:"grafana_enabled"` GrafanaURL string `json:"grafana_url"` GravatarEnabled bool `json:"gravatar_enabled"` HashedStorageEnabled bool `json:"hashed_storage_enabled"` HelpPageHideCommercialContent bool `json:"help_page_hide_commercial_content"` HelpPageSupportURL string `json:"help_page_support_url"` HelpPageText string `json:"help_page_text"` HelpText string `json:"help_text"` HideThirdPartyOffers bool `json:"hide_third_party_offers"` HomePageURL string `json:"home_page_url"` HousekeepingBitmapsEnabled bool `json:"housekeeping_bitmaps_enabled"` HousekeepingEnabled bool `json:"housekeeping_enabled"` HousekeepingFullRepackPeriod int `json:"housekeeping_full_repack_period"` HousekeepingGcPeriod int `json:"housekeeping_gc_period"` HousekeepingIncrementalRepackPeriod int `json:"housekeeping_incremental_repack_period"` HTMLEmailsEnabled bool `json:"html_emails_enabled"` ImportSources []string `json:"import_sources"` InstanceStatisticsVisibilityPrivate bool `json:"instance_statistics_visibility_private"` LocalMarkdownVersion int `json:"local_markdown_version"` MaxArtifactsSize int `json:"max_artifacts_size"` MaxAttachmentSize int `json:"max_attachment_size"` MaxPagesSize int `json:"max_pages_size"` MetricsEnabled bool `json:"metrics_enabled"` MetricsHost string `json:"metrics_host"` MetricsMethodCallThreshold int `json:"metrics_method_call_threshold"` MetricsPacketSize int `json:"metrics_packet_size"` MetricsPoolSize int `json:"metrics_pool_size"` MetricsPort int `json:"metrics_port"` MetricsSampleInterval int `json:"metrics_sample_interval"` MetricsTimeout int `json:"metrics_timeout"` MirrorAvailable bool `json:"mirror_available"` MirrorCapacityThreshold int `json:"mirror_capacity_threshold"` MirrorMaxCapacity int `json:"mirror_max_capacity"` MirrorMaxDelay int `json:"mirror_max_delay"` OutboundLocalRequestsWhitelist []string `json:"outbound_local_requests_whitelist"` PagesDomainVerificationEnabled bool `json:"pages_domain_verification_enabled"` PasswordAuthenticationEnabledForGit bool `json:"password_authentication_enabled_for_git"` PasswordAuthenticationEnabledForWeb bool `json:"password_authentication_enabled_for_web"` PerformanceBarAllowedGroupID string `json:"performance_bar_allowed_group_id"` PerformanceBarAllowedGroupPath string `json:"performance_bar_allowed_group_path"` PerformanceBarEnabled bool `json:"performance_bar_enabled"` PlantumlEnabled bool `json:"plantuml_enabled"` PlantumlURL string `json:"plantuml_url"` PollingIntervalMultiplier float64 `json:"polling_interval_multiplier,string"` ProjectExportEnabled bool `json:"project_export_enabled"` PrometheusMetricsEnabled bool `json:"prometheus_metrics_enabled"` ProtectedCIVariables bool `json:"protected_ci_variables"` PseudonymizerEnabled bool `json:"psedonymizer_enabled"` PushEventHooksLimit int `json:"push_event_hooks_limit"` PushEventActivitiesLimit int `json:"push_event_activities_limit"` RecaptchaEnabled bool `json:"recaptcha_enabled"` RecaptchaPrivateKey string `json:"recaptcha_private_key"` RecaptchaSiteKey string `json:"recaptcha_site_key"` ReceiveMaxInputSize int `json:"receive_max_input_size"` RepositoryChecksEnabled bool `json:"repository_checks_enabled"` RepositorySizeLimit int `json:"repository_size_limit"` RepositoryStorages []string `json:"repository_storages"` RequireTwoFactorAuthentication bool `json:"require_two_factor_authentication"` RestrictedVisibilityLevels []VisibilityValue `json:"restricted_visibility_levels"` RsaKeyRestriction int `json:"rsa_key_restriction"` SendUserConfirmationEmail bool `json:"send_user_confirmation_email"` SessionExpireDelay int `json:"session_expire_delay"` SharedRunnersEnabled bool `json:"shared_runners_enabled"` SharedRunnersMinutes int `json:"shared_runners_minutes"` SharedRunnersText string `json:"shared_runners_text"` SignInText string `json:"sign_in_text"` SignupEnabled bool `json:"signup_enabled"` SlackAppEnabled bool `json:"slack_app_enabled"` SlackAppID string `json:"slack_app_id"` SlackAppSecret string `json:"slack_app_secret"` SlackAppVerificationToken string `json:"slack_app_verification_token"` SnowplowCollectorHostname string `json:"snowplow_collector_hostname"` SnowplowCookieDomain string `json:"snowplow_cookie_domain"` SnowplowEnabled bool `json:"snowplow_enabled"` SnowplowSiteID string `json:"snowplow_site_id"` TerminalMaxSessionTime int `json:"terminal_max_session_time"` Terms string `json:"terms"` ThrottleAuthenticatedAPIEnabled bool `json:"throttle_authenticated_api_enabled"` ThrottleAuthenticatedAPIPeriodInSeconds int `json:"throttle_authenticated_api_period_in_seconds"` ThrottleAuthenticatedAPIRequestsPerPeriod int `json:"throttle_authenticated_api_requests_per_period"` ThrottleAuthenticatedWebEnabled bool `json:"throttle_authenticated_web_enabled"` ThrottleAuthenticatedWebPeriodInSeconds int `json:"throttle_authenticated_web_period_in_seconds"` ThrottleAuthenticatedWebRequestsPerPeriod int `json:"throttle_authenticated_web_requests_per_period"` ThrottleUnauthenticatedEnabled bool `json:"throttle_unauthenticated_enabled"` ThrottleUnauthenticatedPeriodInSeconds int `json:"throttle_unauthenticated_period_in_seconds"` ThrottleUnauthenticatedRequestsPerPeriod int `json:"throttle_unauthenticated_requests_per_period"` TimeTrackingLimitToHours bool `json:"time_tracking_limit_to_hours"` TwoFactorGracePeriod int `json:"two_factor_grace_period"` UniqueIPsLimitEnabled bool `json:"unique_ips_limit_enabled"` UniqueIPsLimitPerUser int `json:"unique_ips_limit_per_user"` UniqueIPsLimitTimeWindow int `json:"unique_ips_limit_time_window"` UsagePingEnabled bool `json:"usage_ping_enabled"` UserDefaultExternal bool `json:"user_default_external"` UserDefaultInternalRegex string `json:"user_default_internal_regex"` UserOauthApplications bool `json:"user_oauth_applications"` UserShowAddSSHKeyMessage bool `json:"user_show_add_ssh_key_message"` VersionCheckEnabled bool `json:"version_check_enabled"` WebIDEClientsidePreviewEnabled bool `json:"web_ide_clientside_preview_enabled"` } func (s Settings) String() string { return Stringify(s) } // GetSettings gets the current application settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/settings.html#get-current-application.settings func (s *SettingsService) GetSettings(options ...OptionFunc) (*Settings, *Response, error) { req, err := s.client.NewRequest("GET", "application/settings", nil, options) if err != nil { return nil, nil, err } as := new(Settings) resp, err := s.client.Do(req, as) if err != nil { return nil, resp, err } return as, resp, err } // UpdateSettingsOptions represents the available UpdateSettings() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/settings.html#change-application.settings type UpdateSettingsOptions struct { AdminNotificationEmail *string `url:"admin_notification_email,omitempty" json:"admin_notification_email,omitempty"` AfterSignOutPath *string `url:"after_sign_out_path,omitempty" json:"after_sign_out_path,omitempty"` AfterSignUpText *string `url:"after_sign_up_text,omitempty" json:"after_sign_up_text,omitempty"` AkismetAPIKey *string `url:"akismet_api_key,omitempty" json:"akismet_api_key,omitempty"` AkismetEnabled *bool `url:"akismet_enabled,omitempty" json:"akismet_enabled,omitempty"` AllowGroupOwnersToManageLDAP *bool `url:"allow_group_owners_to_manage_ldap,omitempty" json:"allow_group_owners_to_manage_ldap,omitempty"` AllowLocalRequestsFromHooksAndServices *bool `url:"allow_local_requests_from_hooks_and_services,omitempty" json:"allow_local_requests_from_hooks_and_services,omitempty"` AllowLocalRequestsFromSystemHooks *bool `url:"allow_local_requests_from_system_hooks,omitempty" json:"allow_local_requests_from_system_hooks,omitempty"` AllowLocalRequestsFromWebHooksAndServices *bool `url:"allow_local_requests_from_web_hooks_and_services,omitempty" json:"allow_local_requests_from_web_hooks_and_services,omitempty"` ArchiveBuildsInHumanReadable *string `url:"archive_builds_in_human_readable,omitempty" json:"archive_builds_in_human_readable,omitempty"` AssetProxyEnabled *bool `url:"asset_proxy_enabled,omitempty" json:"asset_proxy_enabled,omitempty"` AssetProxySecretKey *string `url:"asset_proxy_secret_key,omitempty" json:"asset_proxy_secret_key,omitempty"` AssetProxyURL *string `url:"asset_proxy_url,omitempty" json:"asset_proxy_url,omitempty"` AssetProxyWhitelist []string `url:"asset_proxy_whitelist,omitempty" json:"asset_proxy_whitelist,omitempty"` AuthorizedKeysEnabled *bool `url:"authorized_keys_enabled,omitempty" json:"authorized_keys_enabled,omitempty"` AutoDevOpsDomain *string `url:"auto_devops_domain,omitempty" json:"auto_devops_domain,omitempty"` AutoDevOpsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"` CheckNamespacePlan *bool `url:"check_namespace_plan,omitempty" json:"check_namespace_plan,omitempty"` CommitEmailHostname *string `url:"commit_email_hostname,omitempty" json:"commit_email_hostname,omitempty"` ContainerRegistryTokenExpireDelay *int `url:"container_registry_token_expire_delay,omitempty" json:"container_registry_token_expire_delay,omitempty"` DefaultArtifactsExpireIn *string `url:"default_artifacts_expire_in,omitempty" json:"default_artifacts_expire_in,omitempty"` DefaultBranchProtection *int `url:"default_branch_protection,omitempty" json:"default_branch_protection,omitempty"` DefaultGroupVisibility *VisibilityValue `url:"default_group_visibility,omitempty" json:"default_group_visibility,omitempty"` DefaultProjectCreation *int `url:"default_project_creation,omitempty" json:"default_project_creation,omitempty"` DefaultProjectsLimit *int `url:"default_projects_limit,omitempty" json:"default_projects_limit,omitempty"` DefaultProjectVisibility *VisibilityValue `url:"default_project_visibility,omitempty" json:"default_project_visibility,omitempty"` DefaultSnippetVisibility *VisibilityValue `url:"default_snippet_visibility,omitempty" json:"default_snippet_visibility,omitempty"` DiffMaxPatchBytes *int `url:"diff_max_patch_bytes,omitempty" json:"diff_max_patch_bytes,omitempty"` DisabledOauthSignInSources []string `url:"disabled_oauth_sign_in_sources,omitempty" json:"disabled_oauth_sign_in_sources,omitempty"` DNSRebindingProtectionEnabled *bool `url:"dns_rebinding_protection_enabled,omitempty" json:"dns_rebinding_protection_enabled,omitempty"` DomainBlacklist []string `url:"domain_blacklist,omitempty" json:"domain_blacklist,omitempty"` DomainBlacklistEnabled *bool `url:"domain_blacklist_enabled,omitempty" json:"domain_blacklist_enabled,omitempty"` DomainWhitelist []string `url:"domain_whitelist,omitempty" json:"domain_whitelist,omitempty"` DSAKeyRestriction *int `url:"dsa_key_restriction,omitempty" json:"dsa_key_restriction,omitempty"` ECDSAKeyRestriction *int `url:"ecdsa_key_restriction,omitempty" json:"ecdsa_key_restriction,omitempty"` Ed25519KeyRestriction *int `url:"ed25519_key_restriction,omitempty" json:"ed25519_key_restriction,omitempty"` ElasticsearchAWSAccessKey *string `url:"elasticsearch_aws_access_key,omitempty" json:"elasticsearch_aws_access_key,omitempty"` ElasticsearchAWS *bool `url:"elasticsearch_aws,omitempty" json:"elasticsearch_aws,omitempty"` ElasticsearchAWSRegion *string `url:"elasticsearch_aws_region,omitempty" json:"elasticsearch_aws_region,omitempty"` ElasticsearchAWSSecretAccessKey *string `url:"elasticsearch_aws_secret_access_key,omitempty" json:"elasticsearch_aws_secret_access_key,omitempty"` ElasticsearchIndexing *bool `url:"elasticsearch_indexing,omitempty" json:"elasticsearch_indexing,omitempty"` ElasticsearchLimitIndexing *bool `url:"elasticsearch_limit_indexing,omitempty" json:"elasticsearch_limit_indexing,omitempty"` ElasticsearchNamespaceIDs []int `url:"elasticsearch_namespace_ids,omitempty" json:"elasticsearch_namespace_ids,omitempty"` ElasticsearchProjectIDs []int `url:"elasticsearch_project_ids,omitempty" json:"elasticsearch_project_ids,omitempty"` ElasticsearchSearch *bool `url:"elasticsearch_search,omitempty" json:"elasticsearch_search,omitempty"` ElasticsearchURL *string `url:"elasticsearch_url,omitempty" json:"elasticsearch_url,omitempty"` EmailAdditionalText *string `url:"email_additional_text,omitempty" json:"email_additional_text,omitempty"` EmailAuthorInBody *bool `url:"email_author_in_body,omitempty" json:"email_author_in_body,omitempty"` EnabledGitAccessProtocol *string `url:"enabled_git_access_protocol,omitempty" json:"enabled_git_access_protocol,omitempty"` EnforceTerms *bool `url:"enforce_terms,omitempty" json:"enforce_terms,omitempty"` ExternalAuthClientCert *string `url:"external_auth_client_cert,omitempty" json:"external_auth_client_cert,omitempty"` ExternalAuthClientKeyPass *string `url:"external_auth_client_key_pass,omitempty" json:"external_auth_client_key_pass,omitempty"` ExternalAuthClientKey *string `url:"external_auth_client_key,omitempty" json:"external_auth_client_key,omitempty"` ExternalAuthorizationServiceDefaultLabel *string `url:"external_authorization_service_default_label,omitempty" json:"external_authorization_service_default_label,omitempty"` ExternalAuthorizationServiceEnabled *bool `url:"external_authorization_service_enabled,omitempty" json:"external_authorization_service_enabled,omitempty"` ExternalAuthorizationServiceTimeout *float64 `url:"external_authorization_service_timeout,omitempty" json:"external_authorization_service_timeout,omitempty"` ExternalAuthorizationServiceURL *string `url:"external_authorization_service_url,omitempty" json:"external_authorization_service_url,omitempty"` FileTemplateProjectID *int `url:"file_template_project_id,omitempty" json:"file_template_project_id,omitempty"` FirstDayOfWeek *int `url:"first_day_of_week,omitempty" json:"first_day_of_week,omitempty"` GeoNodeAllowedIPs *string `url:"geo_node_allowed_ips,omitempty" json:"geo_node_allowed_ips,omitempty"` GeoStatusTimeout *int `url:"geo_status_timeout,omitempty" json:"geo_status_timeout,omitempty"` GitalyTimeoutDefault *int `url:"gitaly_timeout_default,omitempty" json:"gitaly_timeout_default,omitempty"` GitalyTimeoutFast *int `url:"gitaly_timeout_fast,omitempty" json:"gitaly_timeout_fast,omitempty"` GitalyTimeoutMedium *int `url:"gitaly_timeout_medium,omitempty" json:"gitaly_timeout_medium,omitempty"` GrafanaEnabled *bool `url:"grafana_enabled,omitempty" json:"grafana_enabled,omitempty"` GrafanaURL *string `url:"grafana_url,omitempty" json:"grafana_url,omitempty"` GravatarEnabled *bool `url:"gravatar_enabled,omitempty" json:"gravatar_enabled,omitempty"` HashedStorageEnabled *bool `url:"hashed_storage_enabled,omitempty" json:"hashed_storage_enabled,omitempty"` HelpPageHideCommercialContent *bool `url:"help_page_hide_commercial_content,omitempty" json:"help_page_hide_commercial_content,omitempty"` HelpPageSupportURL *string `url:"help_page_support_url,omitempty" json:"help_page_support_url,omitempty"` HelpPageText *string `url:"help_page_text,omitempty" json:"help_page_text,omitempty"` HelpText *string `url:"help_text,omitempty" json:"help_text,omitempty"` HideThirdPartyOffers *bool `url:"hide_third_party_offers,omitempty" json:"hide_third_party_offers,omitempty"` HomePageURL *string `url:"home_page_url,omitempty" json:"home_page_url,omitempty"` HousekeepingBitmapsEnabled *bool `url:"housekeeping_bitmaps_enabled,omitempty" json:"housekeeping_bitmaps_enabled,omitempty"` HousekeepingEnabled *bool `url:"housekeeping_enabled,omitempty" json:"housekeeping_enabled,omitempty"` HousekeepingFullRepackPeriod *int `url:"housekeeping_full_repack_period,omitempty" json:"housekeeping_full_repack_period,omitempty"` HousekeepingGcPeriod *int `url:"housekeeping_gc_period,omitempty" json:"housekeeping_gc_period,omitempty"` HousekeepingIncrementalRepackPeriod *int `url:"housekeeping_incremental_repack_period,omitempty" json:"housekeeping_incremental_repack_period,omitempty"` HTMLEmailsEnabled *bool `url:"html_emails_enabled,omitempty" json:"html_emails_enabled,omitempty"` ImportSources []string `url:"import_sources,omitempty" json:"import_sources,omitempty"` InstanceStatisticsVisibilityPrivate *bool `url:"instance_statistics_visibility_private,omitempty" json:"instance_statistics_visibility_private,omitempty"` LocalMarkdownVersion *int `url:"local_markdown_version,omitempty" json:"local_markdown_version,omitempty"` MaxArtifactsSize *int `url:"max_artifacts_size,omitempty" json:"max_artifacts_size,omitempty"` MaxAttachmentSize *int `url:"max_attachment_size,omitempty" json:"max_attachment_size,omitempty"` MaxPagesSize *int `url:"max_pages_size,omitempty" json:"max_pages_size,omitempty"` MetricsEnabled *bool `url:"metrics_enabled,omitempty" json:"metrics_enabled,omitempty"` MetricsHost *string `url:"metrics_host,omitempty" json:"metrics_host,omitempty"` MetricsMethodCallThreshold *int `url:"metrics_method_call_threshold,omitempty" json:"metrics_method_call_threshold,omitempty"` MetricsPacketSize *int `url:"metrics_packet_size,omitempty" json:"metrics_packet_size,omitempty"` MetricsPoolSize *int `url:"metrics_pool_size,omitempty" json:"metrics_pool_size,omitempty"` MetricsPort *int `url:"metrics_port,omitempty" json:"metrics_port,omitempty"` MetricsSampleInterval *int `url:"metrics_sample_interval,omitempty" json:"metrics_sample_interval,omitempty"` MetricsTimeout *int `url:"metrics_timeout,omitempty" json:"metrics_timeout,omitempty"` MirrorAvailable *bool `url:"mirror_available,omitempty" json:"mirror_available,omitempty"` MirrorCapacityThreshold *int `url:"mirror_capacity_threshold,omitempty" json:"mirror_capacity_threshold,omitempty"` MirrorMaxCapacity *int `url:"mirror_max_capacity,omitempty" json:"mirror_max_capacity,omitempty"` MirrorMaxDelay *int `url:"mirror_max_delay,omitempty" json:"mirror_max_delay,omitempty"` OutboundLocalRequestsWhitelist []string `url:"outbound_local_requests_whitelist,omitempty" json:"outbound_local_requests_whitelist,omitempty"` PagesDomainVerificationEnabled *bool `url:"pages_domain_verification_enabled,omitempty" json:"pages_domain_verification_enabled,omitempty"` PasswordAuthenticationEnabledForGit *bool `url:"password_authentication_enabled_for_git,omitempty" json:"password_authentication_enabled_for_git,omitempty"` PasswordAuthenticationEnabledForWeb *bool `url:"password_authentication_enabled_for_web,omitempty" json:"password_authentication_enabled_for_web,omitempty"` PerformanceBarAllowedGroupID *string `url:"performance_bar_allowed_group_id,omitempty" json:"performance_bar_allowed_group_id,omitempty"` PerformanceBarAllowedGroupPath *string `url:"performance_bar_allowed_group_path,omitempty" json:"performance_bar_allowed_group_path,omitempty"` PerformanceBarEnabled *bool `url:"performance_bar_enabled,omitempty" json:"performance_bar_enabled,omitempty"` PlantumlEnabled *bool `url:"plantuml_enabled,omitempty" json:"plantuml_enabled,omitempty"` PlantumlURL *string `url:"plantuml_url,omitempty" json:"plantuml_url,omitempty"` PollingIntervalMultiplier *float64 `url:"polling_interval_multiplier,omitempty" json:"polling_interval_multiplier,omitempty"` ProjectExportEnabled *bool `url:"project_export_enabled,omitempty" json:"project_export_enabled,omitempty"` PrometheusMetricsEnabled *bool `url:"prometheus_metrics_enabled,omitempty" json:"prometheus_metrics_enabled,omitempty"` ProtectedCIVariables *bool `url:"protected_ci_variables,omitempty" json:"protected_ci_variables,omitempty"` PseudonymizerEnabled *bool `url:"psedonymizer_enabled,omitempty" json:"psedonymizer_enabled,omitempty"` PushEventHooksLimit *int `url:"push_event_hooks_limit,omitempty" json:"push_event_hooks_limit,omitempty"` PushEventActivitiesLimit *int `url:"push_event_activities_limit,omitempty" json:"push_event_activities_limit,omitempty"` RecaptchaEnabled *bool `url:"recaptcha_enabled,omitempty" json:"recaptcha_enabled,omitempty"` RecaptchaPrivateKey *string `url:"recaptcha_private_key,omitempty" json:"recaptcha_private_key,omitempty"` RecaptchaSiteKey *string `url:"recaptcha_site_key,omitempty" json:"recaptcha_site_key,omitempty"` ReceiveMaxInputSize *int `url:"receive_max_input_size,omitempty" json:"receive_max_input_size,omitempty"` RepositoryChecksEnabled *bool `url:"repository_checks_enabled,omitempty" json:"repository_checks_enabled,omitempty"` RepositorySizeLimit *int `url:"repository_size_limit,omitempty" json:"repository_size_limit,omitempty"` RepositoryStorages []string `url:"repository_storages,omitempty" json:"repository_storages,omitempty"` RequireTwoFactorAuthentication *bool `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"` RestrictedVisibilityLevels []VisibilityValue `url:"restricted_visibility_levels,omitempty" json:"restricted_visibility_levels,omitempty"` RsaKeyRestriction *int `url:"rsa_key_restriction,omitempty" json:"rsa_key_restriction,omitempty"` SendUserConfirmationEmail *bool `url:"send_user_confirmation_email,omitempty" json:"send_user_confirmation_email,omitempty"` SessionExpireDelay *int `url:"session_expire_delay,omitempty" json:"session_expire_delay,omitempty"` SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` SharedRunnersMinutes *int `url:"shared_runners_minutes,omitempty" json:"shared_runners_minutes,omitempty"` SharedRunnersText *string `url:"shared_runners_text,omitempty" json:"shared_runners_text,omitempty"` SignInText *string `url:"sign_in_text,omitempty" json:"sign_in_text,omitempty"` SignupEnabled *bool `url:"signup_enabled,omitempty" json:"signup_enabled,omitempty"` SlackAppEnabled *bool `url:"slack_app_enabled,omitempty" json:"slack_app_enabled,omitempty"` SlackAppID *string `url:"slack_app_id,omitempty" json:"slack_app_id,omitempty"` SlackAppSecret *string `url:"slack_app_secret,omitempty" json:"slack_app_secret,omitempty"` SlackAppVerificationToken *string `url:"slack_app_verification_token,omitempty" json:"slack_app_verification_token,omitempty"` SnowplowCollectorHostname *string `url:"snowplow_collector_hostname,omitempty" json:"snowplow_collector_hostname,omitempty"` SnowplowCookieDomain *string `url:"snowplow_cookie_domain,omitempty" json:"snowplow_cookie_domain,omitempty"` SnowplowEnabled *bool `url:"snowplow_enabled,omitempty" json:"snowplow_enabled,omitempty"` SnowplowSiteID *string `url:"snowplow_site_id,omitempty" json:"snowplow_site_id,omitempty"` TerminalMaxSessionTime *int `url:"terminal_max_session_time,omitempty" json:"terminal_max_session_time,omitempty"` Terms *string `url:"terms,omitempty" json:"terms,omitempty"` ThrottleAuthenticatedAPIEnabled *bool `url:"throttle_authenticated_api_enabled,omitempty" json:"throttle_authenticated_api_enabled,omitempty"` ThrottleAuthenticatedAPIPeriodInSeconds *int `url:"throttle_authenticated_api_period_in_seconds,omitempty" json:"throttle_authenticated_api_period_in_seconds,omitempty"` ThrottleAuthenticatedAPIRequestsPerPeriod *int `url:"throttle_authenticated_api_requests_per_period,omitempty" json:"throttle_authenticated_api_requests_per_period,omitempty"` ThrottleAuthenticatedWebEnabled *bool `url:"throttle_authenticated_web_enabled,omitempty" json:"throttle_authenticated_web_enabled,omitempty"` ThrottleAuthenticatedWebPeriodInSeconds *int `url:"throttle_authenticated_web_period_in_seconds,omitempty" json:"throttle_authenticated_web_period_in_seconds,omitempty"` ThrottleAuthenticatedWebRequestsPerPeriod *int `url:"throttle_authenticated_web_requests_per_period,omitempty" json:"throttle_authenticated_web_requests_per_period,omitempty"` ThrottleUnauthenticatedEnabled *bool `url:"throttle_unauthenticated_enabled,omitempty" json:"throttle_unauthenticated_enabled,omitempty"` ThrottleUnauthenticatedPeriodInSeconds *int `url:"throttle_unauthenticated_period_in_seconds,omitempty" json:"throttle_unauthenticated_period_in_seconds,omitempty"` ThrottleUnauthenticatedRequestsPerPeriod *int `url:"throttle_unauthenticated_requests_per_period,omitempty" json:"throttle_unauthenticated_requests_per_period,omitempty"` TimeTrackingLimitToHours *bool `url:"time_tracking_limit_to_hours,omitempty" json:"time_tracking_limit_to_hours,omitempty"` TwoFactorGracePeriod *int `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"` UniqueIPsLimitEnabled *bool `url:"unique_ips_limit_enabled,omitempty" json:"unique_ips_limit_enabled,omitempty"` UniqueIPsLimitPerUser *int `url:"unique_ips_limit_per_user,omitempty" json:"unique_ips_limit_per_user,omitempty"` UniqueIPsLimitTimeWindow *int `url:"unique_ips_limit_time_window,omitempty" json:"unique_ips_limit_time_window,omitempty"` UsagePingEnabled *bool `url:"usage_ping_enabled,omitempty" json:"usage_ping_enabled,omitempty"` UserDefaultExternal *bool `url:"user_default_external,omitempty" json:"user_default_external,omitempty"` UserDefaultInternalRegex *string `url:"user_default_internal_regex,omitempty" json:"user_default_internal_regex,omitempty"` UserOauthApplications *bool `url:"user_oauth_applications,omitempty" json:"user_oauth_applications,omitempty"` UserShowAddSSHKeyMessage *bool `url:"user_show_add_ssh_key_message,omitempty" json:"user_show_add_ssh_key_message,omitempty"` VersionCheckEnabled *bool `url:"version_check_enabled,omitempty" json:"version_check_enabled,omitempty"` WebIDEClientsidePreviewEnabled *bool `url:"web_ide_clientside_preview_enabled,omitempty" json:"web_ide_clientside_preview_enabled,omitempty"` } // UpdateSettings updates the application settings. // // GitLab API docs: // https://docs.gitlab.com/ce/api/settings.html#change-application.settings func (s *SettingsService) UpdateSettings(opt *UpdateSettingsOptions, options ...OptionFunc) (*Settings, *Response, error) { req, err := s.client.NewRequest("PUT", "application/settings", opt, options) if err != nil { return nil, nil, err } as := new(Settings) resp, err := s.client.Do(req, as) if err != nil { return nil, resp, err } return as, resp, err } golang-github-xanzy-go-gitlab-0.22.2/settings_test.go000066400000000000000000000023211357140411500225630ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestGetSettings(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/application/settings", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"id":1, "default_projects_limit" : 100000}`) }) settings, _, err := client.Settings.GetSettings() if err != nil { t.Fatal(err) } want := &Settings{ID: 1, DefaultProjectsLimit: 100000} if !reflect.DeepEqual(settings, want) { t.Errorf("Settings.GetSettings returned %+v, want %+v", settings, want) } } func TestUpdateSettings(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/application/settings", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"default_projects_limit" : 100}`) }) options := &UpdateSettingsOptions{ DefaultProjectsLimit: Int(100), } settings, _, err := client.Settings.UpdateSettings(options) if err != nil { t.Fatal(err) } want := &Settings{DefaultProjectsLimit: 100} if !reflect.DeepEqual(settings, want) { t.Errorf("Settings.UpdateSettings returned %+v, want %+v", settings, want) } } golang-github-xanzy-go-gitlab-0.22.2/sidekiq_metrics.go000066400000000000000000000107621357140411500230530ustar00rootroot00000000000000// // Copyright 2018, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import "time" // SidekiqService handles communication with the sidekiq service // // GitLab API docs: https://docs.gitlab.com/ce/api/sidekiq_metrics.html type SidekiqService struct { client *Client } // QueueMetrics represents the GitLab sidekiq queue metrics. // // GitLab API docs: // https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-queue-metrics type QueueMetrics struct { Queues map[string]struct { Backlog int `json:"backlog"` Latency int `json:"latency"` } `json:"queues"` } // GetQueueMetrics lists information about all the registered queues, // their backlog and their latency. // // GitLab API docs: // https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-queue-metrics func (s *SidekiqService) GetQueueMetrics(options ...OptionFunc) (*QueueMetrics, *Response, error) { req, err := s.client.NewRequest("GET", "/sidekiq/queue_metrics", nil, options) if err != nil { return nil, nil, err } q := new(QueueMetrics) resp, err := s.client.Do(req, q) if err != nil { return nil, resp, err } return q, resp, err } // ProcessMetrics represents the GitLab sidekiq process metrics. // // GitLab API docs: // https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-process-metrics type ProcessMetrics struct { Processes []struct { Hostname string `json:"hostname"` Pid int `json:"pid"` Tag string `json:"tag"` StartedAt *time.Time `json:"started_at"` Queues []string `json:"queues"` Labels []string `json:"labels"` Concurrency int `json:"concurrency"` Busy int `json:"busy"` } `json:"processes"` } // GetProcessMetrics lists information about all the Sidekiq workers registered // to process your queues. // // GitLab API docs: // https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-process-metrics func (s *SidekiqService) GetProcessMetrics(options ...OptionFunc) (*ProcessMetrics, *Response, error) { req, err := s.client.NewRequest("GET", "/sidekiq/process_metrics", nil, options) if err != nil { return nil, nil, err } p := new(ProcessMetrics) resp, err := s.client.Do(req, p) if err != nil { return nil, resp, err } return p, resp, err } // JobStats represents the GitLab sidekiq job stats. // // GitLab API docs: // https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics type JobStats struct { Jobs struct { Processed int `json:"processed"` Failed int `json:"failed"` Enqueued int `json:"enqueued"` } `json:"jobs"` } // GetJobStats list information about the jobs that Sidekiq has performed. // // GitLab API docs: // https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics func (s *SidekiqService) GetJobStats(options ...OptionFunc) (*JobStats, *Response, error) { req, err := s.client.NewRequest("GET", "/sidekiq/job_stats", nil, options) if err != nil { return nil, nil, err } j := new(JobStats) resp, err := s.client.Do(req, j) if err != nil { return nil, resp, err } return j, resp, err } // CompoundMetrics represents the GitLab sidekiq compounded stats. // // GitLab API docs: // https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-a-compound-response-of-all-the-previously-mentioned-metrics type CompoundMetrics struct { QueueMetrics ProcessMetrics JobStats } // GetCompoundMetrics lists all the currently available information about Sidekiq. // Get a compound response of all the previously mentioned metrics // // GitLab API docs: https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics func (s *SidekiqService) GetCompoundMetrics(options ...OptionFunc) (*CompoundMetrics, *Response, error) { req, err := s.client.NewRequest("GET", "/sidekiq/compound_metrics", nil, options) if err != nil { return nil, nil, err } c := new(CompoundMetrics) resp, err := s.client.Do(req, c) if err != nil { return nil, resp, err } return c, resp, err } golang-github-xanzy-go-gitlab-0.22.2/snippets.go000066400000000000000000000154741357140411500215460ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "bytes" "fmt" "time" ) // SnippetsService handles communication with the snippets // related methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html type SnippetsService struct { client *Client } // Snippet represents a GitLab snippet. // // GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html type Snippet struct { ID int `json:"id"` Title string `json:"title"` FileName string `json:"file_name"` Description string `json:"description"` Author struct { ID int `json:"id"` Username string `json:"username"` Email string `json:"email"` Name string `json:"name"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` } `json:"author"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` WebURL string `json:"web_url"` RawURL string `json:"raw_url"` } func (s Snippet) String() string { return Stringify(s) } // ListSnippetsOptions represents the available ListSnippets() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets type ListSnippetsOptions ListOptions // ListSnippets gets a list of snippets. // // GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets func (s *SnippetsService) ListSnippets(opt *ListSnippetsOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { req, err := s.client.NewRequest("GET", "snippets", opt, options) if err != nil { return nil, nil, err } var ps []*Snippet resp, err := s.client.Do(req, &ps) if err != nil { return nil, resp, err } return ps, resp, err } // GetSnippet gets a single snippet // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#single-snippet func (s *SnippetsService) GetSnippet(snippet int, options ...OptionFunc) (*Snippet, *Response, error) { u := fmt.Sprintf("snippets/%d", snippet) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } ps := new(Snippet) resp, err := s.client.Do(req, ps) if err != nil { return nil, resp, err } return ps, resp, err } // CreateSnippetOptions represents the available CreateSnippet() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet type CreateSnippetOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Content *string `url:"content,omitempty" json:"content,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` } // CreateSnippet creates a new snippet. The user must have permission // to create new snippets. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet func (s *SnippetsService) CreateSnippet(opt *CreateSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { req, err := s.client.NewRequest("POST", "snippets", opt, options) if err != nil { return nil, nil, err } ps := new(Snippet) resp, err := s.client.Do(req, ps) if err != nil { return nil, resp, err } return ps, resp, err } // UpdateSnippetOptions represents the available UpdateSnippet() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#update-snippet type UpdateSnippetOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` Content *string `url:"content,omitempty" json:"content,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` } // UpdateSnippet updates an existing snippet. The user must have // permission to change an existing snippet. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#update-snippet func (s *SnippetsService) UpdateSnippet(snippet int, opt *UpdateSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { u := fmt.Sprintf("snippets/%d", snippet) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } ps := new(Snippet) resp, err := s.client.Do(req, ps) if err != nil { return nil, resp, err } return ps, resp, err } // DeleteSnippet deletes an existing snippet. This is an idempotent // function and deleting a non-existent snippet still returns a 200 OK status // code. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#delete-snippet func (s *SnippetsService) DeleteSnippet(snippet int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("snippets/%d", snippet) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // SnippetContent returns the raw snippet as plain text. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#snippet-content func (s *SnippetsService) SnippetContent(snippet int, options ...OptionFunc) ([]byte, *Response, error) { u := fmt.Sprintf("snippets/%d/raw", snippet) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var b bytes.Buffer resp, err := s.client.Do(req, &b) if err != nil { return nil, resp, err } return b.Bytes(), resp, err } // ExploreSnippetsOptions represents the available ExploreSnippets() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets type ExploreSnippetsOptions ListOptions // ExploreSnippets gets the list of public snippets. // // GitLab API docs: // https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets func (s *SnippetsService) ExploreSnippets(opt *ExploreSnippetsOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { req, err := s.client.NewRequest("GET", "snippets/public", nil, options) if err != nil { return nil, nil, err } var ps []*Snippet resp, err := s.client.Do(req, &ps) if err != nil { return nil, resp, err } return ps, resp, err } golang-github-xanzy-go-gitlab-0.22.2/strings.go000066400000000000000000000040601357140411500213570ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "bytes" "fmt" "reflect" ) // Stringify attempts to create a reasonable string representation of types in // the GitHub library. It does things like resolve pointers to their values // and omits struct fields with nil values. func Stringify(message interface{}) string { var buf bytes.Buffer v := reflect.ValueOf(message) stringifyValue(&buf, v) return buf.String() } // stringifyValue was heavily inspired by the goprotobuf library. func stringifyValue(buf *bytes.Buffer, val reflect.Value) { if val.Kind() == reflect.Ptr && val.IsNil() { buf.WriteString("") return } v := reflect.Indirect(val) switch v.Kind() { case reflect.String: fmt.Fprintf(buf, `"%s"`, v) case reflect.Slice: buf.WriteByte('[') for i := 0; i < v.Len(); i++ { if i > 0 { buf.WriteByte(' ') } stringifyValue(buf, v.Index(i)) } buf.WriteByte(']') return case reflect.Struct: if v.Type().Name() != "" { buf.WriteString(v.Type().String()) } buf.WriteByte('{') var sep bool for i := 0; i < v.NumField(); i++ { fv := v.Field(i) if fv.Kind() == reflect.Ptr && fv.IsNil() { continue } if fv.Kind() == reflect.Slice && fv.IsNil() { continue } if sep { buf.WriteString(", ") } else { sep = true } buf.WriteString(v.Type().Field(i).Name) buf.WriteByte(':') stringifyValue(buf, fv) } buf.WriteByte('}') default: if v.CanInterface() { fmt.Fprint(buf, v.Interface()) } } } golang-github-xanzy-go-gitlab-0.22.2/system_hooks.go000066400000000000000000000073741357140411500224300ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "time" ) // SystemHooksService handles communication with the system hooks related // methods of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html type SystemHooksService struct { client *Client } // Hook represents a GitLap system hook. // // GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html type Hook struct { ID int `json:"id"` URL string `json:"url"` CreatedAt *time.Time `json:"created_at"` } func (h Hook) String() string { return Stringify(h) } // ListHooks gets a list of system hooks. // // GitLab API docs: // https://docs.gitlab.com/ce/api/system_hooks.html#list-system-hooks func (s *SystemHooksService) ListHooks(options ...OptionFunc) ([]*Hook, *Response, error) { req, err := s.client.NewRequest("GET", "hooks", nil, options) if err != nil { return nil, nil, err } var h []*Hook resp, err := s.client.Do(req, &h) if err != nil { return nil, resp, err } return h, resp, err } // AddHookOptions represents the available AddHook() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook type AddHookOptions struct { URL *string `url:"url,omitempty" json:"url,omitempty"` } // AddHook adds a new system hook hook. // // GitLab API docs: // https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook func (s *SystemHooksService) AddHook(opt *AddHookOptions, options ...OptionFunc) (*Hook, *Response, error) { req, err := s.client.NewRequest("POST", "hooks", opt, options) if err != nil { return nil, nil, err } h := new(Hook) resp, err := s.client.Do(req, h) if err != nil { return nil, resp, err } return h, resp, err } // HookEvent represents an event trigger by a GitLab system hook. // // GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html type HookEvent struct { EventName string `json:"event_name"` Name string `json:"name"` Path string `json:"path"` ProjectID int `json:"project_id"` OwnerName string `json:"owner_name"` OwnerEmail string `json:"owner_email"` } func (h HookEvent) String() string { return Stringify(h) } // TestHook tests a system hook. // // GitLab API docs: // https://docs.gitlab.com/ce/api/system_hooks.html#test-system-hook func (s *SystemHooksService) TestHook(hook int, options ...OptionFunc) (*HookEvent, *Response, error) { u := fmt.Sprintf("hooks/%d", hook) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } h := new(HookEvent) resp, err := s.client.Do(req, h) if err != nil { return nil, resp, err } return h, resp, err } // DeleteHook deletes a system hook. This is an idempotent API function and // returns 200 OK even if the hook is not available. If the hook is deleted it // is also returned as JSON. // // GitLab API docs: // https://docs.gitlab.com/ce/api/system_hooks.html#delete-system-hook func (s *SystemHooksService) DeleteHook(hook int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("hooks/%d", hook) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/tags.go000066400000000000000000000160251357140411500206300ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "fmt" "net/url" ) // TagsService handles communication with the tags related methods // of the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/tags.html type TagsService struct { client *Client } // Tag represents a GitLab tag. // // GitLab API docs: https://docs.gitlab.com/ce/api/tags.html type Tag struct { Commit *Commit `json:"commit"` Release *ReleaseNote `json:"release"` Name string `json:"name"` Message string `json:"message"` } // ReleaseNote represents a GitLab version release. // // GitLab API docs: https://docs.gitlab.com/ce/api/tags.html type ReleaseNote struct { TagName string `json:"tag_name"` Description string `json:"description"` } func (t Tag) String() string { return Stringify(t) } // ListTagsOptions represents the available ListTags() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#list-project-repository-tags type ListTagsOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } // ListTags gets a list of tags from a project, sorted by name in reverse // alphabetical order. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#list-project-repository-tags func (s *TagsService) ListTags(pid interface{}, opt *ListTagsOptions, options ...OptionFunc) ([]*Tag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/tags", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var t []*Tag resp, err := s.client.Do(req, &t) if err != nil { return nil, resp, err } return t, resp, err } // GetTag a specific repository tag determined by its name. It returns 200 together // with the tag information if the tag exists. It returns 404 if the tag does not exist. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#get-a-single-repository-tag func (s *TagsService) GetTag(pid interface{}, tag string, options ...OptionFunc) (*Tag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/tags/%s", pathEscape(project), url.PathEscape(tag)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var t *Tag resp, err := s.client.Do(req, &t) if err != nil { return nil, resp, err } return t, resp, err } // CreateTagOptions represents the available CreateTag() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag type CreateTagOptions struct { TagName *string `url:"tag_name,omitempty" json:"tag_name,omitempty"` Ref *string `url:"ref,omitempty" json:"ref,omitempty"` Message *string `url:"message,omitempty" json:"message,omitempty"` // ReleaseDescription parameter was deprecated in GitLab 11.7 ReleaseDescription *string `url:"release_description:omitempty" json:"release_description,omitempty"` } // CreateTag creates a new tag in the repository that points to the supplied ref. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag func (s *TagsService) CreateTag(pid interface{}, opt *CreateTagOptions, options ...OptionFunc) (*Tag, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/tags", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } t := new(Tag) resp, err := s.client.Do(req, t) if err != nil { return nil, resp, err } return t, resp, err } // DeleteTag deletes a tag of a repository with given name. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#delete-a-tag func (s *TagsService) DeleteTag(pid interface{}, tag string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/repository/tags/%s", pathEscape(project), url.PathEscape(tag)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // CreateReleaseNoteOptions represents the available CreateReleaseNote() options. // // Deprecated: This feature was deprecated in GitLab 11.7. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#create-a-new-release type CreateReleaseNoteOptions struct { Description *string `url:"description:omitempty" json:"description,omitempty"` } // CreateReleaseNote Add release notes to the existing git tag. // If there already exists a release for the given tag, status code 409 is returned. // // Deprecated: This feature was deprecated in GitLab 11.7. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#create-a-new-release func (s *TagsService) CreateReleaseNote(pid interface{}, tag string, opt *CreateReleaseNoteOptions, options ...OptionFunc) (*ReleaseNote, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/tags/%s/release", pathEscape(project), url.PathEscape(tag)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } r := new(ReleaseNote) resp, err := s.client.Do(req, r) if err != nil { return nil, resp, err } return r, resp, err } // UpdateReleaseNoteOptions represents the available UpdateReleaseNote() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#update-a-release type UpdateReleaseNoteOptions struct { Description *string `url:"description:omitempty" json:"description,omitempty"` } // UpdateReleaseNote Updates the release notes of a given release. // // Deprecated: This feature was deprecated in GitLab 11.7. // // GitLab API docs: // https://docs.gitlab.com/ce/api/tags.html#update-a-release func (s *TagsService) UpdateReleaseNote(pid interface{}, tag string, opt *UpdateReleaseNoteOptions, options ...OptionFunc) (*ReleaseNote, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/repository/tags/%s/release", pathEscape(project), url.PathEscape(tag)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } r := new(ReleaseNote) resp, err := s.client.Do(req, r) if err != nil { return nil, resp, err } return r, resp, err } golang-github-xanzy-go-gitlab-0.22.2/tags_test.go000066400000000000000000000042741357140411500216720ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestTagsService_ListTags(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/tags", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `[{"name": "1.0.0"},{"name": "1.0.1"}]`) }) opt := &ListTagsOptions{ListOptions: ListOptions{Page: 2, PerPage: 3}} tags, _, err := client.Tags.ListTags(1, opt) if err != nil { t.Errorf("Tags.ListTags returned error: %v", err) } want := []*Tag{{Name: "1.0.0"}, {Name: "1.0.1"}} if !reflect.DeepEqual(want, tags) { t.Errorf("Tags.ListTags returned %+v, want %+v", tags, want) } } func TestTagsService_CreateReleaseNote(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/tags/1.0.0/release", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, `{"tag_name": "1.0.0", "description": "Amazing release. Wow"}`) }) opt := &CreateReleaseNoteOptions{Description: String("Amazing release. Wow")} release, _, err := client.Tags.CreateReleaseNote(1, "1.0.0", opt) if err != nil { t.Errorf("Tags.CreateRelease returned error: %v", err) } want := &ReleaseNote{TagName: "1.0.0", Description: "Amazing release. Wow"} if !reflect.DeepEqual(want, release) { t.Errorf("Tags.CreateRelease returned %+v, want %+v", release, want) } } func TestTagsService_UpdateReleaseNote(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/projects/1/repository/tags/1.0.0/release", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") fmt.Fprint(w, `{"tag_name": "1.0.0", "description": "Amazing release. Wow!"}`) }) opt := &UpdateReleaseNoteOptions{Description: String("Amazing release. Wow!")} release, _, err := client.Tags.UpdateReleaseNote(1, "1.0.0", opt) if err != nil { t.Errorf("Tags.UpdateRelease returned error: %v", err) } want := &ReleaseNote{TagName: "1.0.0", Description: "Amazing release. Wow!"} if !reflect.DeepEqual(want, release) { t.Errorf("Tags.UpdateRelease returned %+v, want %+v", release, want) } } golang-github-xanzy-go-gitlab-0.22.2/testdata/000077500000000000000000000000001357140411500211505ustar00rootroot00000000000000golang-github-xanzy-go-gitlab-0.22.2/testdata/get_commit.json000066400000000000000000000016121357140411500241720ustar00rootroot00000000000000{ "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", "short_id": "6104942438c", "title": "Sanitize for network graph", "author_name": "randx", "author_email": "dmitriy.zaporozhets@gmail.com", "committer_name": "Dmitriy", "committer_email": "dmitriy.zaporozhets@gmail.com", "message": "Sanitize for network graph", "parent_ids": [ "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" ], "last_pipeline": { "id": 8, "ref": "master", "sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0", "status": "created", "web_url": "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/54268416", "created_at": "2019-11-04T15:38:53.154Z", "updated_at": "2019-11-04T15:39:03.935Z" }, "stats": { "additions": 15, "deletions": 10, "total": 25 }, "status": "running", "project_id": 13083 } golang-github-xanzy-go-gitlab-0.22.2/testdata/get_merge_request.json000066400000000000000000000113061357140411500255520ustar00rootroot00000000000000 { "id": 33092005, "iid": 14656, "project_id": 278964, "title": "Add deletion support for designs", "description": "## What does this MR do?\r\n\r\nThis adds the capability to destroy/hide designs.", "state": "opened", "created_at": "2019-07-11T22:34:43.500Z", "updated_at": "2019-08-20T09:09:56.690Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "delete-designs-v2", "user_notes_count": 245, "upvotes": 1, "downvotes": 0, "assignee": { "id": 2535118, "name": "Thong Kuah", "username": "tkuah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon", "web_url": "https://gitlab.com/tkuah" }, "author": { "id": 3614858, "name": "Alex Kalderimis", "username": "alexkalderimis", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3614858/avatar.png", "web_url": "https://gitlab.com/alexkalderimis" }, "assignees": [ { "id": 2535118, "name": "Thong Kuah", "username": "tkuah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon", "web_url": "https://gitlab.com/tkuah" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "GitLab Enterprise Edition", "backend", "database", "database::reviewed", "design management", "feature", "frontend", "group::knowledge", "missed:12.1" ], "work_in_progress": false, "milestone": { "id": 693521, "iid": 35, "group_id": 9970, "title": "12.2", "description": "", "state": "active", "created_at": "2018-10-30T16:48:32.567Z", "updated_at": "2019-01-16T19:50:02.455Z", "due_date": "2019-08-22", "start_date": "2019-07-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/35" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "8e0b45049b6253b8984cde9241830d2851168142", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!14656", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/14656", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": true, "task_completion_status": { "count": 9, "completed_count": 8 }, "subscribed": false, "changes_count": "35", "latest_build_started_at": "2019-08-19T09:51:06.545Z", "latest_build_finished_at": "2019-08-19T19:22:29.632Z", "first_deployed_to_production_at": null, "pipeline": { "id": 77056819, "sha": "8e0b45049b6253b8984cde9241830d2851168142", "ref": "delete-designs-v2", "status": "success", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/pipelines/77056819", "created_at": "2019-08-19T09:50:58.157Z", "updated_at": "2019-08-19T19:22:29.647Z" }, "head_pipeline": { "id": 77056819, "sha": "8e0b45049b6253b8984cde9241830d2851168142", "ref": "delete-designs-v2", "status": "success", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/pipelines/77056819", "before_sha": "3fe568caacb261b63090886f5b879ca0d9c6f4c3", "tag": false, "yaml_errors": null, "user": { "id": 3614858, "name": "Alex Kalderimis", "username": "alexkalderimis", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3614858/avatar.png", "web_url": "https://gitlab.com/alexkalderimis" }, "created_at": "2019-08-19T09:50:58.157Z", "updated_at": "2019-08-19T19:22:29.647Z", "started_at": "2019-08-19T09:51:06.545Z", "finished_at": "2019-08-19T19:22:29.632Z", "committed_at": null, "duration": 4916, "coverage": "82.68", "detailed_status": { "icon": "status_warning", "text": "passed", "label": "passed with warnings", "group": "success-with-warnings", "tooltip": "passed", "has_details": true, "details_path": "/gitlab-org/gitlab-ee/pipelines/77056819", "illustration": null, "favicon": "https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png" } }, "diff_refs": { "base_sha": "dd692733bb84bc3e9e862e66c099daec2fa00c83", "head_sha": "8e0b45049b6253b8984cde9241830d2851168142", "start_sha": "dd692733bb84bc3e9e862e66c099daec2fa00c83" }, "merge_error": null, "user": { "can_merge": false }, "approvals_before_merge": 1 } golang-github-xanzy-go-gitlab-0.22.2/testdata/get_merge_requests.json000066400000000000000000003271111357140411500257410ustar00rootroot00000000000000[ { "id": 35385049, "iid": 15442, "project_id": 278964, "title": "WIP: Use structured logging for DB load balancer", "description": "## What does this MR do?\r\n\r\n\r\n\r\nRelates to https://gitlab.com/gitlab-org/gitlab-ee/issues/13547 and https://gitlab.com/gitlab-org/gitlab-ee/issues/13548\r\n\r\n## Does this MR meet the acceptance criteria?\r\n\r\n### Conformity\r\n\r\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \r\n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\r\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\r\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\r\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\r\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\r\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\r\n\r\n### Performance and Testing\r\n\r\n\r\n\r\n\r\n\r\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\r\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\r\n\r\n### Security\r\n\r\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\r\n\r\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\r\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\r\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-20T10:58:54.413Z", "updated_at": "2019-08-20T12:01:49.849Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "use-structured-logging-for-db-load-balancer", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 4088036, "name": "Hordur Freyr Yngvason", "username": "hfyngvason", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png", "web_url": "https://gitlab.com/hfyngvason" }, "author": { "id": 4088036, "name": "Hordur Freyr Yngvason", "username": "hfyngvason", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png", "web_url": "https://gitlab.com/hfyngvason" }, "assignees": [ { "id": 4088036, "name": "Hordur Freyr Yngvason", "username": "hfyngvason", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png", "web_url": "https://gitlab.com/hfyngvason" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "backend", "backstage", "database", "database::review pending", "group::autodevops and kubernetes" ], "work_in_progress": true, "milestone": null, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "2fc4e8b972ff3208ec63b6143e34ad67ff343ad7", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!15442", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15442", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": true, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35384461, "iid": 15441, "project_id": 278964, "title": "WIP: Implement public MR-level approval rules API", "description": "## What does this MR do?\r\n\r\nAdd API endpoints so API users can list, create, update and delete MR-level approval rules.\r\n\r\nThe following API endpoints are added:\r\n- `GET /projects/:id/merge_requests/:merge_request_iid/approval_rules`\r\n- `POST /projects/:id/merge_requests/:merge_request_iid/approval_rules`\r\n- `PUT /projects/:id/merge_requests/:merge_request_iid/approval_rules/:approval_rule_id`\r\n- `DELETE /projects/:id/merge_requests/:merge_request_iid/approval_rules/:approval_rule_id`\r\n\r\n## Does this MR meet the acceptance criteria?\r\n\r\n### Conformity\r\n\r\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \r\n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\r\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\r\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\r\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\r\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\r\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\r\n\r\n### Performance and Testing\r\n\r\n\r\n\r\n\r\n\r\n- [x] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\r\n- [-] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\r\n\r\n### Security\r\n\r\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\r\n\r\n- [-] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\r\n- [-] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\r\n- [-] Security reports checked/validated by a reviewer from the AppSec team \r\n\r\n#12055", "state": "opened", "created_at": "2019-08-20T10:51:56.806Z", "updated_at": "2019-08-20T11:00:25.244Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "12055-public-mr-approval-rules-api", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 1884221, "name": "Patrick Bajao", "username": "patrickbajao", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/1884221/avatar.png", "web_url": "https://gitlab.com/patrickbajao" }, "author": { "id": 1884221, "name": "Patrick Bajao", "username": "patrickbajao", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/1884221/avatar.png", "web_url": "https://gitlab.com/patrickbajao" }, "assignees": [ { "id": 1884221, "name": "Patrick Bajao", "username": "patrickbajao", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/1884221/avatar.png", "web_url": "https://gitlab.com/patrickbajao" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "Create [DEPRECATED]", "Deliverable", "GitLab Enterprise Edition", "GitLab Starter", "api", "approvals", "backend", "devops::create", "feature", "group::source code", "workflow::In dev" ], "work_in_progress": true, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "dbb2b82236b86328f44a1754c9188c0991e707e5", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15441", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15441", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 8, "completed_count": 1 }, "approvals_before_merge": 1 }, { "id": 35368820, "iid": 15440, "project_id": 278964, "title": "Log in Prometheus current number of host and index", "description": "## What does this MR do?\n\n1. Log current number of hosts and current index when `#initialize` is called\n1. Log current number of hosts and current index when `#next` is called\n1. Log current number of hosts and current index when `#hosts=` is called\n\nhttps://gitlab.com/gitlab-org/gitlab-ee/issues/13630\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [x] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-20T10:20:51.687Z", "updated_at": "2019-08-20T11:06:40.659Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "load-balancing-prometheus", "user_notes_count": 2, "upvotes": 0, "downvotes": 0, "assignee": { "id": 4059128, "name": "Avielle Wolfe", "username": "avielle", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4059128/avatar.png", "web_url": "https://gitlab.com/avielle" }, "author": { "id": 2535118, "name": "Thong Kuah", "username": "tkuah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon", "web_url": "https://gitlab.com/tkuah" }, "assignees": [ { "id": 4059128, "name": "Avielle Wolfe", "username": "avielle", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4059128/avatar.png", "web_url": "https://gitlab.com/avielle" }, { "id": 2535118, "name": "Thong Kuah", "username": "tkuah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon", "web_url": "https://gitlab.com/tkuah" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "Configure [DEPRECATED]", "Observability", "P1", "backend", "backstage", "database", "database::review pending", "devops::configure", "gitlab.com", "group::autodevops and kubernetes", "infradev", "workflow::In dev" ], "work_in_progress": false, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "eae31acf34d2df2aba2ea469e432cab1c6a05b53", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15440", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15440", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 1 }, "approvals_before_merge": 1 }, { "id": 35355199, "iid": 15438, "project_id": 278964, "title": "WIP: Resolve \"Cancel redundant pipelines in merge train when reconstruction happens\"", "description": "## What does this MR do?\n\n\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team \n\n\nCloses #12996", "state": "opened", "created_at": "2019-08-20T08:58:07.507Z", "updated_at": "2019-08-20T11:31:20.704Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "12996-cancel-redundant-pipelines-in-merge-train-when-reconstruction-happens-2", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 4391348, "name": "Sean Carroll", "username": "sean_carroll", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4391348/avatar.png", "web_url": "https://gitlab.com/sean_carroll" }, "author": { "id": 4391348, "name": "Sean Carroll", "username": "sean_carroll", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4391348/avatar.png", "web_url": "https://gitlab.com/sean_carroll" }, "assignees": [ { "id": 4391348, "name": "Sean Carroll", "username": "sean_carroll", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4391348/avatar.png", "web_url": "https://gitlab.com/sean_carroll" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "GitLab Enterprise Edition", "P2", "Release [DEPRECATED]", "S2", "continuous delivery", "devops::release", "devops::release::merge trains", "feature", "group::progressive delivery" ], "work_in_progress": true, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "cannot_be_merged", "sha": "fcf75b9330b1104bc08c0190cf871759db3f22e0", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": null, "reference": "!15438", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15438", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": null }, { "id": 35354393, "iid": 15437, "project_id": 278964, "title": "WIP: Add purchase point to group billing page", "description": "## What does this MR do?\r\n\r\n\r\n\r\nAdds Billing Plans to top-level `groups/billing` route.\r\nChanges Billing Plan table to Card layout as per https://gitlab.com/gitlab-org/gitlab-ce/issues/63599\r\n\r\nTop-level `groups/billing`\r\n![groups-billing-plans-cards](/uploads/d6a636af7f6d5ba341bfec0d1375f8ea/groups-billing-plans-cards.png)\r\n\r\n`profile/billing`\r\n![profile-billing-plans-cards](/uploads/fa6de1e12b07423573d38af0f523004b/profile-billing-plans-cards.png)\r\n\r\nCloses https://gitlab.com/gitlab-org/gitlab-ce/issues/63599\r\n\r\n## Does this MR meet the acceptance criteria?\r\n\r\n### Conformity\r\n\r\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \r\n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\r\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\r\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\r\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\r\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\r\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\r\n\r\n### Performance and Testing\r\n\r\n\r\n\r\n\r\n\r\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\r\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\r\n\r\n### Security\r\n\r\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\r\n\r\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\r\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\r\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-20T08:46:46.344Z", "updated_at": "2019-08-20T09:26:29.383Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "add-purchase-point-to-group-billing-page", "user_notes_count": 4, "upvotes": 0, "downvotes": 0, "assignee": { "id": 4430316, "name": "Ragnar Hardarson", "username": "rhardarson", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/ed0d38989fa0a7f168f229dfdf56d2b4?s=80&d=identicon", "web_url": "https://gitlab.com/rhardarson" }, "author": { "id": 4430316, "name": "Ragnar Hardarson", "username": "rhardarson", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/ed0d38989fa0a7f168f229dfdf56d2b4?s=80&d=identicon", "web_url": "https://gitlab.com/rhardarson" }, "assignees": [ { "id": 4430316, "name": "Ragnar Hardarson", "username": "rhardarson", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/ed0d38989fa0a7f168f229dfdf56d2b4?s=80&d=identicon", "web_url": "https://gitlab.com/rhardarson" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "GitLab Enterprise Edition", "feature", "frontend", "group::fulfillment" ], "work_in_progress": true, "milestone": null, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "9af81f5ddb59a57d663c27bcb3144f8c0c26a7fd", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15437", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15437", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35345116, "iid": 15436, "project_id": 278964, "title": "[EE] Add Issue and Merge Request titles to Todo items", "description": "## What does this MR do?\n\nEE version of https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30435\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-20T08:14:48.224Z", "updated_at": "2019-08-20T08:14:48.224Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "include-issue-mr-titles-ee", "user_notes_count": 0, "upvotes": 0, "downvotes": 0, "assignee": { "id": 1642716, "name": "Jan Provaznik", "username": "jprovaznik", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/4577c0b60b7640100030d7ab267aba95?s=80&d=identicon", "web_url": "https://gitlab.com/jprovaznik" }, "author": { "id": 1642716, "name": "Jan Provaznik", "username": "jprovaznik", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/4577c0b60b7640100030d7ab267aba95?s=80&d=identicon", "web_url": "https://gitlab.com/jprovaznik" }, "assignees": [ { "id": 1642716, "name": "Jan Provaznik", "username": "jprovaznik", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/4577c0b60b7640100030d7ab267aba95?s=80&d=identicon", "web_url": "https://gitlab.com/jprovaznik" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "Community contribution", "devops::plan" ], "work_in_progress": false, "milestone": { "id": 693521, "iid": 35, "group_id": 9970, "title": "12.2", "description": "", "state": "active", "created_at": "2018-10-30T16:48:32.567Z", "updated_at": "2019-01-16T19:50:02.455Z", "due_date": "2019-08-22", "start_date": "2019-07-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/35" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "54ac04bb0ec8849bf2ff43a949150d18008c8d35", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!15436", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15436", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": true, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35343590, "iid": 15435, "project_id": 278964, "title": "WIP: Resolve \"Data and Privacy Agreement for GitLab users\"", "description": "## What does this MR do?\n\n\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team \n\n\nCloses #13665", "state": "opened", "created_at": "2019-08-20T07:47:26.890Z", "updated_at": "2019-08-20T10:37:36.505Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "13665-data-and-privacy-agreement-for-gitlab-users", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 750946, "name": "Dennis Tang", "username": "dennis", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/82f4c234d7deecb4760072ecd59f184a?s=80&d=identicon", "web_url": "https://gitlab.com/dennis" }, "author": { "id": 750946, "name": "Dennis Tang", "username": "dennis", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/82f4c234d7deecb4760072ecd59f184a?s=80&d=identicon", "web_url": "https://gitlab.com/dennis" }, "assignees": [ { "id": 750946, "name": "Dennis Tang", "username": "dennis", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/82f4c234d7deecb4760072ecd59f184a?s=80&d=identicon", "web_url": "https://gitlab.com/dennis" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "P1", "S1", "UX ready", "collection 🧺", "devops::growth", "feature", "frontend", "gitlab.com", "group::telemetry", "missed:12.1", "missed:12.1", "unplanned", "workflow::In review" ], "work_in_progress": true, "milestone": { "id": 693521, "iid": 35, "group_id": 9970, "title": "12.2", "description": "", "state": "active", "created_at": "2018-10-30T16:48:32.567Z", "updated_at": "2019-01-16T19:50:02.455Z", "due_date": "2019-08-22", "start_date": "2019-07-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/35" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "de5099c8b64d118648c5fd9e381eadc30ae9b72d", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": null, "reference": "!15435", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15435", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": null }, { "id": 35338313, "iid": 15434, "project_id": 278964, "title": "Flexible Rules for CI Build config", "description": "## What does this MR do?\n\nThis is the EE compatibility check merge request for https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29011\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-20T05:51:33.955Z", "updated_at": "2019-08-20T05:52:16.896Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "ee-ci-config-on-policy", "user_notes_count": 0, "upvotes": 0, "downvotes": 0, "assignee": { "id": 12452, "name": "Kamil TrzciÅ„ski", "username": "ayufan", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/7a285e30f35d72526fb0954e8fe7cefa?s=80&d=identicon", "web_url": "https://gitlab.com/ayufan" }, "author": { "id": 730684, "name": "drew", "username": "drewcimino", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/59b7f2c95acd4a085d964f745ead6bdb?s=80&d=identicon", "web_url": "https://gitlab.com/drewcimino" }, "assignees": [ { "id": 12452, "name": "Kamil TrzciÅ„ski", "username": "ayufan", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/7a285e30f35d72526fb0954e8fe7cefa?s=80&d=identicon", "web_url": "https://gitlab.com/ayufan" }, { "id": 730684, "name": "drew", "username": "drewcimino", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/59b7f2c95acd4a085d964f745ead6bdb?s=80&d=identicon", "web_url": "https://gitlab.com/drewcimino" } ], "source_project_id": 11495811, "target_project_id": 278964, "labels": [ "devops::verify", "feature", "group::continuous integration" ], "work_in_progress": false, "milestone": { "id": 693521, "iid": 35, "group_id": 9970, "title": "12.2", "description": "", "state": "active", "created_at": "2018-10-30T16:48:32.567Z", "updated_at": "2019-01-16T19:50:02.455Z", "due_date": "2019-08-22", "start_date": "2019-07-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/35" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "846faa7dccc7e52f8d7af6b2fe1ca595340219a4", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "allow_collaboration": false, "allow_maintainer_to_push": false, "reference": "!15434", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15434", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35337566, "iid": 15433, "project_id": 278964, "title": "WIP:", "description": "## What does this MR do?\n\nThis is `WIP` to get feedback on how a `Design` might receive a message when its `Note`s are created, updated, resolved or unresolved.\n\nIssue #13353.\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team \n\n\nCloses #13353", "state": "opened", "created_at": "2019-08-20T05:20:41.290Z", "updated_at": "2019-08-20T05:31:20.363Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "13353-DesignType-notes_count", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" }, "author": { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" }, "assignees": [ { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "Deliverable", "GitLab Enterprise Edition", "GraphQL", "backend", "design management", "devops::create", "feature", "group::knowledge", "workflow::In dev" ], "work_in_progress": true, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "de578529c00060f334b2b3e5aeda7e269d838a73", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15433", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15433", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35336438, "iid": 15432, "project_id": 278964, "title": "WIP:", "description": "## What does this MR do?\n\nThis is `WIP` to get feedback on how a `Design` might receive a message when its `Note`s are created, updated, resolved or unresolved.\n\nIssue #13353.\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "closed", "created_at": "2019-08-20T04:57:41.639Z", "updated_at": "2019-08-20T05:10:54.302Z", "merged_by": null, "merged_at": null, "closed_by": { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" }, "closed_at": "2019-08-20T05:10:54.356Z", "target_branch": "master", "source_branch": "13353-DesignType-notes_count", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" }, "author": { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" }, "assignees": [ { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "Deliverable", "GitLab Enterprise Edition", "GraphQL", "backend", "design management", "devops::create", "feature", "group::knowledge", "workflow::In dev" ], "work_in_progress": true, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "34b3b319044987ba86af00b19ab5259d54aa8365", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15432", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15432", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35333974, "iid": 15431, "project_id": 278964, "title": "Quarantine failing test", "description": "## What does this MR do?\n\nThe elasticsearch test fails because it uses a license file as a template, and the template is missing.\n\nSee https://gitlab.com/gitlab-org/quality/nightly/issues/127\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "merged", "created_at": "2019-08-20T03:34:46.802Z", "updated_at": "2019-08-20T08:15:51.047Z", "merged_by": { "id": 178079, "name": "Walmyr Lima e Silva Filho", "username": "wlsf82", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/178079/avatar.png", "web_url": "https://gitlab.com/wlsf82" }, "merged_at": "2019-08-20T08:15:51.244Z", "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "qa-quarantine-templates-test", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": null, "author": { "id": 655908, "name": "Mark Lapierre", "username": "mlapierre", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/655908/avatar.png", "web_url": "https://gitlab.com/mlapierre" }, "assignees": [], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "QA", "Quality", "backstage" ], "work_in_progress": false, "milestone": { "id": 693521, "iid": 35, "group_id": 9970, "title": "12.2", "description": "", "state": "active", "created_at": "2018-10-30T16:48:32.567Z", "updated_at": "2019-01-16T19:50:02.455Z", "due_date": "2019-08-22", "start_date": "2019-07-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/35" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "cba824ca33a199303091c2870e43f897574a3f0e", "merge_commit_sha": "6c3af2d1ce3c64bc559332b8b44dc3b33825781a", "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!15431", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15431", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35328489, "iid": 15428, "project_id": 278964, "title": "Replace haml analytics stage-list-item with vue component", "description": "## What does this MR do?\r\n\r\nUpdate the `stage-nav-item` component on the *analytics/cycle_analytics* page\r\n* Adds the `stage-nav-item` component\r\n* Updates css classes used on the table headers\r\n* Fixes broken UI introduced in !14910\r\n\r\n| Before | After |\r\n| --- | --- |\r\n| ![Screen_Shot_2019-08-20_at_11.09.02_am](/uploads/49c7a93b60362439a6773c15b7ecb500/Screen_Shot_2019-08-20_at_11.09.02_am.png) | ![Screen_Shot_2019-08-20_at_11.19.43_am](/uploads/250858f0f3b7cdd2fd59a2c3d43e250d/Screen_Shot_2019-08-20_at_11.19.43_am.png) |\r\n\r\n## Related issues\r\n#13076\r\n\r\n## Does this MR meet the acceptance criteria?\r\n\r\n### Conformity\r\n\r\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \r\n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\r\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\r\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\r\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\r\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\r\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\r\n\r\n### Performance and Testing\r\n\r\n\r\n\r\n\r\n\r\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\r\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\r\n\r\n### Security\r\n\r\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\r\n\r\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\r\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\r\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-20T01:33:19.691Z", "updated_at": "2019-08-20T03:35:18.319Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "ek-replace-analytics-haml-stage-list-item", "user_notes_count": 2, "upvotes": 0, "downvotes": 0, "assignee": { "id": 3732265, "name": "Paul Gascou-Vaillancourt", "username": "pgascouvaillancourt", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/7a190c0b1ff5772c9230b4d9a38ac608?s=80&d=identicon", "web_url": "https://gitlab.com/pgascouvaillancourt" }, "author": { "id": 3397881, "name": "Ezekiel Kigbo", "username": "ekigbo", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3397881/avatar.png", "web_url": "https://gitlab.com/ekigbo" }, "assignees": [ { "id": 3732265, "name": "Paul Gascou-Vaillancourt", "username": "pgascouvaillancourt", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/7a190c0b1ff5772c9230b4d9a38ac608?s=80&d=identicon", "web_url": "https://gitlab.com/pgascouvaillancourt" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "UI component", "analytics", "bug", "cycle analytics", "frontend" ], "work_in_progress": false, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "2ea513d63d0b03a15d19e34a170e406f7ebab1a6", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15428", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15428", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35328403, "iid": 15427, "project_id": 278964, "title": "Remove the store_designs_in_lfs feature flag", "description": "## What does this MR do?\n\nThis MR removes the `store_designs_in_lfs` feature flag from the codebase. \n\nIssue https://gitlab.com/gitlab-org/gitlab-ee/issues/12158.\n\nThe feature flag was added in https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/13389. \n\nThis MR does not include a changelog entry, because the feature has been enabled by default since https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/13389 and that MR contained the changelog.\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [-] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [-] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [x] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [x] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [x] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [-] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [-] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [x] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [-] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)", "state": "opened", "created_at": "2019-08-20T01:27:32.001Z", "updated_at": "2019-08-20T09:57:31.340Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "12158-remove-store_designs_in_lfs-feature-flag", "user_notes_count": 5, "upvotes": 0, "downvotes": 0, "assignee": { "id": 12452, "name": "Kamil TrzciÅ„ski", "username": "ayufan", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/7a285e30f35d72526fb0954e8fe7cefa?s=80&d=identicon", "web_url": "https://gitlab.com/ayufan" }, "author": { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" }, "assignees": [ { "id": 12452, "name": "Kamil TrzciÅ„ski", "username": "ayufan", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/7a285e30f35d72526fb0954e8fe7cefa?s=80&d=identicon", "web_url": "https://gitlab.com/ayufan" }, { "id": 2702368, "name": "Luke Duncalfe", "username": ".luke", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/2702368/avatar.png", "web_url": "https://gitlab.com/.luke" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "Deliverable", "GitLab Enterprise Edition", "backend", "backstage", "design management", "devops::create", "feature flag", "group::knowledge", "workflow::In review" ], "work_in_progress": false, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "2d3f756620c5de9785bf13a98b02d47c63a2ee1c", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!15427", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15427", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 4, "completed_count": 4 }, "approvals_before_merge": 1 }, { "id": 35323180, "iid": 15426, "project_id": 278964, "title": "Resolve \"Broken master - Job Failed #275548923\"", "description": "## What does this MR do?\r\n\r\nRegenerate gitlab pot file\r\n\r\n```diff\r\ndiff --git a/locale/gitlab.pot b/locale/gitlab.pot\r\nindex 816f4a2590c..6dc4e4b6bc4 100644\r\n--- a/locale/gitlab.pot\r\n+++ b/locale/gitlab.pot\r\n@@ -10705,6 +10705,9 @@ msgstr \"\"\r\n msgid \"Pipelines for last year\"\r\n msgstr \"\"\r\n \r\n+msgid \"Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more on the documentation for Pipelines for Merged Results.\"\r\n+msgstr \"\"\r\n+\r\n msgid \"Pipelines settings for '%{project_name}' were successfully updated.\"\r\n msgstr \"\"\r\n \r\n@@ -14746,9 +14749,6 @@ msgstr \"\"\r\n msgid \"The character highlighter helps you keep the subject line to %{titleLength} characters and wrap the body at %{bodyLength} so they are readable in git.\"\r\n msgstr \"\"\r\n \r\n-msgid \"The code of a detached pipeline is tested against the source branch instead of merged results\"\r\n-msgstr \"\"\r\n-\r\n msgid \"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.\"\r\n msgstr \"\"\r\n \r\n\r\n```\r\n\r\n## Does this MR meet the acceptance criteria?\r\n\r\n### Conformity\r\n\r\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \r\n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\r\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\r\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\r\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\r\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\r\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\r\n\r\n### Performance and Testing\r\n\r\n\r\n\r\n\r\n\r\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\r\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\r\n\r\n### Security\r\n\r\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\r\n\r\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\r\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\r\n- [ ] Security reports checked/validated by a reviewer from the AppSec team \r\n\r\n\r\nCloses #13660", "state": "merged", "created_at": "2019-08-20T00:49:43.170Z", "updated_at": "2019-08-20T02:06:44.222Z", "merged_by": { "id": 2535118, "name": "Thong Kuah", "username": "tkuah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon", "web_url": "https://gitlab.com/tkuah" }, "merged_at": "2019-08-20T02:06:44.486Z", "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "13660-broken-master-job-failed-275548923", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 3397881, "name": "Ezekiel Kigbo", "username": "ekigbo", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3397881/avatar.png", "web_url": "https://gitlab.com/ekigbo" }, "author": { "id": 3397881, "name": "Ezekiel Kigbo", "username": "ekigbo", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3397881/avatar.png", "web_url": "https://gitlab.com/ekigbo" }, "assignees": [ { "id": 3397881, "name": "Ezekiel Kigbo", "username": "ekigbo", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3397881/avatar.png", "web_url": "https://gitlab.com/ekigbo" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "internationalization", "master:broken" ], "work_in_progress": false, "milestone": null, "merge_when_pipeline_succeeds": true, "merge_status": "can_be_merged", "sha": "c7a107ac0148339a18250d73834c3c6eb869be12", "merge_commit_sha": "aef47a865512652d02fa6552636de903cda13e11", "discussion_locked": null, "should_remove_source_branch": true, "force_remove_source_branch": false, "reference": "!15426", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15426", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35286273, "iid": 15420, "project_id": 278964, "title": "Improve nplusone spec for PipelinesController#show", "description": "## What does this MR do?\r\n\r\nRelated https://gitlab.com/gitlab-org/gitlab-ce/issues/60925\r\n\r\nCE MR https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/31976\r\n\r\n## Does this MR meet the acceptance criteria?\r\n\r\n### Conformity\r\n\r\n- N/A [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \r\n- N/A [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\r\n- [x] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\r\n- [x] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\r\n- [x] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\r\n- N/A [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\r\n- N/A [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\r\n\r\n### Performance and Testing\r\n\r\n\r\n\r\n\r\n\r\n- N/A [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\r\n- N/A [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\r\n\r\n### Security\r\n\r\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\r\n\r\n- N/A Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\r\n- N/A The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\r\n- N/A Security reports checked/validated by a reviewer from the AppSec team", "state": "closed", "created_at": "2019-08-19T21:20:31.820Z", "updated_at": "2019-08-19T21:53:45.483Z", "merged_by": null, "merged_at": null, "closed_by": { "id": 64248, "name": "Stan Hu", "username": "stanhu", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/64248/stanhu.jpg", "web_url": "https://gitlab.com/stanhu" }, "closed_at": "2019-08-19T21:53:45.560Z", "target_branch": "master", "source_branch": "mc/bug/nplusone-pipelines-show-ee", "user_notes_count": 2, "upvotes": 0, "downvotes": 0, "assignee": { "id": 722076, "name": "Matija ÄŒupić", "username": "matteeyah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/8bc04cc15e0adba406cf56fecd9d910a?s=80&d=identicon", "web_url": "https://gitlab.com/matteeyah" }, "author": { "id": 722076, "name": "Matija ÄŒupić", "username": "matteeyah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/8bc04cc15e0adba406cf56fecd9d910a?s=80&d=identicon", "web_url": "https://gitlab.com/matteeyah" }, "assignees": [ { "id": 722076, "name": "Matija ÄŒupić", "username": "matteeyah", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/8bc04cc15e0adba406cf56fecd9d910a?s=80&d=identicon", "web_url": "https://gitlab.com/matteeyah" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "Category::Continuous Integration", "backstage", "devops::verify", "group::continuous integration", "performance" ], "work_in_progress": false, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "35d5a9f48cbc4602c5920890ea2636dabf2e8cd1", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!15420", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15420", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 3, "completed_count": 3 }, "approvals_before_merge": 1 }, { "id": 35280733, "iid": 15412, "project_id": 278964, "title": "Return Last Deployment in Environment Dashboard", "description": "## What does this MR do?\r\n\r\n\r\n\r\nReturn the last deployment for each environment for the Environment Dashboard.\r\n\r\nInclude the last deployment's user, commit, and deployable.\r\n\r\nThis fills in a significant portion of the data for the environment card:\r\n\r\n![Screen_Shot_2019-08-19_at_3.52.13_PM](/uploads/669768b74f6ddd772ba2296ed634289b/Screen_Shot_2019-08-19_at_3.52.13_PM.png)\r\n\r\nRelevant issue: https://gitlab.com/gitlab-org/gitlab-ee/issues/3713\r\n\r\n## Does this MR meet the acceptance criteria?\r\n\r\n### Conformity\r\n\r\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \r\n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\r\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\r\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\r\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\r\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\r\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\r\n\r\n### Performance and Testing\r\n\r\n\r\n\r\n\r\n\r\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\r\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\r\n\r\n### Security\r\n\r\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\r\n\r\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\r\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\r\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-19T19:56:07.690Z", "updated_at": "2019-08-20T06:17:15.284Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "environments-list-data-a", "source_branch": "environments-list-data-b", "user_notes_count": 5, "upvotes": 0, "downvotes": 0, "assignee": { "id": 3716529, "name": "Jason Goodman", "username": "jagood", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/6696c95a1788e2d4bee67df636805ecc?s=80&d=identicon", "web_url": "https://gitlab.com/jagood" }, "author": { "id": 3716529, "name": "Jason Goodman", "username": "jagood", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/6696c95a1788e2d4bee67df636805ecc?s=80&d=identicon", "web_url": "https://gitlab.com/jagood" }, "assignees": [ { "id": 3716529, "name": "Jason Goodman", "username": "jagood", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/6696c95a1788e2d4bee67df636805ecc?s=80&d=identicon", "web_url": "https://gitlab.com/jagood" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "backend", "devops::release", "feature" ], "work_in_progress": false, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "2aaa325ba6b725d04859a35da8beb666ba4bbc65", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!15412", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15412", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": true, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35273259, "iid": 15409, "project_id": 278964, "title": "Componentize metrics alerts modal form", "description": "## What does this MR do?\r\n\r\n* Refactors metrics alerts to use only gitlab-ui components. \r\n* Removes `query.unit` from the label, since `query.label` includes the units already. \r\nBefore: \r\n![Screen_Shot_2019-08-19_at_5.21.20_PM](/uploads/47e04c85ef96a6ac7f24768873ff74cd/Screen_Shot_2019-08-19_at_5.21.20_PM.png) \r\n\r\nAfter: \r\n![Screen_Shot_2019-08-19_at_5.56.13_PM](/uploads/af315febb8278143b064f4e09cb82939/Screen_Shot_2019-08-19_at_5.56.13_PM.png)\r\n## Does this MR meet the acceptance criteria?\r\n\r\nCloses #13058", "state": "opened", "created_at": "2019-08-19T17:21:57.593Z", "updated_at": "2019-08-19T22:31:03.279Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "13058-componentize-metrics-alerts-modal-form", "user_notes_count": 2, "upvotes": 0, "downvotes": 0, "assignee": { "id": 829774, "name": "Jose Ivan Vargas", "username": "jivanvl", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/730cc1b85a20f2a3891829f7aa198972?s=80&d=identicon", "web_url": "https://gitlab.com/jivanvl" }, "author": { "id": 3946912, "name": "Laura Montemayor", "username": "lauraMon", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/3946912/avatar.png", "web_url": "https://gitlab.com/lauraMon" }, "assignees": [ { "id": 829774, "name": "Jose Ivan Vargas", "username": "jivanvl", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/730cc1b85a20f2a3891829f7aa198972?s=80&d=identicon", "web_url": "https://gitlab.com/jivanvl" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "GitLab Enterprise Edition", "Monitor [DEPRECATED]", "devops::monitor", "frontend", "group::health", "technical debt", "workflow::In review" ], "work_in_progress": false, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "2c935d51b83c5b4f50ca688d5cbbb771b0e378fc", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15409", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15409", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 0, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35273064, "iid": 15408, "project_id": 278964, "title": "Geo: Tell primary which secondary redirected a Git push over HTTP", "description": "## What does this MR do?\n\n\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "closed", "created_at": "2019-08-19T17:16:32.288Z", "updated_at": "2019-08-20T00:02:08.608Z", "merged_by": null, "merged_at": null, "closed_by": { "id": 1144264, "name": "Michael Kozono", "username": "mkozono", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/ddaa576b4b6933a6fb7a996088c30f6c?s=80&d=identicon", "web_url": "https://gitlab.com/mkozono" }, "closed_at": "2019-08-20T00:02:08.635Z", "target_branch": "master", "source_branch": "mk/provide-geo-node-referrer-on-push-geo", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": { "id": 1144264, "name": "Michael Kozono", "username": "mkozono", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/ddaa576b4b6933a6fb7a996088c30f6c?s=80&d=identicon", "web_url": "https://gitlab.com/mkozono" }, "author": { "id": 1144264, "name": "Michael Kozono", "username": "mkozono", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/ddaa576b4b6933a6fb7a996088c30f6c?s=80&d=identicon", "web_url": "https://gitlab.com/mkozono" }, "assignees": [ { "id": 1144264, "name": "Michael Kozono", "username": "mkozono", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/ddaa576b4b6933a6fb7a996088c30f6c?s=80&d=identicon", "web_url": "https://gitlab.com/mkozono" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [], "work_in_progress": false, "milestone": null, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "21dd0530baefaa2e4bce5d8a9857bad829c51d64", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": true, "reference": "!15408", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15408", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": 1 }, { "id": 35270697, "iid": 15406, "project_id": 278964, "title": "WIP: Resolve \"Move dependency scanning reports logic for the Merge Request widget to the backend - frontend part\"", "description": "## What does this MR do?\n\n\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team \n\n\nCloses #13649", "state": "opened", "created_at": "2019-08-19T16:41:11.685Z", "updated_at": "2019-08-20T11:59:46.086Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "13649-move-dependency-scanning-reports-logic-for-the-merge-request-widget-to-the-backend-frontend-part", "user_notes_count": 1, "upvotes": 0, "downvotes": 0, "assignee": null, "author": { "id": 1125848, "name": "Sam Beckham", "username": "samdbeckham", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/359be2b7660c7b7542d63c41b507537d?s=80&d=identicon", "web_url": "https://gitlab.com/samdbeckham" }, "assignees": [], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "backstage", "dependency scanning", "devops::secure", "frontend", "sub-issue", "workflow::ready for development" ], "work_in_progress": true, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "b2e35301e997a6b2eb7abacfb3943fd33532985c", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": null, "reference": "!15406", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15406", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 0 }, "approvals_before_merge": null }, { "id": 35269469, "iid": 15404, "project_id": 278964, "title": "Fix broken link to Security Dashboard help page", "description": "## What does this MR do?\n\nFixes broken link to help docs for ~\"security dashboard\"\n\n## Does this MR meet the acceptance criteria?\n\n### Conformity\n\n- [x] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) \n- [x] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html) or [follow-up review issue created](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review)\n- [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)\n- [ ] [Merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)\n- [ ] [Style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/development/contributing/style_guides.md)\n- [ ] [Database guides](https://docs.gitlab.com/ee/development/README.html#databases-guides)\n- [ ] [Separation of EE specific content](https://docs.gitlab.com/ee/development/ee_features.html#separation-of-ee-code)\n\n### Performance and Testing\n\n\n\n\n\n- [ ] [Review and add/update tests for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html). Consider [all test levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html). See the [Test Planning Process](https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/).\n- [ ] [Tested in all supported browsers](https://docs.gitlab.com/ee/install/requirements.html#supported-web-browsers)\n\n### Security\n\nIf this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review):\n\n- [ ] Label as ~security and @ mention `@gitlab-com/gl-security/appsec`\n- [ ] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods\n- [ ] Security reports checked/validated by a reviewer from the AppSec team", "state": "opened", "created_at": "2019-08-19T16:26:00.171Z", "updated_at": "2019-08-19T18:22:05.236Z", "merged_by": null, "merged_at": null, "closed_by": null, "closed_at": null, "target_branch": "master", "source_branch": "13645-fix-broken-sec-dashboard-help-link", "user_notes_count": 2, "upvotes": 0, "downvotes": 0, "assignee": { "id": 1125848, "name": "Sam Beckham", "username": "samdbeckham", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/359be2b7660c7b7542d63c41b507537d?s=80&d=identicon", "web_url": "https://gitlab.com/samdbeckham" }, "author": { "id": 401232, "name": "Lucas Charles", "username": "theoretick", "state": "active", "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/401232/squares-nail-wall-art.jpg", "web_url": "https://gitlab.com/theoretick" }, "assignees": [ { "id": 1125848, "name": "Sam Beckham", "username": "samdbeckham", "state": "active", "avatar_url": "https://secure.gravatar.com/avatar/359be2b7660c7b7542d63c41b507537d?s=80&d=identicon", "web_url": "https://gitlab.com/samdbeckham" } ], "source_project_id": 278964, "target_project_id": 278964, "labels": [ "bug", "devops::secure", "group::static analysis" ], "work_in_progress": false, "milestone": { "id": 731038, "iid": 37, "group_id": 9970, "title": "12.3", "description": "", "state": "active", "created_at": "2018-12-07T12:40:55.400Z", "updated_at": "2019-01-16T19:50:20.313Z", "due_date": "2019-09-22", "start_date": "2019-08-08", "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37" }, "merge_when_pipeline_succeeds": false, "merge_status": "can_be_merged", "sha": "e3f350239176eb184accae9c4e380acda787cfbf", "merge_commit_sha": null, "discussion_locked": null, "should_remove_source_branch": null, "force_remove_source_branch": false, "reference": "!15404", "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15404", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "squash": false, "task_completion_status": { "count": 12, "completed_count": 2 }, "approvals_before_merge": 1 } ] golang-github-xanzy-go-gitlab-0.22.2/testdata/get_signature.json000066400000000000000000000003751357140411500247100ustar00rootroot00000000000000{ "gpg_key_id": 7977, "gpg_key_primary_keyid": "627C5F589F467F17", "gpg_key_user_name": "Dmitriy Zaporozhets", "gpg_key_user_email": "dmitriy.zaporozhets@gmail.com", "verification_status": "verified", "gpg_key_subkey_id": null } golang-github-xanzy-go-gitlab-0.22.2/testdata/issue_move.json000066400000000000000000000035661357140411500242330ustar00rootroot00000000000000{ "id": 92, "iid": 11, "project_id": 5, "title": "Sit voluptas tempora quisquam aut doloribus et.", "description": "Repellat voluptas quibusdam voluptatem exercitationem.", "state": "opened", "created_at": "2016-04-05T21:41:45.652Z", "updated_at": "2016-04-07T12:20:17.596Z", "closed_at": null, "closed_by": null, "labels": [], "upvotes": 4, "downvotes": 0, "merge_requests_count": 0, "milestone": null, "assignees": [{ "name": "Miss Monserrate Beier", "username": "axel.block", "id": 12, "state": "active", "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon", "web_url": "https://gitlab.example.com/axel.block" }], "assignee": { "name": "Miss Monserrate Beier", "username": "axel.block", "id": 12, "state": "active", "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon", "web_url": "https://gitlab.example.com/axel.block" }, "author": { "name": "Kris Steuber", "username": "solon.cremin", "id": 10, "state": "active", "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "web_url": "https://gitlab.example.com/solon.cremin" }, "due_date": null, "web_url": "http://example.com/example/example/issues/11", "time_stats": { "time_estimate": 0, "total_time_spent": 0, "human_time_estimate": null, "human_total_time_spent": null }, "confidential": false, "discussion_locked": false, "_links": { "self": "http://example.com/api/v4/projects/1/issues/2", "notes": "http://example.com/api/v4/projects/1/issues/2/notes", "award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji", "project": "http://example.com/api/v4/projects/1" }, "task_completion_status":{ "count":0, "completed_count":0 } } golang-github-xanzy-go-gitlab-0.22.2/testdata/list_todos.json000066400000000000000000000003601357140411500242250ustar00rootroot00000000000000[ { "id": 1, "state": "pending", "target": { "id": 1, "approvals_before_merge": 2 } }, { "id": 2, "state": "pending", "target": { "id": 2, "approvals_before_merge": null } } ] golang-github-xanzy-go-gitlab-0.22.2/testdata/search_users.json000066400000000000000000000003601357140411500245300ustar00rootroot00000000000000[ { "id": 1, "name": "John Doe1", "username": "user1", "state": "active", "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", "web_url": "http://localhost/user1" } ] golang-github-xanzy-go-gitlab-0.22.2/time_stats.go000066400000000000000000000110561357140411500220450ustar00rootroot00000000000000package gitlab import ( "fmt" ) // timeStatsService handles communication with the time tracking related // methods of the GitLab API. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html type timeStatsService struct { client *Client } // TimeStats represents the time estimates and time spent for an issue. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html type TimeStats struct { HumanTimeEstimate string `json:"human_time_estimate"` HumanTotalTimeSpent string `json:"human_total_time_spent"` TimeEstimate int `json:"time_estimate"` TotalTimeSpent int `json:"total_time_spent"` } func (t TimeStats) String() string { return Stringify(t) } // SetTimeEstimateOptions represents the available SetTimeEstimate() // options. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html type SetTimeEstimateOptions struct { Duration *string `url:"duration,omitempty" json:"duration,omitempty"` } // setTimeEstimate sets the time estimate for a single project issue. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html func (s *timeStatsService) setTimeEstimate(pid interface{}, entity string, issue int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/time_estimate", pathEscape(project), entity, issue) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } t := new(TimeStats) resp, err := s.client.Do(req, t) if err != nil { return nil, resp, err } return t, resp, err } // resetTimeEstimate resets the time estimate for a single project issue. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html func (s *timeStatsService) resetTimeEstimate(pid interface{}, entity string, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/reset_time_estimate", pathEscape(project), entity, issue) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } t := new(TimeStats) resp, err := s.client.Do(req, t) if err != nil { return nil, resp, err } return t, resp, err } // AddSpentTimeOptions represents the available AddSpentTime() options. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html type AddSpentTimeOptions struct { Duration *string `url:"duration,omitempty" json:"duration,omitempty"` } // addSpentTime adds spent time for a single project issue. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html func (s *timeStatsService) addSpentTime(pid interface{}, entity string, issue int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/add_spent_time", pathEscape(project), entity, issue) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } t := new(TimeStats) resp, err := s.client.Do(req, t) if err != nil { return nil, resp, err } return t, resp, err } // resetSpentTime resets the spent time for a single project issue. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html func (s *timeStatsService) resetSpentTime(pid interface{}, entity string, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/reset_spent_time", pathEscape(project), entity, issue) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, nil, err } t := new(TimeStats) resp, err := s.client.Do(req, t) if err != nil { return nil, resp, err } return t, resp, err } // getTimeSpent gets the spent time for a single project issue. // // GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html func (s *timeStatsService) getTimeSpent(pid interface{}, entity string, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/%s/%d/time_stats", pathEscape(project), entity, issue) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } t := new(TimeStats) resp, err := s.client.Do(req, t) if err != nil { return nil, resp, err } return t, resp, err } golang-github-xanzy-go-gitlab-0.22.2/todos.go000066400000000000000000000140211357140411500210140ustar00rootroot00000000000000package gitlab import "time" import "fmt" // TodosService handles communication with the todos related methods of // the Gitlab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/todos.html type TodosService struct { client *Client } // TodoAction represents the available actions that can be performed on a todo. // // GitLab API docs: https://docs.gitlab.com/ce/api/todos.html type TodoAction string // The available todo actions. const ( TodoAssigned TodoAction = "assigned" TodoMentioned TodoAction = "mentioned" TodoBuildFailed TodoAction = "build_failed" TodoMarked TodoAction = "marked" TodoApprovalRequired TodoAction = "approval_required" TodoDirectlyAddressed TodoAction = "directly_addressed" ) // TodoTarget represents a todo target of type Issue or MergeRequest type TodoTarget struct { // TODO: replace both Assignee and Author structs with v4 User struct Assignee struct { Name string `json:"name"` Username string `json:"username"` ID int `json:"id"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"assignee"` Author struct { Name string `json:"name"` Username string `json:"username"` ID int `json:"id"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"author"` CreatedAt *time.Time `json:"created_at"` Description string `json:"description"` Downvotes int `json:"downvotes"` ID int `json:"id"` IID int `json:"iid"` Labels []string `json:"labels"` Milestone Milestone `json:"milestone"` ProjectID int `json:"project_id"` State string `json:"state"` Subscribed bool `json:"subscribed"` Title string `json:"title"` UpdatedAt *time.Time `json:"updated_at"` Upvotes int `json:"upvotes"` UserNotesCount int `json:"user_notes_count"` WebURL string `json:"web_url"` // Only available for type Issue Confidential bool `json:"confidential"` DueDate string `json:"due_date"` Weight int `json:"weight"` // Only available for type MergeRequest ApprovalsBeforeMerge int `json:"approvals_before_merge"` ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` MergeCommitSHA string `json:"merge_commit_sha"` MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` MergeStatus string `json:"merge_status"` SHA string `json:"sha"` ShouldRemoveSourceBranch bool `json:"should_remove_source_branch"` SourceBranch string `json:"source_branch"` SourceProjectID int `json:"source_project_id"` Squash bool `json:"squash"` TargetBranch string `json:"target_branch"` TargetProjectID int `json:"target_project_id"` WorkInProgress bool `json:"work_in_progress"` } // Todo represents a GitLab todo. // // GitLab API docs: https://docs.gitlab.com/ce/api/todos.html type Todo struct { ID int `json:"id"` Project struct { ID int `json:"id"` HTTPURLToRepo string `json:"http_url_to_repo"` WebURL string `json:"web_url"` Name string `json:"name"` NameWithNamespace string `json:"name_with_namespace"` Path string `json:"path"` PathWithNamespace string `json:"path_with_namespace"` } `json:"project"` Author struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` State string `json:"state"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } `json:"author"` ActionName TodoAction `json:"action_name"` TargetType string `json:"target_type"` Target TodoTarget `json:"target"` TargetURL string `json:"target_url"` Body string `json:"body"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` } func (t Todo) String() string { return Stringify(t) } // ListTodosOptions represents the available ListTodos() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos type ListTodosOptions struct { ListOptions Action *TodoAction `url:"action,omitempty" json:"action,omitempty"` AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` ProjectID *int `url:"project_id,omitempty" json:"project_id,omitempty"` State *string `url:"state,omitempty" json:"state,omitempty"` Type *string `url:"type,omitempty" json:"type,omitempty"` } // ListTodos lists all todos created by authenticated user. // When no filter is applied, it returns all pending todos for the current user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos func (s *TodosService) ListTodos(opt *ListTodosOptions, options ...OptionFunc) ([]*Todo, *Response, error) { req, err := s.client.NewRequest("GET", "todos", opt, options) if err != nil { return nil, nil, err } var t []*Todo resp, err := s.client.Do(req, &t) if err != nil { return nil, resp, err } return t, resp, err } // MarkTodoAsDone marks a single pending todo given by its ID for the current user as done. // // GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-a-todo-as-done func (s *TodosService) MarkTodoAsDone(id int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("todos/%d/mark_as_done", id) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // MarkAllTodosAsDone marks all pending todos for the current user as done. // // GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-all-todos-as-done func (s *TodosService) MarkAllTodosAsDone(options ...OptionFunc) (*Response, error) { req, err := s.client.NewRequest("POST", "todos/mark_as_done", nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } golang-github-xanzy-go-gitlab-0.22.2/todos_test.go000066400000000000000000000024311357140411500220550ustar00rootroot00000000000000package gitlab import ( "net/http" "testing" "github.com/stretchr/testify/require" ) func TestListTodos(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/todos", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") mustWriteHTTPResponse(t, w, "testdata/list_todos.json") }) opts := &ListTodosOptions{ListOptions: ListOptions{PerPage: 2}} todos, _, err := client.Todos.ListTodos(opts) require.NoError(t, err) want := []*Todo{{ID: 1, State: "pending", Target: TodoTarget{ID: 1, ApprovalsBeforeMerge: 2}}, {ID: 2, State: "pending", Target: TodoTarget{ID: 2}}} require.Equal(t, want, todos) } func TestMarkAllTodosAsDone(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/todos/mark_as_done", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusNoContent) }) _, err := client.Todos.MarkAllTodosAsDone() require.NoError(t, err) } func TestMarkTodoAsDone(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/todos/1/mark_as_done", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") }) _, err := client.Todos.MarkTodoAsDone(1) require.NoError(t, err) } golang-github-xanzy-go-gitlab-0.22.2/users.go000066400000000000000000000700311357140411500210300ustar00rootroot00000000000000// // Copyright 2017, Sander van Harmelen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab import ( "errors" "fmt" "time" ) // List a couple of standard errors. var ( ErrUserBlockPrevented = errors.New("Cannot block a user that is already blocked by LDAP synchronization") ErrUserNotFound = errors.New("User does not exist") ErrUserUnblockPrevented = errors.New("Cannot unblock a user that is blocked by LDAP synchronization") ) // UsersService handles communication with the user related methods of // the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html type UsersService struct { client *Client } // BasicUser included in other service responses (such as merge requests, pipelines, etc). type BasicUser struct { ID int `json:"id"` Username string `json:"username"` Name string `json:"name"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` AvatarURL string `json:"avatar_url"` WebURL string `json:"web_url"` } // User represents a GitLab user. // // GitLab API docs: https://docs.gitlab.com/ee/api/users.html type User struct { ID int `json:"id"` Username string `json:"username"` Email string `json:"email"` Name string `json:"name"` State string `json:"state"` CreatedAt *time.Time `json:"created_at"` Bio string `json:"bio"` Location string `json:"location"` PublicEmail string `json:"public_email"` Skype string `json:"skype"` Linkedin string `json:"linkedin"` Twitter string `json:"twitter"` WebsiteURL string `json:"website_url"` Organization string `json:"organization"` ExternUID string `json:"extern_uid"` Provider string `json:"provider"` ThemeID int `json:"theme_id"` LastActivityOn *ISOTime `json:"last_activity_on"` ColorSchemeID int `json:"color_scheme_id"` IsAdmin bool `json:"is_admin"` AvatarURL string `json:"avatar_url"` CanCreateGroup bool `json:"can_create_group"` CanCreateProject bool `json:"can_create_project"` ProjectsLimit int `json:"projects_limit"` CurrentSignInAt *time.Time `json:"current_sign_in_at"` LastSignInAt *time.Time `json:"last_sign_in_at"` ConfirmedAt *time.Time `json:"confirmed_at"` TwoFactorEnabled bool `json:"two_factor_enabled"` Identities []*UserIdentity `json:"identities"` External bool `json:"external"` PrivateProfile bool `json:"private_profile"` SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"` CustomAttributes []*CustomAttribute `json:"custom_attributes"` } // UserIdentity represents a user identity. type UserIdentity struct { Provider string `json:"provider"` ExternUID string `json:"extern_uid"` } // ListUsersOptions represents the available ListUsers() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users type ListUsersOptions struct { ListOptions Active *bool `url:"active,omitempty" json:"active,omitempty"` Blocked *bool `url:"blocked,omitempty" json:"blocked,omitempty"` // The options below are only available for admins. Search *string `url:"search,omitempty" json:"search,omitempty"` Username *string `url:"username,omitempty" json:"username,omitempty"` ExternalUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` Provider *string `url:"provider,omitempty" json:"provider,omitempty"` CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` } // ListUsers gets a list of users. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users func (s *UsersService) ListUsers(opt *ListUsersOptions, options ...OptionFunc) ([]*User, *Response, error) { req, err := s.client.NewRequest("GET", "users", opt, options) if err != nil { return nil, nil, err } var usr []*User resp, err := s.client.Do(req, &usr) if err != nil { return nil, resp, err } return usr, resp, err } // GetUser gets a single user. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-user func (s *UsersService) GetUser(user int, options ...OptionFunc) (*User, *Response, error) { u := fmt.Sprintf("users/%d", user) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } usr := new(User) resp, err := s.client.Do(req, usr) if err != nil { return nil, resp, err } return usr, resp, err } // CreateUserOptions represents the available CreateUser() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation type CreateUserOptions struct { Email *string `url:"email,omitempty" json:"email,omitempty"` Password *string `url:"password,omitempty" json:"password,omitempty"` ResetPassword *bool `url:"reset_password,omitempty" json:"reset_password,omitempty"` Username *string `url:"username,omitempty" json:"username,omitempty"` Name *string `url:"name,omitempty" json:"name,omitempty"` Skype *string `url:"skype,omitempty" json:"skype,omitempty"` Linkedin *string `url:"linkedin,omitempty" json:"linkedin,omitempty"` Twitter *string `url:"twitter,omitempty" json:"twitter,omitempty"` WebsiteURL *string `url:"website_url,omitempty" json:"website_url,omitempty"` Organization *string `url:"organization,omitempty" json:"organization,omitempty"` ProjectsLimit *int `url:"projects_limit,omitempty" json:"projects_limit,omitempty"` ExternUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` Provider *string `url:"provider,omitempty" json:"provider,omitempty"` Bio *string `url:"bio,omitempty" json:"bio,omitempty"` Location *string `url:"location,omitempty" json:"location,omitempty"` Admin *bool `url:"admin,omitempty" json:"admin,omitempty"` CanCreateGroup *bool `url:"can_create_group,omitempty" json:"can_create_group,omitempty"` SkipConfirmation *bool `url:"skip_confirmation,omitempty" json:"skip_confirmation,omitempty"` External *bool `url:"external,omitempty" json:"external,omitempty"` PrivateProfile *bool `url:"private_profile,omitempty" json:"private_profile,omitempty"` } // CreateUser creates a new user. Note only administrators can create new users. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation func (s *UsersService) CreateUser(opt *CreateUserOptions, options ...OptionFunc) (*User, *Response, error) { req, err := s.client.NewRequest("POST", "users", opt, options) if err != nil { return nil, nil, err } usr := new(User) resp, err := s.client.Do(req, usr) if err != nil { return nil, resp, err } return usr, resp, err } // ModifyUserOptions represents the available ModifyUser() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification type ModifyUserOptions struct { Email *string `url:"email,omitempty" json:"email,omitempty"` Password *string `url:"password,omitempty" json:"password,omitempty"` Username *string `url:"username,omitempty" json:"username,omitempty"` Name *string `url:"name,omitempty" json:"name,omitempty"` Skype *string `url:"skype,omitempty" json:"skype,omitempty"` Linkedin *string `url:"linkedin,omitempty" json:"linkedin,omitempty"` Twitter *string `url:"twitter,omitempty" json:"twitter,omitempty"` WebsiteURL *string `url:"website_url,omitempty" json:"website_url,omitempty"` Organization *string `url:"organization,omitempty" json:"organization,omitempty"` ProjectsLimit *int `url:"projects_limit,omitempty" json:"projects_limit,omitempty"` ExternUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` Provider *string `url:"provider,omitempty" json:"provider,omitempty"` Bio *string `url:"bio,omitempty" json:"bio,omitempty"` Location *string `url:"location,omitempty" json:"location,omitempty"` Admin *bool `url:"admin,omitempty" json:"admin,omitempty"` CanCreateGroup *bool `url:"can_create_group,omitempty" json:"can_create_group,omitempty"` SkipReconfirmation *bool `url:"skip_reconfirmation,omitempty" json:"skip_reconfirmation,omitempty"` External *bool `url:"external,omitempty" json:"external,omitempty"` PrivateProfile *bool `url:"private_profile,omitempty" json:"private_profile,omitempty"` } // ModifyUser modifies an existing user. Only administrators can change attributes // of a user. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification func (s *UsersService) ModifyUser(user int, opt *ModifyUserOptions, options ...OptionFunc) (*User, *Response, error) { u := fmt.Sprintf("users/%d", user) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } usr := new(User) resp, err := s.client.Do(req, usr) if err != nil { return nil, resp, err } return usr, resp, err } // DeleteUser deletes a user. Available only for administrators. This is an // idempotent function, calling this function for a non-existent user id still // returns a status code 200 OK. The JSON response differs if the user was // actually deleted or not. In the former the user is returned and in the // latter not. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-deletion func (s *UsersService) DeleteUser(user int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("users/%d", user) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // CurrentUser gets currently authenticated user. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#current-user func (s *UsersService) CurrentUser(options ...OptionFunc) (*User, *Response, error) { req, err := s.client.NewRequest("GET", "user", nil, options) if err != nil { return nil, nil, err } usr := new(User) resp, err := s.client.Do(req, usr) if err != nil { return nil, resp, err } return usr, resp, err } // SSHKey represents a SSH key. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys type SSHKey struct { ID int `json:"id"` Title string `json:"title"` Key string `json:"key"` CreatedAt *time.Time `json:"created_at"` } // ListSSHKeys gets a list of currently authenticated user's SSH keys. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys func (s *UsersService) ListSSHKeys(options ...OptionFunc) ([]*SSHKey, *Response, error) { req, err := s.client.NewRequest("GET", "user/keys", nil, options) if err != nil { return nil, nil, err } var k []*SSHKey resp, err := s.client.Do(req, &k) if err != nil { return nil, resp, err } return k, resp, err } // ListSSHKeysForUserOptions represents the available ListSSHKeysForUser() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user type ListSSHKeysForUserOptions ListOptions // ListSSHKeysForUser gets a list of a specified user's SSH keys. Available // only for admin // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user func (s *UsersService) ListSSHKeysForUser(user int, opt *ListSSHKeysForUserOptions, options ...OptionFunc) ([]*SSHKey, *Response, error) { u := fmt.Sprintf("users/%d/keys", user) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var k []*SSHKey resp, err := s.client.Do(req, &k) if err != nil { return nil, resp, err } return k, resp, err } // GetSSHKey gets a single key. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-ssh-key func (s *UsersService) GetSSHKey(key int, options ...OptionFunc) (*SSHKey, *Response, error) { u := fmt.Sprintf("user/keys/%d", key) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } k := new(SSHKey) resp, err := s.client.Do(req, k) if err != nil { return nil, resp, err } return k, resp, err } // AddSSHKeyOptions represents the available AddSSHKey() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-ssh-key type AddSSHKeyOptions struct { Title *string `url:"title,omitempty" json:"title,omitempty"` Key *string `url:"key,omitempty" json:"key,omitempty"` } // AddSSHKey creates a new key owned by the currently authenticated user. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key func (s *UsersService) AddSSHKey(opt *AddSSHKeyOptions, options ...OptionFunc) (*SSHKey, *Response, error) { req, err := s.client.NewRequest("POST", "user/keys", opt, options) if err != nil { return nil, nil, err } k := new(SSHKey) resp, err := s.client.Do(req, k) if err != nil { return nil, resp, err } return k, resp, err } // AddSSHKeyForUser creates new key owned by specified user. Available only for // admin. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key-for-user func (s *UsersService) AddSSHKeyForUser(user int, opt *AddSSHKeyOptions, options ...OptionFunc) (*SSHKey, *Response, error) { u := fmt.Sprintf("users/%d/keys", user) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } k := new(SSHKey) resp, err := s.client.Do(req, k) if err != nil { return nil, resp, err } return k, resp, err } // DeleteSSHKey deletes key owned by currently authenticated user. This is an // idempotent function and calling it on a key that is already deleted or not // available results in 200 OK. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-current-owner func (s *UsersService) DeleteSSHKey(key int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("user/keys/%d", key) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteSSHKeyForUser deletes key owned by a specified user. Available only // for admin. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-given-user func (s *UsersService) DeleteSSHKeyForUser(user, key int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("users/%d/keys/%d", user, key) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // BlockUser blocks the specified user. Available only for admin. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#block-user func (s *UsersService) BlockUser(user int, options ...OptionFunc) error { u := fmt.Sprintf("users/%d/block", user) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return err } resp, err := s.client.Do(req, nil) if err != nil && resp == nil { return err } switch resp.StatusCode { case 201: return nil case 403: return ErrUserBlockPrevented case 404: return ErrUserNotFound default: return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) } } // UnblockUser unblocks the specified user. Available only for admin. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#unblock-user func (s *UsersService) UnblockUser(user int, options ...OptionFunc) error { u := fmt.Sprintf("users/%d/unblock", user) req, err := s.client.NewRequest("POST", u, nil, options) if err != nil { return err } resp, err := s.client.Do(req, nil) if err != nil && resp == nil { return err } switch resp.StatusCode { case 201: return nil case 403: return ErrUserUnblockPrevented case 404: return ErrUserNotFound default: return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) } } // Email represents an Email. // // GitLab API docs: https://doc.gitlab.com/ce/api/users.html#list-emails type Email struct { ID int `json:"id"` Email string `json:"email"` } // ListEmails gets a list of currently authenticated user's Emails. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-emails func (s *UsersService) ListEmails(options ...OptionFunc) ([]*Email, *Response, error) { req, err := s.client.NewRequest("GET", "user/emails", nil, options) if err != nil { return nil, nil, err } var e []*Email resp, err := s.client.Do(req, &e) if err != nil { return nil, resp, err } return e, resp, err } // ListEmailsForUserOptions represents the available ListEmailsForUser() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#list-emails-for-user type ListEmailsForUserOptions ListOptions // ListEmailsForUser gets a list of a specified user's Emails. Available // only for admin // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#list-emails-for-user func (s *UsersService) ListEmailsForUser(user int, opt *ListEmailsForUserOptions, options ...OptionFunc) ([]*Email, *Response, error) { u := fmt.Sprintf("users/%d/emails", user) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var e []*Email resp, err := s.client.Do(req, &e) if err != nil { return nil, resp, err } return e, resp, err } // GetEmail gets a single email. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-email func (s *UsersService) GetEmail(email int, options ...OptionFunc) (*Email, *Response, error) { u := fmt.Sprintf("user/emails/%d", email) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } e := new(Email) resp, err := s.client.Do(req, e) if err != nil { return nil, resp, err } return e, resp, err } // AddEmailOptions represents the available AddEmail() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-email type AddEmailOptions struct { Email *string `url:"email,omitempty" json:"email,omitempty"` } // AddEmail creates a new email owned by the currently authenticated user. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email func (s *UsersService) AddEmail(opt *AddEmailOptions, options ...OptionFunc) (*Email, *Response, error) { req, err := s.client.NewRequest("POST", "user/emails", opt, options) if err != nil { return nil, nil, err } e := new(Email) resp, err := s.client.Do(req, e) if err != nil { return nil, resp, err } return e, resp, err } // AddEmailForUser creates new email owned by specified user. Available only for // admin. // // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email-for-user func (s *UsersService) AddEmailForUser(user int, opt *AddEmailOptions, options ...OptionFunc) (*Email, *Response, error) { u := fmt.Sprintf("users/%d/emails", user) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } e := new(Email) resp, err := s.client.Do(req, e) if err != nil { return nil, resp, err } return e, resp, err } // DeleteEmail deletes email owned by currently authenticated user. This is an // idempotent function and calling it on a key that is already deleted or not // available results in 200 OK. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#delete-email-for-current-owner func (s *UsersService) DeleteEmail(email int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("user/emails/%d", email) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // DeleteEmailForUser deletes email owned by a specified user. Available only // for admin. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#delete-email-for-given-user func (s *UsersService) DeleteEmailForUser(user, email int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("users/%d/emails/%d", user, email) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // ImpersonationToken represents an impersonation token. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user type ImpersonationToken struct { ID int `json:"id"` Name string `json:"name"` Active bool `json:"active"` Token string `json:"token"` Scopes []string `json:"scopes"` Revoked bool `json:"revoked"` CreatedAt *time.Time `json:"created_at"` ExpiresAt *ISOTime `json:"expires_at"` } // GetAllImpersonationTokensOptions represents the available // GetAllImpersonationTokens() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user type GetAllImpersonationTokensOptions struct { ListOptions State *string `url:"state,omitempty" json:"state,omitempty"` } // GetAllImpersonationTokens retrieves all impersonation tokens of a user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user func (s *UsersService) GetAllImpersonationTokens(user int, opt *GetAllImpersonationTokensOptions, options ...OptionFunc) ([]*ImpersonationToken, *Response, error) { u := fmt.Sprintf("users/%d/impersonation_tokens", user) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var ts []*ImpersonationToken resp, err := s.client.Do(req, &ts) if err != nil { return nil, resp, err } return ts, resp, err } // GetImpersonationToken retrieves an impersonation token of a user. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#get-an-impersonation-token-of-a-user func (s *UsersService) GetImpersonationToken(user, token int, options ...OptionFunc) (*ImpersonationToken, *Response, error) { u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } t := new(ImpersonationToken) resp, err := s.client.Do(req, &t) if err != nil { return nil, resp, err } return t, resp, err } // CreateImpersonationTokenOptions represents the available // CreateImpersonationToken() options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token type CreateImpersonationTokenOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Scopes *[]string `url:"scopes,omitempty" json:"scopes,omitempty"` ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"` } // CreateImpersonationToken creates an impersonation token. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token func (s *UsersService) CreateImpersonationToken(user int, opt *CreateImpersonationTokenOptions, options ...OptionFunc) (*ImpersonationToken, *Response, error) { u := fmt.Sprintf("users/%d/impersonation_tokens", user) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } t := new(ImpersonationToken) resp, err := s.client.Do(req, &t) if err != nil { return nil, resp, err } return t, resp, err } // RevokeImpersonationToken revokes an impersonation token. // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#revoke-an-impersonation-token func (s *UsersService) RevokeImpersonationToken(user, token int, options ...OptionFunc) (*Response, error) { u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) } // UserActivity represents an entry in the user/activities response // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only type UserActivity struct { Username string `json:"username"` LastActivityOn *ISOTime `json:"last_activity_on"` } // GetUserActivitiesOptions represents the options for GetUserActivities // // GitLap API docs: // https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only type GetUserActivitiesOptions struct { From *ISOTime `url:"from,omitempty" json:"from,omitempty"` } // GetUserActivities retrieves user activities (admin only) // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only func (s *UsersService) GetUserActivities(opt *GetUserActivitiesOptions, options ...OptionFunc) ([]*UserActivity, *Response, error) { req, err := s.client.NewRequest("GET", "user/activities", opt, options) if err != nil { return nil, nil, err } var t []*UserActivity resp, err := s.client.Do(req, &t) if err != nil { return nil, resp, err } return t, resp, err } // UserStatus represents the current status of a user // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#user-status type UserStatus struct { Emoji string `json:"emoji"` Message string `json:"message"` MessageHTML string `json:"message_html"` } // CurrentUserStatus retrieves the user status // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#user-status func (s *UsersService) CurrentUserStatus(options ...OptionFunc) (*UserStatus, *Response, error) { req, err := s.client.NewRequest("GET", "user/status", nil, options) if err != nil { return nil, nil, err } status := new(UserStatus) resp, err := s.client.Do(req, status) if err != nil { return nil, resp, err } return status, resp, err } // GetUserStatus retrieves a user's status // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#get-the-status-of-a-user func (s *UsersService) GetUserStatus(user int, options ...OptionFunc) (*UserStatus, *Response, error) { u := fmt.Sprintf("users/%d/status", user) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } status := new(UserStatus) resp, err := s.client.Do(req, status) if err != nil { return nil, resp, err } return status, resp, err } // UserStatusOptions represents the options required to set the status // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#set-user-status type UserStatusOptions struct { Emoji *string `url:"emoji,omitempty" json:"emoji,omitempty"` Message *string `url:"message,omitempty" json:"message,omitempty"` } // SetUserStatus sets the user's status // // GitLab API docs: // https://docs.gitlab.com/ce/api/users.html#set-user-status func (s *UsersService) SetUserStatus(opt *UserStatusOptions, options ...OptionFunc) (*UserStatus, *Response, error) { req, err := s.client.NewRequest("PUT", "user/status", opt, options) if err != nil { return nil, nil, err } status := new(UserStatus) resp, err := s.client.Do(req, status) if err != nil { return nil, resp, err } return status, resp, err } golang-github-xanzy-go-gitlab-0.22.2/users_test.go000066400000000000000000000107671357140411500221010ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestBlockUser(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/block", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusCreated) }) err := client.Users.BlockUser(1) if err != nil { t.Errorf("Users.BlockUser returned error: %v", err) } } func TestBlockUser_UserNotFound(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/block", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusNotFound) }) err := client.Users.BlockUser(1) if err != ErrUserNotFound { t.Errorf("Users.BlockUser error.\nExpected: %+v\n Got: %+v", ErrUserNotFound, err) } } func TestBlockUser_BlockPrevented(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/block", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusForbidden) }) err := client.Users.BlockUser(1) if err != ErrUserBlockPrevented { t.Errorf("Users.BlockUser error.\nExpected: %+v\n Got: %+v", ErrUserBlockPrevented, err) } } func TestBlockUser_UnknownError(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/block", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusTeapot) }) want := fmt.Errorf("Received unexpected result code: %d", http.StatusTeapot) err := client.Users.BlockUser(1) if !reflect.DeepEqual(err, want) { t.Errorf("Users.BlockUser error.\nExpected: %+v\n Got: %+v", want, err) } } func TestBlockUser_BadResponseFromNet(t *testing.T) { client := NewClient(nil, "") client.SetBaseURL("") want := fmt.Sprintf("Post /%susers/1/block: unsupported protocol scheme \"\"", apiVersionPath) err := client.Users.BlockUser(1) if err.Error() != want { t.Errorf("Users.BlockUser error.\nExpected: %+v\n Got: %+v", want, err) } } // ------------------------ Unblock user ------------------------- func TestUnblockUser(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/unblock", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusCreated) }) err := client.Users.UnblockUser(1) if err != nil { t.Errorf("Users.UnblockUser returned error: %v", err) } } func TestUnblockUser_UserNotFound(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/unblock", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusNotFound) }) err := client.Users.UnblockUser(1) if err != ErrUserNotFound { t.Errorf("Users.UnblockUser error.\nExpected: %+v\n Got: %+v", ErrUserNotFound, err) } } func TestUnblockUser_UnblockPrevented(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/unblock", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusForbidden) }) err := client.Users.UnblockUser(1) if err != ErrUserUnblockPrevented { t.Errorf("Users.UnblockUser error.\nExpected: %+v\n Got: %+v", ErrUserUnblockPrevented, err) } } func TestUnblockUser_UnknownError(t *testing.T) { mux, server, client := setup() defer teardown(server) path := fmt.Sprintf("/%susers/1/unblock", apiVersionPath) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") w.WriteHeader(http.StatusTeapot) }) want := fmt.Errorf("Received unexpected result code: %d", http.StatusTeapot) err := client.Users.UnblockUser(1) if !reflect.DeepEqual(err, want) { t.Errorf("Users.UnblockUser error.\nExpected: %+v\n Got: %+v", want, err) } } func TestUnblockUser_BadResponseFromNet(t *testing.T) { client := NewClient(nil, "") client.SetBaseURL("") want := fmt.Sprintf("Post /%susers/1/unblock: unsupported protocol scheme \"\"", apiVersionPath) err := client.Users.UnblockUser(1) if err.Error() != want { t.Errorf("Users.UnblockUser error.\nExpected: %+v\n Got: %+v", want, err) } } golang-github-xanzy-go-gitlab-0.22.2/validate.go000066400000000000000000000017411357140411500214620ustar00rootroot00000000000000package gitlab // ValidateService handles communication with the validation related methods of // the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/lint.html type ValidateService struct { client *Client } // LintResult represents the linting results. // // GitLab API docs: https://docs.gitlab.com/ce/api/lint.html type LintResult struct { Status string `json:"status"` Errors []string `json:"errors"` } // Lint validates .gitlab-ci.yml content. // // GitLab API docs: https://docs.gitlab.com/ce/api/lint.html func (s *ValidateService) Lint(content string, options ...OptionFunc) (*LintResult, *Response, error) { var opts struct { Content string `url:"content,omitempty" json:"content,omitempty"` } opts.Content = content req, err := s.client.NewRequest("POST", "ci/lint", &opts, options) if err != nil { return nil, nil, err } l := new(LintResult) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err } return l, resp, nil } golang-github-xanzy-go-gitlab-0.22.2/validate_test.go000066400000000000000000000025431357140411500225220ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestValidate(t *testing.T) { testCases := []struct { description string content string response string want *LintResult }{ { description: "valid", content: ` build1: stage: build script: - echo "Do your build here"`, response: `{ "status": "valid", "errors": [] }`, want: &LintResult{ Status: "valid", Errors: []string{}, }, }, { description: "invalid", content: ` build1: - echo "Do your build here"`, response: `{ "status": "invalid", "errors": ["error message when content is invalid"] }`, want: &LintResult{ Status: "invalid", Errors: []string{"error message when content is invalid"}, }, }, } for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/ci/lint", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "POST") fmt.Fprint(w, tc.response) }) got, _, err := client.Validate.Lint(tc.content) if err != nil { t.Errorf("Validate returned error: %v", err) } want := tc.want if !reflect.DeepEqual(got, want) { t.Errorf("Validate returned \ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want)) } }) } } golang-github-xanzy-go-gitlab-0.22.2/version.go000066400000000000000000000030621357140411500213540ustar00rootroot00000000000000// // Copyright 2017, Andrea Funto' // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package gitlab // VersionService handles communication with the GitLab server instance to // retrieve its version information via the GitLab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/version.md type VersionService struct { client *Client } // Version represents a GitLab instance version. // // GitLab API docs: https://docs.gitlab.com/ce/api/version.md type Version struct { Version string `json:"version"` Revision string `json:"revision"` } func (s Version) String() string { return Stringify(s) } // GetVersion gets a GitLab server instance version; it is only available to // authenticated users. // // GitLab API docs: https://docs.gitlab.com/ce/api/version.md func (s *VersionService) GetVersion() (*Version, *Response, error) { req, err := s.client.NewRequest("GET", "version", nil, nil) if err != nil { return nil, nil, err } v := new(Version) resp, err := s.client.Do(req, v) if err != nil { return nil, resp, err } return v, resp, err } golang-github-xanzy-go-gitlab-0.22.2/version_test.go000066400000000000000000000012101357140411500224040ustar00rootroot00000000000000package gitlab import ( "fmt" "net/http" "reflect" "testing" ) func TestGetVersion(t *testing.T) { mux, server, client := setup() defer teardown(server) mux.HandleFunc("/api/v4/version", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"version":"11.3.4-ee", "revision":"14d3a1d"}`) }) version, _, err := client.Version.GetVersion() if err != nil { t.Errorf("Version.GetVersion returned error: %v", err) } want := &Version{Version: "11.3.4-ee", Revision: "14d3a1d"} if !reflect.DeepEqual(want, version) { t.Errorf("Version.GetVersion returned %+v, want %+v", version, want) } } golang-github-xanzy-go-gitlab-0.22.2/wikis.go000066400000000000000000000131321357140411500210140ustar00rootroot00000000000000// Copyright 2017, Stany MARCEL // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gitlab import ( "fmt" "net/url" ) // WikisService handles communication with the wikis related methods of // the Gitlab API. // // GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html type WikisService struct { client *Client } // WikiFormat represents the available wiki formats. // // GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html type WikiFormat string // The available wiki formats. const ( WikiFormatMarkdown WikiFormat = "markdown" WikiFormatRFoc WikiFormat = "rdoc" WikiFormatASCIIDoc WikiFormat = "asciidoc" ) // Wiki represents a GitLab wiki. // // GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html type Wiki struct { Content string `json:"content"` Format WikiFormat `json:"format"` Slug string `json:"slug"` Title string `json:"title"` } func (w Wiki) String() string { return Stringify(w) } // ListWikisOptions represents the available ListWikis options. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages type ListWikisOptions struct { WithContent *bool `url:"with_content,omitempty" json:"with_content,omitempty"` } // ListWikis lists all pages of the wiki of the given project id. // When with_content is set, it also returns the content of the pages. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages func (s *WikisService) ListWikis(pid interface{}, opt *ListWikisOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/wikis", pathEscape(project)) req, err := s.client.NewRequest("GET", u, opt, options) if err != nil { return nil, nil, err } var w []*Wiki resp, err := s.client.Do(req, &w) if err != nil { return nil, resp, err } return w, resp, err } // GetWikiPage gets a wiki page for a given project. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#get-a-wiki-page func (s *WikisService) GetWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Wiki, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/wikis/%s", pathEscape(project), url.PathEscape(slug)) req, err := s.client.NewRequest("GET", u, nil, options) if err != nil { return nil, nil, err } var w *Wiki resp, err := s.client.Do(req, &w) if err != nil { return nil, resp, err } return w, resp, err } // CreateWikiPageOptions represents options to CreateWikiPage. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page type CreateWikiPageOptions struct { Content *string `url:"content" json:"content"` Title *string `url:"title" json:"title"` Format *string `url:"format,omitempty" json:"format,omitempty"` } // CreateWikiPage creates a new wiki page for the given repository with // the given title, slug, and content. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page func (s *WikisService) CreateWikiPage(pid interface{}, opt *CreateWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/wikis", pathEscape(project)) req, err := s.client.NewRequest("POST", u, opt, options) if err != nil { return nil, nil, err } w := new(Wiki) resp, err := s.client.Do(req, w) if err != nil { return nil, resp, err } return w, resp, err } // EditWikiPageOptions represents options to EditWikiPage. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page type EditWikiPageOptions struct { Content *string `url:"content" json:"content"` Title *string `url:"title" json:"title"` Format *string `url:"format,omitempty" json:"format,omitempty"` } // EditWikiPage Updates an existing wiki page. At least one parameter is // required to update the wiki page. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page func (s *WikisService) EditWikiPage(pid interface{}, slug string, opt *EditWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) { project, err := parseID(pid) if err != nil { return nil, nil, err } u := fmt.Sprintf("projects/%s/wikis/%s", pathEscape(project), url.PathEscape(slug)) req, err := s.client.NewRequest("PUT", u, opt, options) if err != nil { return nil, nil, err } w := new(Wiki) resp, err := s.client.Do(req, w) if err != nil { return nil, resp, err } return w, resp, err } // DeleteWikiPage deletes a wiki page with a given slug. // // GitLab API docs: // https://docs.gitlab.com/ce/api/wikis.html#delete-a-wiki-page func (s *WikisService) DeleteWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Response, error) { project, err := parseID(pid) if err != nil { return nil, err } u := fmt.Sprintf("projects/%s/wikis/%s", pathEscape(project), url.PathEscape(slug)) req, err := s.client.NewRequest("DELETE", u, nil, options) if err != nil { return nil, err } return s.client.Do(req, nil) }