* First stab at a Gitlab migrations interface. * Modify JS to show migration for Gitlab * Properly strip out #gitlab tag from repo name * Working Gitlab migrations! Still need to figure out how to hide tokens/etc from showing up in opts.CloneAddr * Try #2 at trying to hide credentials. CloneAddr was being used as OriginalURL. Now passing OriginalURL through from the form and saving it. * Add go-gitlab dependency * Vendor go-gitlab * Use gitlab.BasicAuthClient Correct CloneURL. This should be functioning! Previous commits fixed "Migrated from" from including the migration credentials. * Replaced repoPath with repoID globally. RepoID is grabbed in NewGitlabDownloader * Logging touchup * Properly set private repo status. Properly set milestone deadline time. Consistently use Gitlab username for 'Name'. * Add go-gitlab vendor cache * Fix PR migrations: - Count of issues is kept to set a non-conflicting PR.ID - Bool is used to tell whether to fetch Issue or PR comments * Ensure merged PRs are closed and set with the proper time * Remove copyright and some commented code * Rip out '#gitlab' based self-hosted Gitlab support * Hide given credentials for migrated repos. CloneAddr was being saved as OriginalURL. Now passing OriginalURL through from the form and saving it in it's place * Use asset.URL directly, no point in parsing. Opened PRs should fall through to false. * Fix importing Milestones. Allow importing using Personal Tokens or anonymous access. * Fix Gitlab Milestone migration if DueDate isn't set * Empty Milestone due dates properly return nil, not zero time * Add GITLAB_READ_TOKEN to drone unit-test step * Add working gitlab_test.go. A Personal Access Token, given in env variable GITLAB_READ_TOKEN is required to run the test. * Fix linting issues * Add modified JS files * Remove pre-build JS files * Only merged PRs are marged as merged/closed * Test topics * Skip test if gitlab is inaccessible * Grab personal token from username, not password. Matches Github migration implementation * Add SetContext() to GitlabDownloader. * Checking Updated field in Issues. * Actually fetch Issue Updated time from Gitlab * Add Gitlab migration GetReviews() stub * Fix Patch and Clone URLs * check Updated too * fix mod * make vendor with go1.14 Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>tags/v1.13.0-dev
| @@ -99,7 +99,19 @@ services: | |||
| image: mysql:5.7 | |||
| environment: | |||
| MYSQL_ALLOW_EMPTY_PASSWORD: yes | |||
| MYSQL_DATABASE: test | |||
| MYSQL_DATABASE: test | |||
| GOPROXY: off | |||
| TAGS: bindata sqlite sqlite_unlock_notify | |||
| GITLAB_READ_TOKEN: | |||
| from_secret: gitlab_read_token | |||
| depends_on: | |||
| - build | |||
| when: | |||
| branch: | |||
| - master | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: mysql8 | |||
| pull: default | |||
| @@ -104,6 +104,7 @@ require ( | |||
| github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6 | |||
| github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141 | |||
| github.com/urfave/cli v1.20.0 | |||
| github.com/xanzy/go-gitlab v0.22.1 | |||
| github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 | |||
| github.com/yuin/goldmark v1.1.25 | |||
| github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 | |||
| @@ -608,6 +608,8 @@ github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= | |||
| github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= | |||
| github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc= | |||
| github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= | |||
| github.com/xanzy/go-gitlab v0.22.1 h1:TVxgHmoa35jQL+9FCkG0nwPDxU9dQZXknBTDtGaSFno= | |||
| github.com/xanzy/go-gitlab v0.22.1/go.mod h1:t4Bmvnxj7k37S4Y17lfLx+nLqkf/oQwT2HagfWKv5Og= | |||
| github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= | |||
| github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= | |||
| github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= | |||
| @@ -669,6 +671,7 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r | |||
| golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| @@ -692,6 +695,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7 | |||
| golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
| golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
| golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
| golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= | |||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
| @@ -770,6 +774,7 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn | |||
| google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= | |||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | |||
| google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| @@ -0,0 +1,539 @@ | |||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "context" | |||
| "errors" | |||
| "fmt" | |||
| "net/http" | |||
| "net/url" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/migrations/base" | |||
| "code.gitea.io/gitea/modules/structs" | |||
| "github.com/xanzy/go-gitlab" | |||
| ) | |||
| var ( | |||
| _ base.Downloader = &GitlabDownloader{} | |||
| _ base.DownloaderFactory = &GitlabDownloaderFactory{} | |||
| ) | |||
| func init() { | |||
| RegisterDownloaderFactory(&GitlabDownloaderFactory{}) | |||
| } | |||
| // GitlabDownloaderFactory defines a gitlab downloader factory | |||
| type GitlabDownloaderFactory struct { | |||
| } | |||
| // Match returns ture if the migration remote URL matched this downloader factory | |||
| func (f *GitlabDownloaderFactory) Match(opts base.MigrateOptions) (bool, error) { | |||
| var matched bool | |||
| u, err := url.Parse(opts.CloneAddr) | |||
| if err != nil { | |||
| return false, err | |||
| } | |||
| if strings.EqualFold(u.Host, "gitlab.com") && opts.AuthUsername != "" { | |||
| matched = true | |||
| } | |||
| return matched, nil | |||
| } | |||
| // New returns a Downloader related to this factory according MigrateOptions | |||
| func (f *GitlabDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader, error) { | |||
| u, err := url.Parse(opts.CloneAddr) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| baseURL := u.Scheme + "://" + u.Host | |||
| repoNameSpace := strings.TrimPrefix(u.Path, "/") | |||
| log.Trace("Create gitlab downloader. BaseURL: %s RepoName: %s", baseURL, repoNameSpace) | |||
| return NewGitlabDownloader(baseURL, repoNameSpace, opts.AuthUsername, opts.AuthPassword), nil | |||
| } | |||
| // GitServiceType returns the type of git service | |||
| func (f *GitlabDownloaderFactory) GitServiceType() structs.GitServiceType { | |||
| return structs.GitlabService | |||
| } | |||
| // GitlabDownloader implements a Downloader interface to get repository informations | |||
| // from gitlab via go-gitlab | |||
| // - issueCount is incremented in GetIssues() to ensure PR and Issue numbers do not overlap, | |||
| // because Gitlab has individual Issue and Pull Request numbers. | |||
| // - issueSeen, working alongside issueCount, is checked in GetComments() to see whether we | |||
| // need to fetch the Issue or PR comments, as Gitlab stores them separately. | |||
| type GitlabDownloader struct { | |||
| ctx context.Context | |||
| client *gitlab.Client | |||
| repoID int | |||
| repoName string | |||
| issueCount int64 | |||
| fetchPRcomments bool | |||
| } | |||
| // NewGitlabDownloader creates a gitlab Downloader via gitlab API | |||
| // Use either a username/password, personal token entered into the username field, or anonymous/public access | |||
| // Note: Public access only allows very basic access | |||
| func NewGitlabDownloader(baseURL, repoPath, username, password string) *GitlabDownloader { | |||
| var client *http.Client | |||
| var gitlabClient *gitlab.Client | |||
| var err error | |||
| if username != "" { | |||
| if password == "" { | |||
| gitlabClient = gitlab.NewClient(client, username) | |||
| } else { | |||
| gitlabClient, err = gitlab.NewBasicAuthClient(client, baseURL, username, password) | |||
| } | |||
| } | |||
| if err != nil { | |||
| log.Trace("Error logging into gitlab: %v", err) | |||
| return nil | |||
| } | |||
| // Grab and store project/repo ID here, due to issues using the URL escaped path | |||
| gr, _, err := gitlabClient.Projects.GetProject(repoPath, nil, nil) | |||
| if err != nil { | |||
| log.Trace("Error retrieving project: %v", err) | |||
| return nil | |||
| } | |||
| if gr == nil { | |||
| log.Trace("Error getting project, project is nil") | |||
| return nil | |||
| } | |||
| return &GitlabDownloader{ | |||
| ctx: context.Background(), | |||
| client: gitlabClient, | |||
| repoID: gr.ID, | |||
| repoName: gr.Name, | |||
| } | |||
| } | |||
| // SetContext set context | |||
| func (g *GitlabDownloader) SetContext(ctx context.Context) { | |||
| g.ctx = ctx | |||
| } | |||
| // GetRepoInfo returns a repository information | |||
| func (g *GitlabDownloader) GetRepoInfo() (*base.Repository, error) { | |||
| if g == nil { | |||
| return nil, errors.New("error: GitlabDownloader is nil") | |||
| } | |||
| gr, _, err := g.client.Projects.GetProject(g.repoID, nil, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| var private bool | |||
| switch gr.Visibility { | |||
| case gitlab.InternalVisibility: | |||
| private = true | |||
| case gitlab.PrivateVisibility: | |||
| private = true | |||
| } | |||
| var owner string | |||
| if gr.Owner == nil { | |||
| log.Trace("gr.Owner is nil, trying to get owner from Namespace") | |||
| if gr.Namespace != nil && gr.Namespace.Kind == "user" { | |||
| owner = gr.Namespace.Path | |||
| } | |||
| } else { | |||
| owner = gr.Owner.Username | |||
| } | |||
| // convert gitlab repo to stand Repo | |||
| return &base.Repository{ | |||
| Owner: owner, | |||
| Name: gr.Name, | |||
| IsPrivate: private, | |||
| Description: gr.Description, | |||
| OriginalURL: gr.WebURL, | |||
| CloneURL: gr.HTTPURLToRepo, | |||
| }, nil | |||
| } | |||
| // GetTopics return gitlab topics | |||
| func (g *GitlabDownloader) GetTopics() ([]string, error) { | |||
| if g == nil { | |||
| return nil, errors.New("error: GitlabDownloader is nil") | |||
| } | |||
| gr, _, err := g.client.Projects.GetProject(g.repoID, nil, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return gr.TagList, err | |||
| } | |||
| // GetMilestones returns milestones | |||
| func (g *GitlabDownloader) GetMilestones() ([]*base.Milestone, error) { | |||
| if g == nil { | |||
| return nil, errors.New("error: GitlabDownloader is nil") | |||
| } | |||
| var perPage = 100 | |||
| var state = "all" | |||
| var milestones = make([]*base.Milestone, 0, perPage) | |||
| for i := 1; ; i++ { | |||
| ms, _, err := g.client.Milestones.ListMilestones(g.repoID, &gitlab.ListMilestonesOptions{ | |||
| State: &state, | |||
| ListOptions: gitlab.ListOptions{ | |||
| Page: i, | |||
| PerPage: perPage, | |||
| }}, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| for _, m := range ms { | |||
| var desc string | |||
| if m.Description != "" { | |||
| desc = m.Description | |||
| } | |||
| var state = "open" | |||
| var closedAt *time.Time | |||
| if m.State != "" { | |||
| state = m.State | |||
| if state == "closed" { | |||
| closedAt = m.UpdatedAt | |||
| } | |||
| } | |||
| var deadline *time.Time | |||
| if m.DueDate != nil { | |||
| deadlineParsed, err := time.Parse("2006-01-02", m.DueDate.String()) | |||
| if err != nil { | |||
| log.Trace("Error parsing Milestone DueDate time") | |||
| deadline = nil | |||
| } else { | |||
| deadline = &deadlineParsed | |||
| } | |||
| } | |||
| milestones = append(milestones, &base.Milestone{ | |||
| Title: m.Title, | |||
| Description: desc, | |||
| Deadline: deadline, | |||
| State: state, | |||
| Created: *m.CreatedAt, | |||
| Updated: m.UpdatedAt, | |||
| Closed: closedAt, | |||
| }) | |||
| } | |||
| if len(ms) < perPage { | |||
| break | |||
| } | |||
| } | |||
| return milestones, nil | |||
| } | |||
| // GetLabels returns labels | |||
| func (g *GitlabDownloader) GetLabels() ([]*base.Label, error) { | |||
| if g == nil { | |||
| return nil, errors.New("error: GitlabDownloader is nil") | |||
| } | |||
| var perPage = 100 | |||
| var labels = make([]*base.Label, 0, perPage) | |||
| for i := 1; ; i++ { | |||
| ls, _, err := g.client.Labels.ListLabels(g.repoID, &gitlab.ListLabelsOptions{ | |||
| Page: i, | |||
| PerPage: perPage, | |||
| }, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| for _, label := range ls { | |||
| baseLabel := &base.Label{ | |||
| Name: label.Name, | |||
| Color: strings.TrimLeft(label.Color, "#)"), | |||
| Description: label.Description, | |||
| } | |||
| labels = append(labels, baseLabel) | |||
| } | |||
| if len(ls) < perPage { | |||
| break | |||
| } | |||
| } | |||
| return labels, nil | |||
| } | |||
| func (g *GitlabDownloader) convertGitlabRelease(rel *gitlab.Release) *base.Release { | |||
| r := &base.Release{ | |||
| TagName: rel.TagName, | |||
| TargetCommitish: rel.Commit.ID, | |||
| Name: rel.Name, | |||
| Body: rel.Description, | |||
| Created: *rel.CreatedAt, | |||
| PublisherID: int64(rel.Author.ID), | |||
| PublisherName: rel.Author.Username, | |||
| } | |||
| for k, asset := range rel.Assets.Links { | |||
| r.Assets = append(r.Assets, base.ReleaseAsset{ | |||
| URL: asset.URL, | |||
| Name: asset.Name, | |||
| ContentType: &rel.Assets.Sources[k].Format, | |||
| }) | |||
| } | |||
| return r | |||
| } | |||
| // GetReleases returns releases | |||
| func (g *GitlabDownloader) GetReleases() ([]*base.Release, error) { | |||
| var perPage = 100 | |||
| var releases = make([]*base.Release, 0, perPage) | |||
| for i := 1; ; i++ { | |||
| ls, _, err := g.client.Releases.ListReleases(g.repoID, &gitlab.ListReleasesOptions{ | |||
| Page: i, | |||
| PerPage: perPage, | |||
| }, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| for _, release := range ls { | |||
| releases = append(releases, g.convertGitlabRelease(release)) | |||
| } | |||
| if len(ls) < perPage { | |||
| break | |||
| } | |||
| } | |||
| return releases, nil | |||
| } | |||
| // GetIssues returns issues according start and limit | |||
| // Note: issue label description and colors are not supported by the go-gitlab library at this time | |||
| // TODO: figure out how to transfer issue reactions | |||
| func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { | |||
| state := "all" | |||
| sort := "asc" | |||
| opt := &gitlab.ListProjectIssuesOptions{ | |||
| State: &state, | |||
| Sort: &sort, | |||
| ListOptions: gitlab.ListOptions{ | |||
| PerPage: perPage, | |||
| Page: page, | |||
| }, | |||
| } | |||
| var allIssues = make([]*base.Issue, 0, perPage) | |||
| issues, _, err := g.client.Issues.ListProjectIssues(g.repoID, opt, nil) | |||
| if err != nil { | |||
| return nil, false, fmt.Errorf("error while listing issues: %v", err) | |||
| } | |||
| for _, issue := range issues { | |||
| var labels = make([]*base.Label, 0, len(issue.Labels)) | |||
| for _, l := range issue.Labels { | |||
| labels = append(labels, &base.Label{ | |||
| Name: l, | |||
| }) | |||
| } | |||
| var milestone string | |||
| if issue.Milestone != nil { | |||
| milestone = issue.Milestone.Title | |||
| } | |||
| allIssues = append(allIssues, &base.Issue{ | |||
| Title: issue.Title, | |||
| Number: int64(issue.IID), | |||
| PosterID: int64(issue.Author.ID), | |||
| PosterName: issue.Author.Username, | |||
| Content: issue.Description, | |||
| Milestone: milestone, | |||
| State: issue.State, | |||
| Created: *issue.CreatedAt, | |||
| Labels: labels, | |||
| Closed: issue.ClosedAt, | |||
| IsLocked: issue.DiscussionLocked, | |||
| Updated: *issue.UpdatedAt, | |||
| }) | |||
| // increment issueCount, to be used in GetPullRequests() | |||
| g.issueCount++ | |||
| } | |||
| return allIssues, len(issues) < perPage, nil | |||
| } | |||
| // GetComments returns comments according issueNumber | |||
| func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { | |||
| var allComments = make([]*base.Comment, 0, 100) | |||
| var page = 1 | |||
| var realIssueNumber int64 | |||
| for { | |||
| var comments []*gitlab.Discussion | |||
| var resp *gitlab.Response | |||
| var err error | |||
| // fetchPRcomments decides whether to fetch Issue or PR comments | |||
| if !g.fetchPRcomments { | |||
| realIssueNumber = issueNumber | |||
| comments, resp, err = g.client.Discussions.ListIssueDiscussions(g.repoID, int(realIssueNumber), &gitlab.ListIssueDiscussionsOptions{ | |||
| Page: page, | |||
| PerPage: 100, | |||
| }, nil) | |||
| } else { | |||
| // If this is a PR, we need to figure out the Gitlab/original PR ID to be passed below | |||
| realIssueNumber = issueNumber - g.issueCount | |||
| comments, resp, err = g.client.Discussions.ListMergeRequestDiscussions(g.repoID, int(realIssueNumber), &gitlab.ListMergeRequestDiscussionsOptions{ | |||
| Page: page, | |||
| PerPage: 100, | |||
| }, nil) | |||
| } | |||
| if err != nil { | |||
| return nil, fmt.Errorf("error while listing comments: %v %v", g.repoID, err) | |||
| } | |||
| for _, comment := range comments { | |||
| // Flatten comment threads | |||
| if !comment.IndividualNote { | |||
| for _, note := range comment.Notes { | |||
| allComments = append(allComments, &base.Comment{ | |||
| IssueIndex: realIssueNumber, | |||
| PosterID: int64(note.Author.ID), | |||
| PosterName: note.Author.Username, | |||
| PosterEmail: note.Author.Email, | |||
| Content: note.Body, | |||
| Created: *note.CreatedAt, | |||
| }) | |||
| } | |||
| } else { | |||
| c := comment.Notes[0] | |||
| allComments = append(allComments, &base.Comment{ | |||
| IssueIndex: realIssueNumber, | |||
| PosterID: int64(c.Author.ID), | |||
| PosterName: c.Author.Username, | |||
| PosterEmail: c.Author.Email, | |||
| Content: c.Body, | |||
| Created: *c.CreatedAt, | |||
| }) | |||
| } | |||
| } | |||
| if resp.NextPage == 0 { | |||
| break | |||
| } | |||
| page = resp.NextPage | |||
| } | |||
| return allComments, nil | |||
| } | |||
| // GetPullRequests returns pull requests according page and perPage | |||
| func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, error) { | |||
| opt := &gitlab.ListProjectMergeRequestsOptions{ | |||
| ListOptions: gitlab.ListOptions{ | |||
| PerPage: perPage, | |||
| Page: page, | |||
| }, | |||
| } | |||
| // Set fetchPRcomments to true here, so PR comments are fetched instead of Issue comments | |||
| g.fetchPRcomments = true | |||
| var allPRs = make([]*base.PullRequest, 0, perPage) | |||
| prs, _, err := g.client.MergeRequests.ListProjectMergeRequests(g.repoID, opt, nil) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("error while listing merge requests: %v", err) | |||
| } | |||
| for _, pr := range prs { | |||
| var labels = make([]*base.Label, 0, len(pr.Labels)) | |||
| for _, l := range pr.Labels { | |||
| labels = append(labels, &base.Label{ | |||
| Name: l, | |||
| }) | |||
| } | |||
| var merged bool | |||
| if pr.State == "merged" { | |||
| merged = true | |||
| pr.State = "closed" | |||
| } | |||
| var mergeTime = pr.MergedAt | |||
| if merged && pr.MergedAt == nil { | |||
| mergeTime = pr.UpdatedAt | |||
| } | |||
| var closeTime = pr.ClosedAt | |||
| if merged && pr.ClosedAt == nil { | |||
| closeTime = pr.UpdatedAt | |||
| } | |||
| var locked bool | |||
| if pr.State == "locked" { | |||
| locked = true | |||
| } | |||
| var milestone string | |||
| if pr.Milestone != nil { | |||
| milestone = pr.Milestone.Title | |||
| } | |||
| // Add the PR ID to the Issue Count because PR and Issues share ID space in Gitea | |||
| newPRnumber := g.issueCount + int64(pr.IID) | |||
| allPRs = append(allPRs, &base.PullRequest{ | |||
| Title: pr.Title, | |||
| Number: int64(newPRnumber), | |||
| PosterName: pr.Author.Username, | |||
| PosterID: int64(pr.Author.ID), | |||
| Content: pr.Description, | |||
| Milestone: milestone, | |||
| State: pr.State, | |||
| Created: *pr.CreatedAt, | |||
| Closed: closeTime, | |||
| Labels: labels, | |||
| Merged: merged, | |||
| MergeCommitSHA: pr.MergeCommitSHA, | |||
| MergedTime: mergeTime, | |||
| IsLocked: locked, | |||
| Head: base.PullRequestBranch{ | |||
| Ref: pr.SourceBranch, | |||
| SHA: pr.SHA, | |||
| RepoName: g.repoName, | |||
| OwnerName: pr.Author.Username, | |||
| CloneURL: pr.WebURL, | |||
| }, | |||
| Base: base.PullRequestBranch{ | |||
| Ref: pr.TargetBranch, | |||
| SHA: pr.DiffRefs.BaseSha, | |||
| RepoName: g.repoName, | |||
| OwnerName: pr.Author.Username, | |||
| }, | |||
| PatchURL: pr.WebURL + ".patch", | |||
| }) | |||
| } | |||
| return allPRs, nil | |||
| } | |||
| // GetReviews returns pull requests review | |||
| func (g *GitlabDownloader) GetReviews(pullRequestNumber int64) ([]*base.Review, error) { | |||
| return nil, nil | |||
| } | |||
| @@ -0,0 +1,246 @@ | |||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "net/http" | |||
| "os" | |||
| "testing" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/migrations/base" | |||
| "github.com/stretchr/testify/assert" | |||
| ) | |||
| func TestGitlabDownloadRepo(t *testing.T) { | |||
| // Skip tests if Gitlab token is not found | |||
| gitlabPersonalAccessToken := os.Getenv("GITLAB_READ_TOKEN") | |||
| if gitlabPersonalAccessToken == "" { | |||
| t.Skip("skipped test because GITLAB_READ_TOKEN was not in the environment") | |||
| } | |||
| resp, err := http.Get("https://gitlab.com/gitea/test_repo") | |||
| if err != nil || resp.StatusCode != 200 { | |||
| t.Skipf("Can't access test repo, skipping %s", t.Name()) | |||
| } | |||
| downloader := NewGitlabDownloader("https://gitlab.com", "gitea/test_repo", gitlabPersonalAccessToken, "") | |||
| if downloader == nil { | |||
| t.Fatal("NewGitlabDownloader is nil") | |||
| } | |||
| repo, err := downloader.GetRepoInfo() | |||
| assert.NoError(t, err) | |||
| // Repo Owner is blank in Gitlab Group repos | |||
| assert.EqualValues(t, &base.Repository{ | |||
| Name: "test_repo", | |||
| Owner: "", | |||
| Description: "Test repository for testing migration from gitlab to gitea", | |||
| CloneURL: "https://gitlab.com/gitea/test_repo.git", | |||
| OriginalURL: "https://gitlab.com/gitea/test_repo", | |||
| }, repo) | |||
| topics, err := downloader.GetTopics() | |||
| assert.NoError(t, err) | |||
| assert.True(t, len(topics) == 2) | |||
| assert.EqualValues(t, []string{"migration", "test"}, topics) | |||
| milestones, err := downloader.GetMilestones() | |||
| assert.NoError(t, err) | |||
| assert.True(t, len(milestones) >= 2) | |||
| for _, milestone := range milestones { | |||
| switch milestone.Title { | |||
| case "1.0": | |||
| assertMilestoneEqual(t, "", "1.0", | |||
| "", | |||
| "2019-11-28 08:42:30.301 +0000 UTC", | |||
| "2019-11-28 15:57:52.401 +0000 UTC", | |||
| "", | |||
| "closed", milestone) | |||
| case "1.1.0": | |||
| assertMilestoneEqual(t, "", "1.1.0", | |||
| "", | |||
| "2019-11-28 08:42:44.575 +0000 UTC", | |||
| "2019-11-28 08:42:44.575 +0000 UTC", | |||
| "", | |||
| "active", milestone) | |||
| } | |||
| } | |||
| labels, err := downloader.GetLabels() | |||
| assert.NoError(t, err) | |||
| assert.True(t, len(labels) >= 9) | |||
| for _, l := range labels { | |||
| switch l.Name { | |||
| case "bug": | |||
| assertLabelEqual(t, "bug", "d9534f", "", l) | |||
| case "documentation": | |||
| assertLabelEqual(t, "documentation", "f0ad4e", "", l) | |||
| case "confirmed": | |||
| assertLabelEqual(t, "confirmed", "d9534f", "", l) | |||
| case "enhancement": | |||
| assertLabelEqual(t, "enhancement", "5cb85c", "", l) | |||
| case "critical": | |||
| assertLabelEqual(t, "critical", "d9534f", "", l) | |||
| case "discussion": | |||
| assertLabelEqual(t, "discussion", "428bca", "", l) | |||
| case "suggestion": | |||
| assertLabelEqual(t, "suggestion", "428bca", "", l) | |||
| case "support": | |||
| assertLabelEqual(t, "support", "f0ad4e", "", l) | |||
| case "duplicate": | |||
| assertLabelEqual(t, "duplicate", "7F8C8D", "", l) | |||
| } | |||
| } | |||
| releases, err := downloader.GetReleases() | |||
| assert.NoError(t, err) | |||
| assert.EqualValues(t, []*base.Release{ | |||
| { | |||
| TagName: "v0.9.99", | |||
| TargetCommitish: "0720a3ec57c1f843568298117b874319e7deee75", | |||
| Name: "First Release", | |||
| Body: "A test release", | |||
| Created: time.Date(2019, 11, 28, 9, 9, 48, 840000000, time.UTC), | |||
| PublisherID: 1241334, | |||
| PublisherName: "lafriks", | |||
| }, | |||
| }, releases[len(releases)-1:]) | |||
| // downloader.GetIssues() | |||
| issues, isEnd, err := downloader.GetIssues(1, 2) | |||
| assert.NoError(t, err) | |||
| assert.EqualValues(t, 2, len(issues)) | |||
| assert.False(t, isEnd) | |||
| var ( | |||
| closed1 = time.Date(2019, 11, 28, 8, 46, 23, 275000000, time.UTC) | |||
| closed2 = time.Date(2019, 11, 28, 8, 45, 44, 959000000, time.UTC) | |||
| ) | |||
| assert.EqualValues(t, []*base.Issue{ | |||
| { | |||
| Number: 1, | |||
| Title: "Please add an animated gif icon to the merge button", | |||
| Content: "I just want the merge button to hurt my eyes a little. :stuck_out_tongue_closed_eyes:", | |||
| Milestone: "1.0.0", | |||
| PosterID: 1241334, | |||
| PosterName: "lafriks", | |||
| State: "closed", | |||
| Created: time.Date(2019, 11, 28, 8, 43, 35, 459000000, time.UTC), | |||
| Updated: time.Date(2019, 11, 28, 8, 46, 23, 275000000, time.UTC), | |||
| Labels: []*base.Label{ | |||
| { | |||
| Name: "bug", | |||
| }, | |||
| { | |||
| Name: "discussion", | |||
| }, | |||
| }, | |||
| Reactions: nil, | |||
| Closed: &closed1, | |||
| }, | |||
| { | |||
| Number: 2, | |||
| Title: "Test issue", | |||
| Content: "This is test issue 2, do not touch!", | |||
| Milestone: "1.1.0", | |||
| PosterID: 1241334, | |||
| PosterName: "lafriks", | |||
| State: "closed", | |||
| Created: time.Date(2019, 11, 28, 8, 44, 46, 277000000, time.UTC), | |||
| Updated: time.Date(2019, 11, 28, 8, 45, 44, 987000000, time.UTC), | |||
| Labels: []*base.Label{ | |||
| { | |||
| Name: "duplicate", | |||
| }, | |||
| }, | |||
| Reactions: nil, | |||
| Closed: &closed2, | |||
| }, | |||
| }, issues) | |||
| // downloader.GetComments() | |||
| comments, err := downloader.GetComments(2) | |||
| assert.NoError(t, err) | |||
| assert.EqualValues(t, 4, len(comments)) | |||
| assert.EqualValues(t, []*base.Comment{ | |||
| { | |||
| IssueIndex: 2, | |||
| PosterID: 1241334, | |||
| PosterName: "lafriks", | |||
| Created: time.Date(2019, 11, 28, 8, 44, 52, 501000000, time.UTC), | |||
| Updated: time.Date(2019, 11, 28, 8, 44, 52, 501000000, time.UTC), | |||
| Content: "This is a comment", | |||
| Reactions: nil, | |||
| }, | |||
| { | |||
| IssueIndex: 2, | |||
| PosterID: 1241334, | |||
| PosterName: "lafriks", | |||
| Created: time.Date(2019, 11, 28, 8, 45, 2, 329000000, time.UTC), | |||
| Content: "changed milestone to %2", | |||
| Reactions: nil, | |||
| }, | |||
| { | |||
| IssueIndex: 2, | |||
| PosterID: 1241334, | |||
| PosterName: "lafriks", | |||
| Created: time.Date(2019, 11, 28, 8, 45, 45, 7000000, time.UTC), | |||
| Content: "closed", | |||
| Reactions: nil, | |||
| }, | |||
| { | |||
| IssueIndex: 2, | |||
| PosterID: 1241334, | |||
| PosterName: "lafriks", | |||
| Created: time.Date(2019, 11, 28, 8, 45, 53, 501000000, time.UTC), | |||
| Content: "A second comment", | |||
| Reactions: nil, | |||
| }, | |||
| }, comments[:4]) | |||
| // downloader.GetPullRequests() | |||
| prs, err := downloader.GetPullRequests(1, 1) | |||
| assert.NoError(t, err) | |||
| assert.EqualValues(t, 1, len(prs)) | |||
| assert.EqualValues(t, []*base.PullRequest{ | |||
| { | |||
| Number: 4, | |||
| Title: "Test branch", | |||
| Content: "do not merge this PR", | |||
| Milestone: "1.0.0", | |||
| PosterID: 1241334, | |||
| PosterName: "lafriks", | |||
| State: "opened", | |||
| Created: time.Date(2019, 11, 28, 15, 56, 54, 104000000, time.UTC), | |||
| Updated: time.Date(2019, 11, 28, 15, 56, 54, 104000000, time.UTC), | |||
| Labels: []*base.Label{ | |||
| { | |||
| Name: "bug", | |||
| }, | |||
| }, | |||
| PatchURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2.patch", | |||
| Head: base.PullRequestBranch{ | |||
| Ref: "feat/test", | |||
| CloneURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2", | |||
| SHA: "9f733b96b98a4175276edf6a2e1231489c3bdd23", | |||
| RepoName: "test_repo", | |||
| OwnerName: "lafriks", | |||
| }, | |||
| Base: base.PullRequestBranch{ | |||
| Ref: "master", | |||
| SHA: "", | |||
| OwnerName: "lafriks", | |||
| RepoName: "test_repo", | |||
| }, | |||
| Closed: nil, | |||
| Merged: false, | |||
| MergedTime: nil, | |||
| MergeCommitSHA: "", | |||
| }, | |||
| }, prs) | |||
| } | |||
| @@ -203,6 +203,7 @@ var ( | |||
| // TODO: add to this list after new git service added | |||
| SupportedFullGitService = []GitServiceType{ | |||
| GithubService, | |||
| GitlabService, | |||
| } | |||
| ) | |||
| @@ -0,0 +1,28 @@ | |||
| # 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 | |||
| @@ -0,0 +1,28 @@ | |||
| language: 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 | |||
| @@ -0,0 +1,27 @@ | |||
| go-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. | |||
| @@ -0,0 +1,202 @@ | |||
| Apache 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. | |||
| @@ -0,0 +1,173 @@ | |||
| # go-gitlab | |||
| A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way | |||
| [](https://travis-ci.org/xanzy/go-gitlab) | |||
| [](https://github.com/xanzy/go-gitlab/blob/master/LICENSE) | |||
| [](https://sourcegraph.com/github.com/xanzy/go-gitlab?badge) | |||
| [](https://godoc.org/github.com/xanzy/go-gitlab) | |||
| [](https://goreportcard.com/report/github.com/xanzy/go-gitlab) | |||
| [](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 (<sander@xanzy.io>) | |||
| ## 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 <http://www.apache.org/licenses/LICENSE-2.0> | |||
| @@ -0,0 +1,236 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,467 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,344 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,242 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,172 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,69 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,593 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,171 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,200 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,120 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,212 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,211 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,117 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,815 @@ | |||
| // | |||
| // 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 struct { | |||
| ForceRemoveSourceBranch string `json:"force_remove_source_branch"` | |||
| } `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"` | |||
| } | |||
| @@ -0,0 +1,146 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,79 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,84 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,955 @@ | |||
| // | |||
| // 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": { | |||
| // "<property-name>": [ | |||
| // "<error-message>", | |||
| // "<error-message>", | |||
| // ... | |||
| // ], | |||
| // "<embed-entity>": { | |||
| // "<property-name>": [ | |||
| // "<error-message>", | |||
| // "<error-message>", | |||
| // ... | |||
| // ], | |||
| // } | |||
| // }, | |||
| // "error": "<error-message>" | |||
| // } | |||
| 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 | |||
| } | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| module 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 | |||
| @@ -0,0 +1,25 @@ | |||
| github.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= | |||
| @@ -0,0 +1,213 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,261 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,211 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,196 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,219 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,249 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,196 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,335 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,127 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,568 @@ | |||
| // | |||
| // 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...) | |||
| } | |||
| @@ -0,0 +1,408 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,65 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,250 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,94 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,92 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,191 @@ | |||
| package 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"` | |||
| } | |||
| } | |||
| // 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{}, mergeRequestIID 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), mergeRequestIID) | |||
| 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{}, mergeRequestIID 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), mergeRequestIID) | |||
| 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 | |||
| } | |||
| @@ -0,0 +1,836 @@ | |||
| // | |||
| // 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...) | |||
| } | |||
| @@ -0,0 +1,267 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,122 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,678 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,213 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,193 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,327 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,231 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,286 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,207 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,221 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,196 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,209 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,206 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,201 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,165 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,145 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,219 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,176 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,212 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,327 @@ | |||
| // | |||
| // 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 ListOptions | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,311 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,219 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,415 @@ | |||
| // | |||
| // 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"` | |||
| 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) | |||
| } | |||
| @@ -0,0 +1,354 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,864 @@ | |||
| // | |||
| // 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"` | |||
| 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"` | |||
| 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) | |||
| } | |||
| @@ -0,0 +1,409 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,154 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,230 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,94 @@ | |||
| // | |||
| // 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("<nil>") | |||
| 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()) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,143 @@ | |||
| // | |||
| // 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) | |||
| } | |||
| @@ -0,0 +1,243 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,162 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,176 @@ | |||
| package 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) | |||
| } | |||
| @@ -0,0 +1,871 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,40 @@ | |||
| package 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 | |||
| } | |||
| @@ -0,0 +1,56 @@ | |||
| // | |||
| // 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 | |||
| } | |||
| @@ -0,0 +1,204 @@ | |||
| // 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) | |||
| } | |||
| @@ -638,6 +638,9 @@ github.com/unknwon/paginater | |||
| github.com/urfave/cli | |||
| # github.com/willf/bitset v1.1.10 | |||
| github.com/willf/bitset | |||
| # github.com/xanzy/go-gitlab v0.22.1 | |||
| ## explicit | |||
| github.com/xanzy/go-gitlab | |||
| # github.com/xanzy/ssh-agent v0.2.1 | |||
| github.com/xanzy/ssh-agent | |||
| # github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 | |||
| @@ -1162,7 +1162,7 @@ function initMigration() { | |||
| const authUserName = $('#auth_username').val(); | |||
| const cloneAddr = $('#clone_addr').val(); | |||
| if (!$('#mirror').is(':checked') && (authUserName && authUserName.length > 0) && | |||
| (cloneAddr !== undefined && (cloneAddr.startsWith('https://github.com') || cloneAddr.startsWith('http://github.com')))) { | |||
| (cloneAddr !== undefined && (cloneAddr.startsWith('https://github.com') || cloneAddr.startsWith('http://github.com') || cloneAddr.startsWith('http://gitlab.com') || cloneAddr.startsWith('https://gitlab.com')))) { | |||
| $('#migrate_items').show(); | |||
| } else { | |||
| $('#migrate_items').hide(); | |||