diff --git a/go.mod b/go.mod index 07a8f8c20..973f49ac0 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/google/go-github/v32 v32.1.0 github.com/google/uuid v1.1.1 github.com/gorilla/context v1.1.1 - github.com/hashicorp/go-retryablehttp v0.6.6 // indirect + github.com/hashicorp/go-retryablehttp v0.6.7 // indirect github.com/hashicorp/go-version v0.0.0-00010101000000-000000000000 github.com/huandu/xstrings v1.3.0 github.com/issue9/assert v1.3.2 // indirect @@ -94,7 +94,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.31.0 + github.com/xanzy/go-gitlab v0.37.0 github.com/yohcop/openid-go v1.0.0 github.com/yuin/goldmark v1.2.1 github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 @@ -104,8 +104,8 @@ require ( golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae golang.org/x/text v0.3.3 - golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect - golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d + golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect + golang.org/x/tools v0.0.0-20200825202427-b303f430e36d gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df diff --git a/go.sum b/go.sum index 2b11989e6..e3eeb6875 100644 --- a/go.sum +++ b/go.sum @@ -477,8 +477,8 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo= +github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -888,8 +888,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 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.31.0 h1:+nHztQuCXGSMluKe5Q9IRaPdz6tO8O0gMkQ0vqGpiBk= -github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= +github.com/xanzy/go-gitlab v0.37.0 h1:Z/CQkjj5VwbWVYVL7S70kS/TFj5H/pJumV7xbJ0YUQ8= +github.com/xanzy/go-gitlab v0.37.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= 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/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -1072,15 +1072,14 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORK golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1111,11 +1110,10 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d h1:XZxUC4/ZNKTjrT4/Oc9gCgIYnzPW3/CefdPjsndrVWM= -golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1160,7 +1158,6 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= @@ -1187,9 +1184,7 @@ gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.60.1 h1:P5y5shSkb0CFe44qEeMBgn8JLow09MP17jlJHanke5g= gopkg.in/ini.v1 v1.60.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.60.2 h1:7i8mqModL63zqi8nQn8Q3+0zvSCZy1AxhBgthKfi4WU= gopkg.in/ini.v1 v1.60.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index 3cdcef3af..7e7d88b70 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -234,10 +234,10 @@ func (g *GitlabDownloader) GetLabels() ([]*base.Label, error) { var perPage = 100 var labels = make([]*base.Label, 0, perPage) for i := 1; ; i++ { - ls, _, err := g.client.Labels.ListLabels(g.repoID, &gitlab.ListLabelsOptions{ + ls, _, err := g.client.Labels.ListLabels(g.repoID, &gitlab.ListLabelsOptions{ListOptions: gitlab.ListOptions{ Page: i, PerPage: perPage, - }, nil, gitlab.WithContext(g.ctx)) + }}, nil, gitlab.WithContext(g.ctx)) if err != nil { return nil, err } diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml b/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml deleted file mode 100644 index c4fb6d6c8..000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -sudo: false - -language: go - -go: - - 1.12.4 - -branches: - only: - - master - -script: make updatedeps test diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go index f1ccd3df3..a23f9a93f 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/client.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/client.go @@ -35,11 +35,12 @@ import ( "net/url" "os" "regexp" + "strconv" "strings" "sync" "time" - "github.com/hashicorp/go-cleanhttp" + cleanhttp "github.com/hashicorp/go-cleanhttp" ) var ( @@ -276,12 +277,16 @@ type Logger interface { Printf(string, ...interface{}) } -// LeveledLogger interface implements the basic methods that a logger library needs +// LeveledLogger is an interface that can be implemented by any logger or a +// logger wrapper to provide leveled logging. The methods accept a message +// string and a variadic number of key-value pairs. For log.Printf style +// formatting where message string contains a format specifier, use Logger +// interface. type LeveledLogger interface { - Error(string, ...interface{}) - Info(string, ...interface{}) - Debug(string, ...interface{}) - Warn(string, ...interface{}) + Error(msg string, keysAndValues ...interface{}) + Info(msg string, keysAndValues ...interface{}) + Debug(msg string, keysAndValues ...interface{}) + Warn(msg string, keysAndValues ...interface{}) } // hookLogger adapts an LeveledLogger to Logger for use by the existing hook functions @@ -357,6 +362,7 @@ type Client struct { ErrorHandler ErrorHandler loggerInit sync.Once + clientInit sync.Once } // NewClient creates a new Client with default settings. @@ -420,6 +426,13 @@ func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bo return true, nil } + // 429 Too Many Requests is recoverable. Sometimes the server puts + // a Retry-After response header to indicate when the server is + // available to start processing request from client. + if resp.StatusCode == http.StatusTooManyRequests { + return true, nil + } + // Check the response code. We retry on 500-range responses to allow // the server time to recover, as 500's are typically not permanent // errors and may relate to outages on the server side. This will catch @@ -431,10 +444,66 @@ func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bo return false, nil } +// ErrorPropagatedRetryPolicy is the same as DefaultRetryPolicy, except it +// propagates errors back instead of returning nil. This allows you to inspect +// why it decided to retry or not. +func ErrorPropagatedRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { + // do not retry on context.Canceled or context.DeadlineExceeded + if ctx.Err() != nil { + return false, ctx.Err() + } + + if err != nil { + if v, ok := err.(*url.Error); ok { + // Don't retry if the error was due to too many redirects. + if redirectsErrorRe.MatchString(v.Error()) { + return false, v + } + + // Don't retry if the error was due to an invalid protocol scheme. + if schemeErrorRe.MatchString(v.Error()) { + return false, v + } + + // Don't retry if the error was due to TLS cert verification failure. + if _, ok := v.Err.(x509.UnknownAuthorityError); ok { + return false, v + } + } + + // The error is likely recoverable so retry. + return true, nil + } + + // Check the response code. We retry on 500-range responses to allow + // the server time to recover, as 500's are typically not permanent + // errors and may relate to outages on the server side. This will catch + // invalid response codes as well, like 0 and 999. + if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) { + return true, fmt.Errorf("unexpected HTTP status %s", resp.Status) + } + + return false, nil +} + // DefaultBackoff provides a default callback for Client.Backoff which // will perform exponential backoff based on the attempt number and limited // by the provided minimum and maximum durations. +// +// It also tries to parse Retry-After response header when a http.StatusTooManyRequests +// (HTTP Code 429) is found in the resp parameter. Hence it will return the number of +// seconds the server states it may be ready to process more requests from this client. func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { + if resp != nil { + if resp.StatusCode == http.StatusTooManyRequests { + if s, ok := resp.Header["Retry-After"]; ok { + if sleep, err := strconv.ParseInt(s[0], 10, 64); err == nil { + return time.Second * time.Duration(sleep) + } + } + } + } + mult := math.Pow(2, float64(attemptNum)) * float64(min) sleep := time.Duration(mult) if float64(sleep) != mult || sleep > max { @@ -490,25 +559,31 @@ func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Respo // Do wraps calling an HTTP method with retries. func (c *Client) Do(req *Request) (*http.Response, error) { - if c.HTTPClient == nil { - c.HTTPClient = cleanhttp.DefaultPooledClient() - } + c.clientInit.Do(func() { + if c.HTTPClient == nil { + c.HTTPClient = cleanhttp.DefaultPooledClient() + } + }) logger := c.logger() if logger != nil { switch v := logger.(type) { - case Logger: - v.Printf("[DEBUG] %s %s", req.Method, req.URL) case LeveledLogger: v.Debug("performing request", "method", req.Method, "url", req.URL) + case Logger: + v.Printf("[DEBUG] %s %s", req.Method, req.URL) } } var resp *http.Response - var err error + var attempt int + var shouldRetry bool + var doErr, checkErr error for i := 0; ; i++ { + attempt++ + var code int // HTTP response code // Always rewind the request body when non-nil. @@ -527,30 +602,30 @@ func (c *Client) Do(req *Request) (*http.Response, error) { if c.RequestLogHook != nil { switch v := logger.(type) { - case Logger: - c.RequestLogHook(v, req.Request, i) case LeveledLogger: c.RequestLogHook(hookLogger{v}, req.Request, i) + case Logger: + c.RequestLogHook(v, req.Request, i) default: c.RequestLogHook(nil, req.Request, i) } } // Attempt the request - resp, err = c.HTTPClient.Do(req.Request) + resp, doErr = c.HTTPClient.Do(req.Request) if resp != nil { code = resp.StatusCode } // Check if we should continue with retries. - checkOK, checkErr := c.CheckRetry(req.Context(), resp, err) + shouldRetry, checkErr = c.CheckRetry(req.Context(), resp, doErr) - if err != nil { + if doErr != nil { switch v := logger.(type) { - case Logger: - v.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err) case LeveledLogger: - v.Error("request failed", "error", err, "method", req.Method, "url", req.URL) + v.Error("request failed", "error", doErr, "method", req.Method, "url", req.URL) + case Logger: + v.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, doErr) } } else { // Call this here to maintain the behavior of logging all requests, @@ -558,23 +633,18 @@ func (c *Client) Do(req *Request) (*http.Response, error) { if c.ResponseLogHook != nil { // Call the response logger function if provided. switch v := logger.(type) { - case Logger: - c.ResponseLogHook(v, resp) case LeveledLogger: c.ResponseLogHook(hookLogger{v}, resp) + case Logger: + c.ResponseLogHook(v, resp) default: c.ResponseLogHook(nil, resp) } } } - // Now decide if we should continue. - if !checkOK { - if checkErr != nil { - err = checkErr - } - c.HTTPClient.CloseIdleConnections() - return resp, err + if !shouldRetry { + break } // We do this before drainBody because there's no need for the I/O if @@ -585,7 +655,7 @@ func (c *Client) Do(req *Request) (*http.Response, error) { } // We're going to retry, consume any response to reuse the connection. - if err == nil && resp != nil { + if doErr == nil { c.drainBody(resp.Body) } @@ -596,10 +666,10 @@ func (c *Client) Do(req *Request) (*http.Response, error) { } if logger != nil { switch v := logger.(type) { - case Logger: - v.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) case LeveledLogger: v.Debug("retrying request", "request", desc, "timeout", wait, "remaining", remain) + case Logger: + v.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) } } select { @@ -608,21 +678,44 @@ func (c *Client) Do(req *Request) (*http.Response, error) { return nil, req.Context().Err() case <-time.After(wait): } + + // Make shallow copy of http Request so that we can modify its body + // without racing against the closeBody call in persistConn.writeLoop. + httpreq := *req.Request + req.Request = &httpreq + } + + // this is the closest we have to success criteria + if doErr == nil && checkErr == nil && !shouldRetry { + return resp, nil + } + + defer c.HTTPClient.CloseIdleConnections() + + err := doErr + if checkErr != nil { + err = checkErr } if c.ErrorHandler != nil { - c.HTTPClient.CloseIdleConnections() - return c.ErrorHandler(resp, err, c.RetryMax+1) + return c.ErrorHandler(resp, err, attempt) } // By default, we close the response body and return an error without // returning the response if resp != nil { - resp.Body.Close() + c.drainBody(resp.Body) + } + + // this means CheckRetry thought the request was a failure, but didn't + // communicate why + if err == nil { + return nil, fmt.Errorf("%s %s giving up after %d attempt(s)", + req.Method, req.URL, attempt) } - c.HTTPClient.CloseIdleConnections() - return nil, fmt.Errorf("%s %s giving up after %d attempts", - req.Method, req.URL, c.RetryMax+1) + + return nil, fmt.Errorf("%s %s giving up after %d attempt(s): %w", + req.Method, req.URL, attempt, err) } // Try to read the response body so we can reuse this connection. @@ -632,10 +725,10 @@ func (c *Client) drainBody(body io.ReadCloser) { if err != nil { if c.logger() != nil { switch v := c.logger().(type) { - case Logger: - v.Printf("[ERR] error reading response body: %v", err) case LeveledLogger: v.Error("error reading response body", "error", err) + case Logger: + v.Printf("[ERR] error reading response body: %v", err) } } } diff --git a/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go b/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go index b841b4cfe..8f3ee3584 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go @@ -1,7 +1,9 @@ package retryablehttp import ( + "errors" "net/http" + "net/url" "sync" ) @@ -39,5 +41,12 @@ func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { } // Execute the request. - return rt.Client.Do(retryableReq) + resp, err := rt.Client.Do(retryableReq) + // If we got an error returned by standard library's `Do` method, unwrap it + // otherwise we will wind up erroneously re-nesting the error. + if _, ok := err.(*url.Error); ok { + return resp, errors.Unwrap(err) + } + + return resp, err } diff --git a/vendor/github.com/xanzy/go-gitlab/README.md b/vendor/github.com/xanzy/go-gitlab/README.md index 0b1f5bfc2..ead2361fe 100644 --- a/vendor/github.com/xanzy/go-gitlab/README.md +++ b/vendor/github.com/xanzy/go-gitlab/README.md @@ -44,6 +44,7 @@ to add new and/or missing endpoints. Currently the following services are suppor - [x] Group Milestones - [x] Group-Level Variables - [x] Groups +- [x] Instance Clusters - [x] Issue Boards - [x] Issues - [x] Jobs @@ -161,7 +162,7 @@ func main() { s := &gitlab.CreateProjectSnippetOptions{ Title: gitlab.String("Dummy Snippet"), FileName: gitlab.String("snippet.go"), - Code: gitlab.String("package main...."), + Content: gitlab.String("package main...."), Visibility: gitlab.Visibility(gitlab.PublicVisibility), } _, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s) diff --git a/vendor/github.com/xanzy/go-gitlab/branches.go b/vendor/github.com/xanzy/go-gitlab/branches.go index fd473f545..df5facd7d 100644 --- a/vendor/github.com/xanzy/go-gitlab/branches.go +++ b/vendor/github.com/xanzy/go-gitlab/branches.go @@ -38,8 +38,10 @@ type Branch struct { Protected bool `json:"protected"` Merged bool `json:"merged"` Default bool `json:"default"` + CanPush bool `json:"can_push"` DevelopersCanPush bool `json:"developers_can_push"` DevelopersCanMerge bool `json:"developers_can_merge"` + WebURL string `json:"web_url"` } func (b Branch) String() string { diff --git a/vendor/github.com/xanzy/go-gitlab/client_options.go b/vendor/github.com/xanzy/go-gitlab/client_options.go index dfc408979..4d9b0d698 100644 --- a/vendor/github.com/xanzy/go-gitlab/client_options.go +++ b/vendor/github.com/xanzy/go-gitlab/client_options.go @@ -24,6 +24,16 @@ func WithCustomBackoff(backoff retryablehttp.Backoff) ClientOptionFunc { } } +// WithCustomLimiter injects a custom rate limiter to the client. +func WithCustomLimiter(limiter RateLimiter) ClientOptionFunc { + return func(c *Client) error { + c.configureLimiterOnce.Do(func() { + c.limiter = limiter + }) + return nil + } +} + // WithCustomRetry can be used to configure a custom retry policy. func WithCustomRetry(checkRetry retryablehttp.CheckRetry) ClientOptionFunc { return func(c *Client) error { diff --git a/vendor/github.com/xanzy/go-gitlab/commits.go b/vendor/github.com/xanzy/go-gitlab/commits.go index 3ebeda2e3..f9c6f8c9a 100644 --- a/vendor/github.com/xanzy/go-gitlab/commits.go +++ b/vendor/github.com/xanzy/go-gitlab/commits.go @@ -50,6 +50,7 @@ type Commit struct { Status *BuildStateValue `json:"status"` LastPipeline *PipelineInfo `json:"last_pipeline"` ProjectID int `json:"project_id"` + WebURL string `json:"web_url"` } // CommitStats represents the number of added and deleted files in a commit. @@ -118,11 +119,13 @@ const ( // 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"` + 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"` + LastCommitID string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"` + ExecuteFilemode bool `url:"execute_filemode,omitempty" json:"execute_filemode,omitempty"` } // CommitRef represents the reference of branches/tags in a commit. diff --git a/vendor/github.com/xanzy/go-gitlab/deployments.go b/vendor/github.com/xanzy/go-gitlab/deployments.go index 251cded82..2855f9146 100644 --- a/vendor/github.com/xanzy/go-gitlab/deployments.go +++ b/vendor/github.com/xanzy/go-gitlab/deployments.go @@ -35,6 +35,7 @@ type Deployment struct { Ref string `json:"ref"` SHA string `json:"sha"` CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` User *ProjectUser `json:"user"` Environment *Environment `json:"environment"` Deployable struct { diff --git a/vendor/github.com/xanzy/go-gitlab/epic_issues.go b/vendor/github.com/xanzy/go-gitlab/epic_issues.go new file mode 100644 index 000000000..3286b84dc --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/epic_issues.go @@ -0,0 +1,133 @@ +package gitlab + +import "fmt" + +// EpicIssuesService handles communication with the epic issue related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html +type EpicIssuesService struct { + client *Client +} + +// EpicIssueAssignment contains both the epic and issue objects returned from +// Gitlab with the assignment ID. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html +type EpicIssueAssignment struct { + ID int `json:"id"` + Epic *Epic `json:"epic"` + Issue *Issue `json:"issue"` +} + +// ListEpicIssues get a list of epic issues. +// +// Gitlab API docs: +// https://docs.gitlab.com/ee/api/epic_issues.html#list-issues-for-an-epic +func (s *EpicIssuesService) ListEpicIssues(gid interface{}, epic int, opt *ListOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/epics/%d/issues", pathEscape(group), epic) + + req, err := s.client.NewRequest("GET", u, opt, 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 +} + +// AssignEpicIssue assigns an existing issue to an epic. +// +// Gitlab API Docs: +// https://docs.gitlab.com/ee/api/epic_issues.html#assign-an-issue-to-the-epic +func (s *EpicIssuesService) AssignEpicIssue(gid interface{}, epic, issue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, issue) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + a := new(EpicIssueAssignment) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// RemoveEpicIssue removes an issue from an epic. +// +// Gitlab API Docs: +// https://docs.gitlab.com/ee/api/epic_issues.html#remove-an-issue-from-the-epic +func (s *EpicIssuesService) RemoveEpicIssue(gid interface{}, epic, epicIssue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, nil, err + } + + a := new(EpicIssueAssignment) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// UpdateEpicIsssueAssignmentOptions describes the UpdateEpicIssueAssignment() +// options. +// +// Gitlab API Docs: +// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association +type UpdateEpicIsssueAssignmentOptions struct { + *ListOptions + MoveBeforeID *int `url:"move_before_id,omitempty" json:"move_before_id,omitempty"` + MoveAfterID *int `url:"move_after_id,omitempty" json:"move_after_id,omitempty"` +} + +// UpdateEpicIssueAssignment moves an issue before or after another issue in an +// epic issue list. +// +// Gitlab API Docs: +// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association +func (s *EpicIssuesService) UpdateEpicIssueAssignment(gid interface{}, epic, epicIssue int, opt *UpdateEpicIsssueAssignmentOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue) + + req, err := s.client.NewRequest("PUT", u, opt, 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 +} diff --git a/vendor/github.com/xanzy/go-gitlab/epics.go b/vendor/github.com/xanzy/go-gitlab/epics.go index 87dbe200c..7f24c5029 100644 --- a/vendor/github.com/xanzy/go-gitlab/epics.go +++ b/vendor/github.com/xanzy/go-gitlab/epics.go @@ -30,16 +30,12 @@ type Epic struct { ID int `json:"id"` IID int `json:"iid"` GroupID int `json:"group_id"` - Author *EpicAuthor `json:"author"` + ParentID int `json:"parent_id"` + Title string `json:"title"` 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"` + WebURL string `json:"web_url"` + Author *EpicAuthor `json:"author"` StartDate *ISOTime `json:"start_date"` StartDateIsFixed bool `json:"start_date_is_fixed"` StartDateFixed *ISOTime `json:"start_date_fixed"` @@ -48,6 +44,13 @@ type Epic struct { DueDateIsFixed bool `json:"due_date_is_fixed"` DueDateFixed *ISOTime `json:"due_date_fixed"` DueDateFromMilestones *ISOTime `json:"due_date_from_milestones"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` + Labels []string `json:"labels"` + Upvotes int `json:"upvotes"` + Downvotes int `json:"downvotes"` + UserNotesCount int `json:"user_notes_count"` + URL string `json:"url"` } func (e Epic) String() string { @@ -59,12 +62,20 @@ func (e Epic) String() string { // 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"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,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"` + State *string `url:"state,omitempty" json:"state,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"` + IncludeAncestorGroups *bool `url:"include_ancestor_groups,omitempty" json:"include_ancestor_groups,omitempty"` + IncludeDescendantGroups *bool `url:"include_descendant_groups,omitempty" json:"include_descendant_groups,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` } // ListGroupEpics gets a list of group epics. This function accepts pagination @@ -116,6 +127,30 @@ func (s *EpicsService) GetEpic(gid interface{}, epic int, options ...RequestOpti return e, resp, err } +// GetEpicLinks gets all child epics of an epic. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/epic_links.html +func (s *EpicsService) GetEpicLinks(gid interface{}, epic int, options ...RequestOptionFunc) ([]*Epic, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/epics/%d/epics", pathEscape(group), epic) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var e []*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 diff --git a/vendor/github.com/xanzy/go-gitlab/event_webhook_types.go b/vendor/github.com/xanzy/go-gitlab/event_webhook_types.go index 108c191b8..d41379a4f 100644 --- a/vendor/github.com/xanzy/go-gitlab/event_webhook_types.go +++ b/vendor/github.com/xanzy/go-gitlab/event_webhook_types.go @@ -85,6 +85,7 @@ type TagEvent struct { UserID int `json:"user_id"` UserName string `json:"user_name"` UserAvatar string `json:"user_avatar"` + UserEmail string `json:"user_email"` ProjectID int `json:"project_id"` Message string `json:"message"` Project struct { @@ -443,8 +444,8 @@ type IssueCommentEvent struct { 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"` + HumanTotalTimeSpent string `json:"human_total_time_spent"` + HumanTimeEstimate string `json:"human_time_estimate"` AssigneeIDs []int `json:"assignee_ids"` AssigneeID int `json:"assignee_id"` } `json:"issue"` @@ -593,6 +594,10 @@ type MergeEvent struct { Previous int `json:"previous"` Current int `json:"current"` } `json:"source_project_id"` + StateID struct { + Previous int `json:"previous"` + Current int `json:"current"` + } `json:"state_id"` TargetBranch struct { Previous string `json:"previous"` Current string `json:"current"` diff --git a/vendor/github.com/xanzy/go-gitlab/gitlab.go b/vendor/github.com/xanzy/go-gitlab/gitlab.go index 4fdca5635..f8e4ee22d 100644 --- a/vendor/github.com/xanzy/go-gitlab/gitlab.go +++ b/vendor/github.com/xanzy/go-gitlab/gitlab.go @@ -20,7 +20,6 @@ package gitlab import ( "context" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -63,268 +62,6 @@ const ( 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" - Created BuildStateValue = "created" - Running BuildStateValue = "running" - Success BuildStateValue = "success" - Failed BuildStateValue = "failed" - Canceled BuildStateValue = "canceled" - Skipped BuildStateValue = "skipped" - Manual BuildStateValue = "manual" -) - -// DeploymentStatusValue represents a Gitlab deployment status. -type DeploymentStatusValue string - -// These constants represent all valid deployment statuses. -const ( - DeploymentStatusCreated DeploymentStatusValue = "created" - DeploymentStatusRunning DeploymentStatusValue = "running" - DeploymentStatusSuccess DeploymentStatusValue = "success" - DeploymentStatusFailed DeploymentStatusValue = "failed" - DeploymentStatusCanceled DeploymentStatusValue = "canceled" -) - -// 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" -) - -// ProjectCreationLevelValue represents a project creation level within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -type ProjectCreationLevelValue string - -// List of available project creation levels. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -const ( - NoOneProjectCreation ProjectCreationLevelValue = "noone" - MaintainerProjectCreation ProjectCreationLevelValue = "maintainer" - DeveloperProjectCreation ProjectCreationLevelValue = "developer" -) - -// SubGroupCreationLevelValue represents a sub group creation level within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -type SubGroupCreationLevelValue string - -// List of available sub group creation levels. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -const ( - OwnerSubGroupCreationLevelValue SubGroupCreationLevelValue = "owner" - MaintainerSubGroupCreationLevelValue SubGroupCreationLevelValue = "maintainer" -) - -// 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. @@ -338,12 +75,12 @@ type Client struct { // disableRetries is used to disable the default retry logic. disableRetries bool - // configLimiter is used to make sure the limiter is configured exactly + // configureLimiterOnce is used to make sure the limiter is configured exactly // once and block all other calls until the initial (one) call is done. configureLimiterOnce sync.Once // Limiter is used to limit API calls and prevent 429 responses. - limiter *rate.Limiter + limiter RateLimiter // Token type used to make authenticated API calls. authType authType @@ -354,6 +91,9 @@ type Client struct { // Token used to make authenticated API calls. token string + // Protects the token field from concurrent read/write accesses. + tokenLock sync.RWMutex + // User agent used when communicating with the GitLab API. UserAgent string @@ -373,6 +113,7 @@ type Client struct { Deployments *DeploymentsService Discussions *DiscussionsService Environments *EnvironmentsService + EpicIssues *EpicIssuesService Epics *EpicsService Events *EventsService Features *FeaturesService @@ -385,8 +126,11 @@ type Client struct { GroupMilestones *GroupMilestonesService GroupVariables *GroupVariablesService Groups *GroupsService + InstanceCluster *InstanceClustersService + InstanceVariables *InstanceVariablesService IssueLinks *IssueLinksService Issues *IssuesService + IssuesStatistics *IssuesStatisticsService Jobs *JobsService Keys *KeysService Labels *LabelsService @@ -406,6 +150,7 @@ type Client struct { ProjectCluster *ProjectClustersService ProjectImportExport *ProjectImportExportService ProjectMembers *ProjectMembersService + ProjectMirrors *ProjectMirrorService ProjectSnippets *ProjectSnippetsService ProjectVariables *ProjectVariablesService Projects *ProjectsService @@ -441,6 +186,11 @@ type ListOptions struct { PerPage int `url:"per_page,omitempty" json:"per_page,omitempty"` } +// RateLimiter describes the interface that all (custom) rate limiters must implement. +type RateLimiter interface { + Wait(context.Context) error +} + // NewClient returns a new GitLab API client. To use API methods which require // authentication, provide a valid private or personal token. func NewClient(token string, options ...ClientOptionFunc) (*Client, error) { @@ -465,11 +215,6 @@ func NewBasicAuthClient(username, password string, options ...ClientOptionFunc) client.username = username client.password = password - err = client.requestOAuthToken(context.Background()) - if err != nil { - return nil, err - } - return client, nil } @@ -485,22 +230,6 @@ func NewOAuthClient(token string, options ...ClientOptionFunc) (*Client, error) 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 -} - func newClient(options ...ClientOptionFunc) (*Client, error) { c := &Client{UserAgent: userAgent} @@ -547,6 +276,7 @@ func newClient(options ...ClientOptionFunc) (*Client, error) { c.Deployments = &DeploymentsService{client: c} c.Discussions = &DiscussionsService{client: c} c.Environments = &EnvironmentsService{client: c} + c.EpicIssues = &EpicIssuesService{client: c} c.Epics = &EpicsService{client: c} c.Events = &EventsService{client: c} c.Features = &FeaturesService{client: c} @@ -559,8 +289,10 @@ func newClient(options ...ClientOptionFunc) (*Client, error) { c.GroupMilestones = &GroupMilestonesService{client: c} c.GroupVariables = &GroupVariablesService{client: c} c.Groups = &GroupsService{client: c} + c.InstanceCluster = &InstanceClustersService{client: c} c.IssueLinks = &IssueLinksService{client: c} c.Issues = &IssuesService{client: c, timeStats: timeStats} + c.IssuesStatistics = &IssuesStatisticsService{client: c} c.Jobs = &JobsService{client: c} c.Keys = &KeysService{client: c} c.Labels = &LabelsService{client: c} @@ -580,6 +312,7 @@ func newClient(options ...ClientOptionFunc) (*Client, error) { c.ProjectCluster = &ProjectClustersService{client: c} c.ProjectImportExport = &ProjectImportExportService{client: c} c.ProjectMembers = &ProjectMembersService{client: c} + c.ProjectMirrors = &ProjectMirrorService{client: c} c.ProjectSnippets = &ProjectSnippetsService{client: c} c.ProjectVariables = &ProjectVariablesService{client: c} c.Projects = &ProjectsService{client: c} @@ -755,13 +488,6 @@ func (c *Client) NewRequest(method, path string, opt interface{}, options []Requ reqHeaders := make(http.Header) reqHeaders.Set("Accept", "application/json") - switch c.authType { - case basicAuth, oAuthToken: - reqHeaders.Set("Authorization", "Bearer "+c.token) - case privateToken: - reqHeaders.Set("PRIVATE-TOKEN", c.token) - } - if c.UserAgent != "" { reqHeaders.Set("User-Agent", c.UserAgent) } @@ -875,23 +601,47 @@ func (c *Client) Do(req *retryablehttp.Request, v interface{}) (*Response, error c.configureLimiterOnce.Do(func() { c.configureLimiter() }) // Wait will block until the limiter can obtain a new token. - if err := c.limiter.Wait(req.Context()); err != nil { + err := c.limiter.Wait(req.Context()) + if err != nil { return nil, err } + // Set the correct authentication header. If using basic auth, then check + // if we already have a token and if not first authenticate and get one. + var basicAuthToken string + switch c.authType { + case basicAuth: + c.tokenLock.RLock() + basicAuthToken = c.token + c.tokenLock.RUnlock() + if basicAuthToken == "" { + // If we don't have a token yet, we first need to request one. + basicAuthToken, err = c.requestOAuthToken(req.Context(), basicAuthToken) + if err != nil { + return nil, err + } + } + req.Header.Set("Authorization", "Bearer "+basicAuthToken) + case oAuthToken: + req.Header.Set("Authorization", "Bearer "+c.token) + case privateToken: + req.Header.Set("PRIVATE-TOKEN", c.token) + } + 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 { + resp.Body.Close() + // The token most likely expired, so we need to request a new one and try again. + if _, err := c.requestOAuthToken(req.Context(), basicAuthToken); err != nil { return nil, err } return c.Do(req, v) } + defer resp.Body.Close() response := newResponse(resp) @@ -913,6 +663,32 @@ func (c *Client) Do(req *retryablehttp.Request, v interface{}) (*Response, error return response, err } +func (c *Client) requestOAuthToken(ctx context.Context, token string) (string, error) { + c.tokenLock.Lock() + defer c.tokenLock.Unlock() + + // Return early if the token was updated while waiting for the lock. + if c.token != token { + return c.token, nil + } + + config := &oauth2.Config{ + Endpoint: oauth2.Endpoint{ + AuthURL: strings.TrimSuffix(c.baseURL.String(), apiVersionPath) + "oauth/authorize", + TokenURL: strings.TrimSuffix(c.baseURL.String(), apiVersionPath) + "oauth/token", + }, + } + + ctx = context.WithValue(ctx, oauth2.HTTPClient, c.client.HTTPClient) + t, err := config.PasswordCredentialsToken(ctx, c.username, c.password) + if err != nil { + return "", err + } + c.token = t.AccessToken + + return c.token, nil +} + // 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) { @@ -1012,129 +788,3 @@ func parseError(raw interface{}) string { return fmt.Sprintf("failed to parse unexpected error type: %T", raw) } } - -// 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 -} - -// DeploymentStatus is a helper routine that allocates a new -// DeploymentStatusValue to store v and returns a pointer to it. -func DeploymentStatus(v DeploymentStatusValue) *DeploymentStatusValue { - p := new(DeploymentStatusValue) - *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 -} - -// ProjectCreationLevel is a helper routine that allocates a new ProjectCreationLevelValue -// to store v and returns a pointer to it. -func ProjectCreationLevel(v ProjectCreationLevelValue) *ProjectCreationLevelValue { - p := new(ProjectCreationLevelValue) - *p = v - return p -} - -// SubGroupCreationLevel is a helper routine that allocates a new SubGroupCreationLevelValue -// to store v and returns a pointer to it. -func SubGroupCreationLevel(v SubGroupCreationLevelValue) *SubGroupCreationLevelValue { - p := new(SubGroupCreationLevelValue) - *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 - } -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_clusters.go b/vendor/github.com/xanzy/go-gitlab/group_clusters.go index 6e893ea46..e91cbd20f 100644 --- a/vendor/github.com/xanzy/go-gitlab/group_clusters.go +++ b/vendor/github.com/xanzy/go-gitlab/group_clusters.go @@ -93,13 +93,13 @@ func (s *GroupClustersService) GetCluster(pid interface{}, cluster int, options return nil, nil, err } - pc := new(GroupCluster) - resp, err := s.client.Do(req, &pc) + gc := new(GroupCluster) + resp, err := s.client.Do(req, &gc) if err != nil { return nil, resp, err } - return pc, resp, err + return gc, resp, err } // AddGroupClusterOptions represents the available AddCluster() options. @@ -141,13 +141,13 @@ func (s *GroupClustersService) AddCluster(pid interface{}, opt *AddGroupClusterO return nil, nil, err } - pc := new(GroupCluster) - resp, err := s.client.Do(req, pc) + gc := new(GroupCluster) + resp, err := s.client.Do(req, gc) if err != nil { return nil, resp, err } - return pc, resp, err + return gc, resp, err } // EditGroupClusterOptions represents the available EditCluster() options. @@ -185,13 +185,13 @@ func (s *GroupClustersService) EditCluster(pid interface{}, cluster int, opt *Ed return nil, nil, err } - pc := new(GroupCluster) - resp, err := s.client.Do(req, pc) + gc := new(GroupCluster) + resp, err := s.client.Do(req, gc) if err != nil { return nil, resp, err } - return pc, resp, err + return gc, resp, err } // DeleteCluster deletes an existing group cluster. diff --git a/vendor/github.com/xanzy/go-gitlab/group_labels.go b/vendor/github.com/xanzy/go-gitlab/group_labels.go index bff4496a8..87a5ea659 100644 --- a/vendor/github.com/xanzy/go-gitlab/group_labels.go +++ b/vendor/github.com/xanzy/go-gitlab/group_labels.go @@ -51,6 +51,35 @@ func (s *GroupLabelsService) ListGroupLabels(gid interface{}, opt *ListGroupLabe return l, resp, err } +// GetGroupLabel get a single label for a given group. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_labels.html#get-a-single-group-label +func (s *GroupLabelsService) GetGroupLabel(gid interface{}, labelID interface{}, options ...RequestOptionFunc) (*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", pathEscape(group), label) + + req, err := s.client.NewRequest("GET", u, nil, 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: diff --git a/vendor/github.com/xanzy/go-gitlab/group_members.go b/vendor/github.com/xanzy/go-gitlab/group_members.go index 08b1d51b0..7fc1d4ced 100644 --- a/vendor/github.com/xanzy/go-gitlab/group_members.go +++ b/vendor/github.com/xanzy/go-gitlab/group_members.go @@ -176,6 +176,50 @@ func (s *GroupMembersService) AddGroupMember(gid interface{}, opt *AddGroupMembe return gm, resp, err } +// ShareWithGroup shares a group with the group. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#share-groups-with-groups +func (s *GroupMembersService) ShareWithGroup(gid interface{}, opt *ShareWithGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/share", pathEscape(group)) + + req, err := s.client.NewRequest("POST", 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 +} + +// DeleteShareWithGroup allows to unshare a group from a group. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#delete-link-sharing-group-with-another-group +func (s *GroupMembersService) DeleteShareWithGroup(gid interface{}, groupID int, options ...RequestOptionFunc) (*Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("groups/%s/share/%d", pathEscape(group), groupID) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + // EditGroupMemberOptions represents the available EditGroupMember() // options. // diff --git a/vendor/github.com/xanzy/go-gitlab/group_milestones.go b/vendor/github.com/xanzy/go-gitlab/group_milestones.go index 21a4d2edf..4cf91f944 100644 --- a/vendor/github.com/xanzy/go-gitlab/group_milestones.go +++ b/vendor/github.com/xanzy/go-gitlab/group_milestones.go @@ -247,3 +247,42 @@ func (s *GroupMilestonesService) GetGroupMilestoneMergeRequests(gid interface{}, return mr, resp, err } + +type BurndownChartEvent struct { + CreatedAt *time.Time `json:"created_at"` + Weight *int `json:"weight"` + Action *string `json:"action"` +} + +// GetGroupMilestoneBurndownChartEventsOptions represents the available +// GetGroupMilestoneBurndownChartEventsOptions() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/group_milestones.html#get-all-burndown-chart-events-for-a-single-milestone-starter +type GetGroupMilestoneBurndownChartEventsOptions ListOptions + +// GetGroupMilestoneBurndownChartEvents gets all merge requests assigned to a +// single group milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/group_milestones.html#get-all-burndown-chart-events-for-a-single-milestone-starter +func (s *GroupMilestonesService) GetGroupMilestoneBurndownChartEvents(gid interface{}, milestone int, opt *GetGroupMilestoneBurndownChartEventsOptions, options ...RequestOptionFunc) ([]*BurndownChartEvent, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/milestones/%d/burndown_events", pathEscape(group), milestone) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var be []*BurndownChartEvent + resp, err := s.client.Do(req, &be) + if err != nil { + return nil, resp, err + } + + return be, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/groups.go b/vendor/github.com/xanzy/go-gitlab/groups.go index 3a1d872d5..8706f6be9 100644 --- a/vendor/github.com/xanzy/go-gitlab/groups.go +++ b/vendor/github.com/xanzy/go-gitlab/groups.go @@ -18,6 +18,7 @@ package gitlab import ( "fmt" + "time" ) // GroupsService handles communication with the group related methods of @@ -32,38 +33,46 @@ type GroupsService struct { // // 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"` - MembershipLock bool `json:"membership_lock"` - 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 ProjectCreationLevelValue `json:"project_creation_level"` - AutoDevopsEnabled bool `json:"auto_devops_enabled"` - SubGroupCreationLevel SubGroupCreationLevelValue `json:"subgroup_creation_level"` - EmailsDisabled bool `json:"emails_disabled"` - MentionsDisabled bool `json:"mentions_disabled"` - RunnersToken string `json:"runners_token"` - SharedProjects []*Project `json:"shared_projects"` - LDAPCN string `json:"ldap_cn"` - LDAPAccess AccessLevelValue `json:"ldap_access"` - LDAPGroupLinks []*LDAPGroupLink `json:"ldap_group_links"` - SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"` - ExtraSharedRunnersMinutesLimit int `json:"extra_shared_runners_minutes_limit"` - MarkedForDeletionOn *ISOTime `json:"marked_for_deletion_on"` + ID int `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Description string `json:"description"` + MembershipLock bool `json:"membership_lock"` + 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 ProjectCreationLevelValue `json:"project_creation_level"` + AutoDevopsEnabled bool `json:"auto_devops_enabled"` + SubGroupCreationLevel SubGroupCreationLevelValue `json:"subgroup_creation_level"` + EmailsDisabled bool `json:"emails_disabled"` + MentionsDisabled bool `json:"mentions_disabled"` + RunnersToken string `json:"runners_token"` + SharedProjects []*Project `json:"shared_projects"` + SharedWithGroups []struct { + GroupID int `json:"group_id"` + GroupName string `json:"group_name"` + GroupFullPath string `json:"group_full_path"` + GroupAccessLevel int `json:"group_access_level"` + ExpiresAt *ISOTime `json:"expires_at"` + } `json:"shared_with_groups"` + LDAPCN string `json:"ldap_cn"` + LDAPAccess AccessLevelValue `json:"ldap_access"` + LDAPGroupLinks []*LDAPGroupLink `json:"ldap_group_links"` + SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"` + ExtraSharedRunnersMinutesLimit int `json:"extra_shared_runners_minutes_limit"` + MarkedForDeletionOn *ISOTime `json:"marked_for_deletion_on"` + CreatedAt *time.Time `json:"created_at"` } type LDAPGroupLink struct { @@ -85,6 +94,7 @@ type ListGroupsOptions struct { 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"` + TopLevelOnly *bool `url:"top_level_only,omitempty" json:"top_level_only,omitempty"` WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` } @@ -388,7 +398,7 @@ func (s *GroupsService) ListGroupLDAPLinks(gid interface{}, options ...RequestOp type AddGroupLDAPLinkOptions struct { CN *string `url:"cn,omitempty" json:"cn,omitempty"` GroupAccess *int `url:"group_access,omitempty" json:"group_access,omitempty"` - Provider *string `url:"provider,omitempty" json:"provider,ommitempty"` + Provider *string `url:"provider,omitempty" json:"provider,omitempty"` } // AddGroupLDAPLink creates a new group LDAP link. Available only for users who diff --git a/vendor/github.com/xanzy/go-gitlab/instance_clusters.go b/vendor/github.com/xanzy/go-gitlab/instance_clusters.go new file mode 100644 index 000000000..415685430 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/instance_clusters.go @@ -0,0 +1,151 @@ +// +// Copyright 2020, Serena Fang +// +// 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" +) + +// InstanceClustersService handles communication with the +// instance clusters related methods of the GitLab API. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_clusters.html +type InstanceClustersService struct { + client *Client +} + +// InstanceCluster represents a GitLab Instance Cluster. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/instance_clusters.html +type InstanceCluster 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"` + ManagementProject *ManagementProject `json:"management_project"` +} + +func (v InstanceCluster) String() string { + return Stringify(v) +} + +// ListClusters gets a list of all instance clusters. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_clusters.html#list-instance-clusters +func (s *InstanceClustersService) ListClusters(options ...RequestOptionFunc) ([]*InstanceCluster, *Response, error) { + u := "admin/clusters" + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var ics []*InstanceCluster + resp, err := s.client.Do(req, &ics) + if err != nil { + return nil, resp, err + } + + return ics, resp, err +} + +// GetCluster gets an instance cluster. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_clusters.html#get-a-single-instance-cluster +func (s *InstanceClustersService) GetCluster(cluster int, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) { + u := fmt.Sprintf("admin/clusters/%d", cluster) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ic := new(InstanceCluster) + resp, err := s.client.Do(req, &ic) + if err != nil { + return nil, resp, err + } + + return ic, resp, err +} + +// AddCluster adds an existing cluster to the instance. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-instance-cluster +func (s *InstanceClustersService) AddCluster(opt *AddClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) { + u := "admin/clusters/add" + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + ic := new(InstanceCluster) + resp, err := s.client.Do(req, ic) + if err != nil { + return nil, resp, err + } + + return ic, resp, err +} + +// EditCluster updates an existing instance cluster. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_clusters.html#edit-instance-cluster +func (s *InstanceClustersService) EditCluster(cluster int, opt *EditClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) { + u := fmt.Sprintf("admin/clusters/%d", cluster) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + ic := new(InstanceCluster) + resp, err := s.client.Do(req, ic) + if err != nil { + return nil, resp, err + } + + return ic, resp, err +} + +// DeleteCluster deletes an existing instance cluster. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_clusters.html#delete-instance-cluster +func (s *InstanceClustersService) DeleteCluster(cluster int, options ...RequestOptionFunc) (*Response, error) { + u := fmt.Sprintf("admin/clusters/%d", cluster) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/instance_variables.go b/vendor/github.com/xanzy/go-gitlab/instance_variables.go new file mode 100644 index 000000000..0d4006b68 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/instance_variables.go @@ -0,0 +1,179 @@ +// +// 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" +) + +// InstanceVariablesService handles communication with the +// instance level CI variables related methods of the GitLab API. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html +type InstanceVariablesService struct { + client *Client +} + +// InstanceVariable represents a GitLab instance level CI Variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html +type InstanceVariable struct { + Key string `json:"key"` + Value string `json:"value"` + VariableType VariableTypeValue `json:"variable_type"` + Protected bool `json:"protected"` + Masked bool `json:"masked"` +} + +func (v InstanceVariable) String() string { + return Stringify(v) +} + +// ListInstanceVariablesOptions represents the available options for listing variables +// for an instance. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#list-all-instance-variables +type ListInstanceVariablesOptions ListOptions + +// ListVariables gets a list of all variables for an instance. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#list-all-instance-variables +func (s *InstanceVariablesService) ListVariables(opt *ListInstanceVariablesOptions, options ...RequestOptionFunc) ([]*InstanceVariable, *Response, error) { + u := "admin/ci/variables" + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var vs []*InstanceVariable + 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/instance_level_ci_variables.html#show-instance-variable-details +func (s *InstanceVariablesService) GetVariable(key string, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) { + u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + v := new(InstanceVariable) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// CreateInstanceVariableOptions represents the available CreateVariable() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#create-instance-variable +type CreateInstanceVariableOptions 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"` +} + +// CreateVariable creates a new instance level CI variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#create-instance-variable +func (s *InstanceVariablesService) CreateVariable(opt *CreateInstanceVariableOptions, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) { + u := "admin/ci/variables" + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + v := new(InstanceVariable) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// UpdateInstanceVariableOptions represents the available UpdateVariable() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#update-instance-variable +type UpdateInstanceVariableOptions 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"` +} + +// UpdateVariable updates the position of an existing +// instance level CI variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#update-instance-variable +func (s *InstanceVariablesService) UpdateVariable(key string, opt *UpdateInstanceVariableOptions, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) { + u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + v := new(InstanceVariable) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// RemoveVariable removes an instance level CI variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#remove-instance-variable +func (s *InstanceVariablesService) RemoveVariable(key string, options ...RequestOptionFunc) (*Response, error) { + u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/issues.go b/vendor/github.com/xanzy/go-gitlab/issues.go index 7b7a583ed..30eae41d3 100644 --- a/vendor/github.com/xanzy/go-gitlab/issues.go +++ b/vendor/github.com/xanzy/go-gitlab/issues.go @@ -17,6 +17,7 @@ package gitlab import ( + "bytes" "encoding/json" "fmt" "net/url" @@ -60,6 +61,16 @@ type IssueReferences struct { Full string `json:"full"` } +// IssueCloser represents a closer of the issue. +type IssueCloser 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"` @@ -83,9 +94,11 @@ type Issue struct { Assignee *IssueAssignee `json:"assignee"` UpdatedAt *time.Time `json:"updated_at"` ClosedAt *time.Time `json:"closed_at"` + ClosedBy *IssueCloser `json:"closed_by"` Title string `json:"title"` CreatedAt *time.Time `json:"created_at"` Labels Labels `json:"labels"` + LabelDetails []*LabelDetails `json:"label_details"` Upvotes int `json:"upvotes"` Downvotes int `json:"downvotes"` DueDate *ISOTime `json:"due_date"` @@ -100,6 +113,8 @@ type Issue struct { Links *IssueLinks `json:"_links"` IssueLinkID int `json:"issue_link_id"` MergeRequestCount int `json:"merge_requests_count"` + EpicIssueID int `json:"epic_issue_id"` + Epic *Epic `json:"epic"` TaskCompletionStatus struct { Count int `json:"count"` CompletedCount int `json:"completed_count"` @@ -110,42 +125,104 @@ func (i Issue) String() string { return Stringify(i) } +func (i *Issue) UnmarshalJSON(data []byte) error { + type alias Issue + + raw := make(map[string]interface{}) + err := json.Unmarshal(data, &raw) + if err != nil { + return err + } + + labelDetails, ok := raw["labels"].([]interface{}) + if ok && len(labelDetails) > 0 { + // We only want to change anything if we got label details. + if _, ok := labelDetails[0].(map[string]interface{}); !ok { + return json.Unmarshal(data, (*alias)(i)) + } + + labels := make([]interface{}, len(labelDetails)) + for i, details := range labelDetails { + labels[i] = details.(map[string]interface{})["name"] + } + + // Set the correct values + raw["labels"] = labels + raw["label_details"] = labelDetails + + data, err = json.Marshal(raw) + if err != nil { + return err + } + } + + return json.Unmarshal(data, (*alias)(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) { + if *l == nil { + return []byte(`null`), nil + } return json.Marshal(strings.Join(*l, ",")) } +// UnmarshalJSON implements the json.Unmarshaler interface. +func (l *Labels) UnmarshalJSON(data []byte) error { + type alias Labels + if !bytes.HasPrefix(data, []byte("[")) { + data = []byte(fmt.Sprintf("[%s]", string(data))) + } + return json.Unmarshal(data, (*alias)(l)) +} + // EncodeValues implements the query.EncodeValues interface func (l *Labels) EncodeValues(key string, v *url.Values) error { v.Set(key, strings.Join(*l, ",")) return nil } +// LabelDetails represents detailed label information. +type LabelDetails struct { + ID int `json:"id"` + Name string `json:"name"` + Color string `json:"color"` + Description string `json:"description"` + DescriptionHTML string `json:"description_html"` + TextColor string `json:"text_color"` +} + // 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"` + State *string `url:"state,omitempty" json:"state,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + NotLabels Labels `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"` + WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + NotMilestone *string `url:"not[milestone],omitempty" json:"not[milestone],omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + NotAuthorID []int `url:"not[author_id],omitempty" json:"not[author_id],omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + NotAssigneeID []int `url:"not[assignee_id],omitempty" json:"not[assignee_id],omitempty"` + AssigneeUsername *string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` + NotMyReactionEmoji []string `url:"not[my_reaction_emoji],omitempty" json:"not[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 @@ -172,22 +249,30 @@ func (s *IssuesService) ListIssues(opt *ListIssuesOptions, options ...RequestOpt // 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"` + State *string `url:"state,omitempty" json:"state,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + NotLabels Labels `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"` + WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` + IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + NotMilestone *string `url:"not[milestone],omitempty" json:"not[milestone],omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + NotAuthorID []int `url:"not[author_id],omitempty" json:"not[author_id],omitempty"` + AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + NotAssigneeID []int `url:"not[assignee_id],omitempty" json:"not[assignee_id],omitempty"` + AssigneeUsername *string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` + NotMyReactionEmoji []string `url:"not[my_reaction_emoji],omitempty" json:"not[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 @@ -220,24 +305,30 @@ func (s *IssuesService) ListGroupIssues(pid interface{}, opt *ListGroupIssuesOpt // 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"` + 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"` + NotLabels Labels `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"` + WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + NotMilestone []string `url:"not[milestone],omitempty" json:"not[milestone],omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + NotAuthorID []int `url:"not[author_id],omitempty" json:"not[author_id],omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + NotAssigneeID []int `url:"not[assignee_id],omitempty" json:"not[assignee_id],omitempty"` + AssigneeUsername *string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` + NotMyReactionEmoji []string `url:"not[my_reaction_emoji],omitempty" json:"not[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 @@ -341,6 +432,8 @@ type UpdateIssueOptions struct { 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"` + AddLabels *Labels `url:"add_labels,comma,omitempty" json:"add_labels,omitempty"` + RemoveLabels *Labels `url:"remove_labels,comma,omitempty" json:"remove_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"` @@ -585,3 +678,28 @@ func (s *IssuesService) ResetSpentTime(pid interface{}, issue int, options ...Re func (s *IssuesService) GetTimeSpent(pid interface{}, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { return s.timeStats.getTimeSpent(pid, "issues", issue, options...) } + +// GetParticipants gets a list of issue participants. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/issues.html#participants-on-issues +func (s *IssuesService) GetParticipants(pid interface{}, issue int, options ...RequestOptionFunc) ([]*BasicUser, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/participants", pathEscape(project), issue) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var bu []*BasicUser + resp, err := s.client.Do(req, &bu) + if err != nil { + return nil, resp, err + } + + return bu, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/issues_statistics.go b/vendor/github.com/xanzy/go-gitlab/issues_statistics.go new file mode 100644 index 000000000..0f61c3f0b --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/issues_statistics.go @@ -0,0 +1,186 @@ +// +// 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" +) + +// IssuesStatisticsService handles communication with the issues statistics +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/issues_statistics.html +type IssuesStatisticsService struct { + client *Client +} + +// IssuesStatistics represents a GitLab issues statistic. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/issues_statistics.html +type IssuesStatistics struct { + Statistics struct { + Counts struct { + All int `json:"all"` + Closed int `json:"closed"` + Opened int `json:"opened"` + } `json:"counts"` + } `json:"statistics"` +} + +func (n IssuesStatistics) String() string { + return Stringify(n) +} + +// GetIssuesStatisticsOptions represents the available GetIssuesStatistics() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issues_statistics.html#get-issues-statistics +type GetIssuesStatisticsOptions struct { + Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` + Milestone *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + AssigneeUsername []string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` + IIDs []int `url:"iids,omitempty" json:"iids,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"` +} + +// GetIssuesStatistics gets issues statistics on all issues the authenticated +// user has access to. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issues_statistics.html#get-issues-statistics +func (s *IssuesStatisticsService) GetIssuesStatistics(opt *GetIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) { + req, err := s.client.NewRequest("GET", "issues_statistics", opt, options) + if err != nil { + return nil, nil, err + } + + is := new(IssuesStatistics) + resp, err := s.client.Do(req, is) + if err != nil { + return nil, resp, err + } + + return is, resp, err +} + +// GetGroupIssuesStatisticsOptions represents the available GetGroupIssuesStatistics() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issues_statistics.html#get-group-issues-statistics +type GetGroupIssuesStatisticsOptions struct { + Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` + IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` + Milestone *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + AssigneeUsername []string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,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"` +} + +// GetGroupIssuesStatistics gets issues count statistics for given group. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issues_statistics.html#get-group-issues-statistics +func (s *IssuesStatisticsService) GetGroupIssuesStatistics(gid interface{}, opt *GetGroupIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/issues_statistics", pathEscape(group)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + is := new(IssuesStatistics) + resp, err := s.client.Do(req, is) + if err != nil { + return nil, resp, err + } + + return is, resp, err +} + +// GetProjectIssuesStatisticsOptions represents the available +// GetProjectIssuesStatistics() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issues_statistics.html#get-project-issues-statistics +type GetProjectIssuesStatisticsOptions struct { + IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` + Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` + Milestone *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + AssigneeUsername []string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,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"` +} + +// GetProjectIssuesStatistics gets issues count statistics for given project. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issues_statistics.html#get-project-issues-statistics +func (s *IssuesStatisticsService) GetProjectIssuesStatistics(pid interface{}, opt *GetProjectIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues_statistics", pathEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + is := new(IssuesStatistics) + resp, err := s.client.Do(req, is) + if err != nil { + return nil, resp, err + } + + return is, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/labels.go b/vendor/github.com/xanzy/go-gitlab/labels.go index 37e727762..0aab8c5e2 100644 --- a/vendor/github.com/xanzy/go-gitlab/labels.go +++ b/vendor/github.com/xanzy/go-gitlab/labels.go @@ -73,7 +73,11 @@ func (l Label) String() string { // ListLabelsOptions represents the available ListLabels() options. // // GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels -type ListLabelsOptions ListOptions +type ListLabelsOptions struct { + ListOptions + WithCounts *bool `url:"with_counts,omitempty" json:"with_counts,omitempty"` + IncludeAncestorGroups *bool `url:"include_ancestor_groups,omitempty" json:"include_ancestor_groups,omitempty"` +} // ListLabels gets all labels for given project. // @@ -99,6 +103,34 @@ func (s *LabelsService) ListLabels(pid interface{}, opt *ListLabelsOptions, opti return l, resp, err } +// GetLabel get a single label for a given project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#get-a-single-project-label +func (s *LabelsService) GetLabel(pid interface{}, labelID interface{}, options ...RequestOptionFunc) (*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", pathEscape(project), label) + + req, err := s.client.NewRequest("GET", u, nil, 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 @@ -248,3 +280,26 @@ func (s *LabelsService) UnsubscribeFromLabel(pid interface{}, labelID interface{ return s.client.Do(req, nil) } + +// PromoteLabel Promotes a project label to a group label. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/labels.html#promote-a-project-label-to-a-group-label +func (s *LabelsService) PromoteLabel(pid interface{}, labelID interface{}, options ...RequestOptionFunc) (*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/promote", pathEscape(project), label) + + req, err := s.client.NewRequest("PUT", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/license.go b/vendor/github.com/xanzy/go-gitlab/license.go index f14aef609..c6deb44e3 100644 --- a/vendor/github.com/xanzy/go-gitlab/license.go +++ b/vendor/github.com/xanzy/go-gitlab/license.go @@ -16,6 +16,8 @@ package gitlab +import "time" + // LicenseService handles communication with the license // related methods of the GitLab API. // @@ -30,17 +32,30 @@ type LicenseService struct { // 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 { + ID int `json:"id"` + Plan string `json:"plan"` + CreatedAt *time.Time `json:"created_at"` + StartsAt *ISOTime `json:"starts_at"` + ExpiresAt *ISOTime `json:"expires_at"` + HistoricalMax int `json:"historical_max"` + MaximumUserCount int `json:"maximum_user_count"` + Expired bool `json:"expired"` + Overage int `json:"overage"` + UserLimit int `json:"user_limit"` + ActiveUsers int `json:"active_users"` + 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"` + // Add on codes that may occur in legacy licenses that don't have a plan yet. + // https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb + AddOns struct { + GitLabAuditorUser int `json:"GitLab_Auditor_User"` + GitLabDeployBoard int `json:"GitLab_DeployBoard"` + GitLabFileLocks int `json:"GitLab_FileLocks"` + GitLabGeo int `json:"GitLab_Geo"` + GitLabServiceDesk int `json:"GitLab_ServiceDesk"` } `json:"add_ons"` } diff --git a/vendor/github.com/xanzy/go-gitlab/merge_requests.go b/vendor/github.com/xanzy/go-gitlab/merge_requests.go index 044a1c584..5bc845eda 100644 --- a/vendor/github.com/xanzy/go-gitlab/merge_requests.go +++ b/vendor/github.com/xanzy/go-gitlab/merge_requests.go @@ -240,7 +240,7 @@ type ListProjectMergeRequestsOptions struct { 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"` + 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"` @@ -399,6 +399,31 @@ func (s *MergeRequestsService) GetMergeRequestChanges(pid interface{}, mergeRequ return m, resp, err } +// GetMergeRequestParticipants gets a list of merge request participants. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/merge_requests.html#get-single-mr-participants +func (s *MergeRequestsService) GetMergeRequestParticipants(pid interface{}, mergeRequest int, options ...RequestOptionFunc) ([]*BasicUser, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/participants", pathEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var ps []*BasicUser + resp, err := s.client.Do(req, &ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + // ListMergeRequestPipelines gets all pipelines for the provided merge request. // // GitLab API docs: @@ -424,6 +449,31 @@ func (s *MergeRequestsService) ListMergeRequestPipelines(pid interface{}, mergeR return p, resp, err } +// CreateMergeRequestPipeline creates a new pipeline for a merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr-pipeline +func (s *MergeRequestsService) CreateMergeRequestPipeline(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*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("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(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. // diff --git a/vendor/github.com/xanzy/go-gitlab/milestones.go b/vendor/github.com/xanzy/go-gitlab/milestones.go index c276ab2e0..eb3e3a302 100644 --- a/vendor/github.com/xanzy/go-gitlab/milestones.go +++ b/vendor/github.com/xanzy/go-gitlab/milestones.go @@ -41,6 +41,7 @@ type Milestone struct { StartDate *ISOTime `json:"start_date"` DueDate *ISOTime `json:"due_date"` State string `json:"state"` + WebURL string `json:"web_url"` UpdatedAt *time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"` } diff --git a/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go b/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go index b9eaa5352..b57adcff3 100644 --- a/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go +++ b/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go @@ -230,6 +230,25 @@ func (s *PipelineSchedulesService) DeletePipelineSchedule(pid interface{}, sched return s.client.Do(req, nil) } +// RunPipelineSchedule triggers a new scheduled pipeline to run immediately. +// +// Gitlab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#run-a-scheduled-pipeline-immediately +func (s *PipelineSchedulesService) RunPipelineSchedule(pid interface{}, schedule int, options ...RequestOptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/play", pathEscape(project), schedule) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + // CreatePipelineScheduleVariableOptions represents the available // CreatePipelineScheduleVariable() options. // diff --git a/vendor/github.com/xanzy/go-gitlab/pipelines.go b/vendor/github.com/xanzy/go-gitlab/pipelines.go index e5b9d99ce..5ab5fe1bf 100644 --- a/vendor/github.com/xanzy/go-gitlab/pipelines.go +++ b/vendor/github.com/xanzy/go-gitlab/pipelines.go @@ -109,7 +109,7 @@ type ListProjectPipelinesOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Username *string `url:"username,omitempty" json:"username,omitempty"` UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"update_before,omitempty" json:"updated_before,omitempty"` + UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } diff --git a/vendor/github.com/xanzy/go-gitlab/project_mirror.go b/vendor/github.com/xanzy/go-gitlab/project_mirror.go new file mode 100644 index 000000000..aa7a1aa5d --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/project_mirror.go @@ -0,0 +1,145 @@ +// +// 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" +) + +// ProjectMirrorService handles communication with the project mirror +// related methods of the GitLab API. +// +// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html +type ProjectMirrorService struct { + client *Client +} + +// ProjectMirror represents a project mirror configuration. +// +// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html +type ProjectMirror struct { + Enabled bool `json:"enabled"` + ID int `json:"id"` + LastError string `json:"last_error"` + LastSuccessfulUpdateAt *time.Time `json:"last_successful_update_at"` + LastUpdateAt *time.Time `json:"last_update_at"` + LastUpdateStartedAt *time.Time `json:"last_update_started_at"` + OnlyProtectedBranches bool `json:"only_protected_branches"` + KeepDivergentRefs bool `json:"keep_divergent_refs"` + UpdateStatus string `json:"update_status"` + URL string `json:"url"` +} + +// ListProjectMirror gets a list of mirrors configured on the project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/remote_mirrors.html#list-a-projects-remote-mirrors +func (s *ProjectMirrorService) ListProjectMirror(pid interface{}, options ...RequestOptionFunc) ([]*ProjectMirror, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/remote_mirrors", pathEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var pm []*ProjectMirror + resp, err := s.client.Do(req, &pm) + if err != nil { + return nil, resp, err + } + + return pm, resp, err + +} + +// AddProjectMirrorOptions contains the properties requires to create +// a new project mirror. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror +type AddProjectMirrorOptions struct { + URL *string `url:"url,omitempty" json:"url,omitempty"` + Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` + OnlyProtectedBranches *bool `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"` + KeepDivergentRefs *bool `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"` +} + +// AddProjectMirror creates a new mirror on the project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror +func (s *ProjectMirrorService) AddProjectMirror(pid interface{}, opt *AddProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/remote_mirrors", pathEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + pm := new(ProjectMirror) + resp, err := s.client.Do(req, pm) + if err != nil { + return nil, resp, err + } + + return pm, resp, err +} + +// EditProjectMirrorOptions contains the properties requires to edit +// an existing project mirror. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes +type EditProjectMirrorOptions struct { + Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` + OnlyProtectedBranches *bool `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"` + KeepDivergentRefs *bool `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"` +} + +// EditProjectMirror updates a project team member to a specified access level.. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes +func (s *ProjectMirrorService) EditProjectMirror(pid interface{}, mirror int, opt *EditProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/remote_mirrors/%d", pathEscape(project), mirror) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + pm := new(ProjectMirror) + resp, err := s.client.Do(req, pm) + if err != nil { + return nil, resp, err + } + + return pm, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/project_snippets.go b/vendor/github.com/xanzy/go-gitlab/project_snippets.go index 59ab1452f..8789db707 100644 --- a/vendor/github.com/xanzy/go-gitlab/project_snippets.go +++ b/vendor/github.com/xanzy/go-gitlab/project_snippets.go @@ -91,7 +91,7 @@ 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"` + Content *string `url:"content,omitempty" json:"content,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` } @@ -129,7 +129,7 @@ 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"` + Content *string `url:"content,omitempty" json:"content,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` } diff --git a/vendor/github.com/xanzy/go-gitlab/projects.go b/vendor/github.com/xanzy/go-gitlab/projects.go index ad454787a..cc1ba79c8 100644 --- a/vendor/github.com/xanzy/go-gitlab/projects.go +++ b/vendor/github.com/xanzy/go-gitlab/projects.go @@ -38,57 +38,68 @@ type ProjectsService struct { // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html type Project struct { - ID int `json:"id"` - Description string `json:"description"` - DefaultBranch string `json:"default_branch"` - Public bool `json:"public"` - Visibility VisibilityValue `json:"visibility"` - SSHURLToRepo string `json:"ssh_url_to_repo"` - HTTPURLToRepo string `json:"http_url_to_repo"` - WebURL string `json:"web_url"` - ReadmeURL string `json:"readme_url"` - TagList []string `json:"tag_list"` - Owner *User `json:"owner"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - IssuesEnabled bool `json:"issues_enabled"` - OpenIssuesCount int `json:"open_issues_count"` - MergeRequestsEnabled bool `json:"merge_requests_enabled"` - ApprovalsBeforeMerge int `json:"approvals_before_merge"` - JobsEnabled bool `json:"jobs_enabled"` - WikiEnabled bool `json:"wiki_enabled"` - SnippetsEnabled bool `json:"snippets_enabled"` - ResolveOutdatedDiffDiscussions bool `json:"resolve_outdated_diff_discussions"` - ContainerRegistryEnabled bool `json:"container_registry_enabled"` - CreatedAt *time.Time `json:"created_at,omitempty"` - LastActivityAt *time.Time `json:"last_activity_at,omitempty"` - CreatorID int `json:"creator_id"` - Namespace *ProjectNamespace `json:"namespace"` - ImportStatus string `json:"import_status"` - ImportError string `json:"import_error"` - Permissions *Permissions `json:"permissions"` - MarkedForDeletionAt *ISOTime `json:"marked_for_deletion_at"` - Archived bool `json:"archived"` - AvatarURL string `json:"avatar_url"` - SharedRunnersEnabled bool `json:"shared_runners_enabled"` - ForksCount int `json:"forks_count"` - StarCount int `json:"star_count"` - RunnersToken string `json:"runners_token"` - PublicBuilds bool `json:"public_builds"` - OnlyAllowMergeIfPipelineSucceeds bool `json:"only_allow_merge_if_pipeline_succeeds"` - OnlyAllowMergeIfAllDiscussionsAreResolved bool `json:"only_allow_merge_if_all_discussions_are_resolved"` - RemoveSourceBranchAfterMerge bool `json:"remove_source_branch_after_merge"` - LFSEnabled bool `json:"lfs_enabled"` - RequestAccessEnabled bool `json:"request_access_enabled"` - MergeMethod MergeMethodValue `json:"merge_method"` - ForkedFromProject *ForkParent `json:"forked_from_project"` - Mirror bool `json:"mirror"` - MirrorUserID int `json:"mirror_user_id"` - MirrorTriggerBuilds bool `json:"mirror_trigger_builds"` - OnlyMirrorProtectedBranches bool `json:"only_mirror_protected_branches"` - MirrorOverwritesDivergedBranches bool `json:"mirror_overwrites_diverged_branches"` + ID int `json:"id"` + Description string `json:"description"` + DefaultBranch string `json:"default_branch"` + Public bool `json:"public"` + Visibility VisibilityValue `json:"visibility"` + SSHURLToRepo string `json:"ssh_url_to_repo"` + HTTPURLToRepo string `json:"http_url_to_repo"` + WebURL string `json:"web_url"` + ReadmeURL string `json:"readme_url"` + TagList []string `json:"tag_list"` + Owner *User `json:"owner"` + Name string `json:"name"` + NameWithNamespace string `json:"name_with_namespace"` + Path string `json:"path"` + PathWithNamespace string `json:"path_with_namespace"` + IssuesEnabled bool `json:"issues_enabled"` + OpenIssuesCount int `json:"open_issues_count"` + MergeRequestsEnabled bool `json:"merge_requests_enabled"` + ApprovalsBeforeMerge int `json:"approvals_before_merge"` + JobsEnabled bool `json:"jobs_enabled"` + WikiEnabled bool `json:"wiki_enabled"` + SnippetsEnabled bool `json:"snippets_enabled"` + ResolveOutdatedDiffDiscussions bool `json:"resolve_outdated_diff_discussions"` + ContainerRegistryEnabled bool `json:"container_registry_enabled"` + CreatedAt *time.Time `json:"created_at,omitempty"` + LastActivityAt *time.Time `json:"last_activity_at,omitempty"` + CreatorID int `json:"creator_id"` + Namespace *ProjectNamespace `json:"namespace"` + ImportStatus string `json:"import_status"` + ImportError string `json:"import_error"` + Permissions *Permissions `json:"permissions"` + MarkedForDeletionAt *ISOTime `json:"marked_for_deletion_at"` + Archived bool `json:"archived"` + AvatarURL string `json:"avatar_url"` + SharedRunnersEnabled bool `json:"shared_runners_enabled"` + ForksCount int `json:"forks_count"` + StarCount int `json:"star_count"` + RunnersToken string `json:"runners_token"` + PublicBuilds bool `json:"public_builds"` + OnlyAllowMergeIfPipelineSucceeds bool `json:"only_allow_merge_if_pipeline_succeeds"` + OnlyAllowMergeIfAllDiscussionsAreResolved bool `json:"only_allow_merge_if_all_discussions_are_resolved"` + RemoveSourceBranchAfterMerge bool `json:"remove_source_branch_after_merge"` + LFSEnabled bool `json:"lfs_enabled"` + RequestAccessEnabled bool `json:"request_access_enabled"` + MergeMethod MergeMethodValue `json:"merge_method"` + ForkedFromProject *ForkParent `json:"forked_from_project"` + Mirror bool `json:"mirror"` + MirrorUserID int `json:"mirror_user_id"` + MirrorTriggerBuilds bool `json:"mirror_trigger_builds"` + OnlyMirrorProtectedBranches bool `json:"only_mirror_protected_branches"` + MirrorOverwritesDivergedBranches bool `json:"mirror_overwrites_diverged_branches"` + ServiceDeskEnabled bool `json:"service_desk_enabled"` + ServiceDeskAddress string `json:"service_desk_address"` + IssuesAccessLevel AccessControlValue `json:"issues_access_level"` + RepositoryAccessLevel AccessControlValue `json:"repository_access_level"` + MergeRequestsAccessLevel AccessControlValue `json:"merge_requests_access_level"` + ForkingAccessLevel AccessControlValue `json:"forking_access_level"` + WikiAccessLevel AccessControlValue `json:"wiki_access_level"` + BuildsAccessLevel AccessControlValue `json:"builds_access_level"` + SnippetsAccessLevel AccessControlValue `json:"snippets_access_level"` + PagesAccessLevel AccessControlValue `json:"pages_access_level"` + AutocloseReferencedIssues bool `json:"autoclose_referenced_issues"` SharedWithGroups []struct { GroupID int `json:"group_id"` GroupName string `json:"group_name"` @@ -213,20 +224,27 @@ func (s ProjectApprovalRule) String() string { type ListProjectsOptions 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"` + SearchNamespaces *bool `url:"search_namespaces,omitempty" json:"search_namespaces,omitempty"` Simple *bool `url:"simple,omitempty" json:"simple,omitempty"` Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` Membership *bool `url:"membership,omitempty" json:"membership,omitempty"` Starred *bool `url:"starred,omitempty" json:"starred,omitempty"` Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` + WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"` WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"` - MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"` - WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` WithProgrammingLanguage *string `url:"with_programming_language,omitempty" json:"with_programming_language,omitempty"` + WikiChecksumFailed *bool `url:"wiki_checksum_failed,omitempty" json:"wiki_checksum_failed,omitempty"` + RepositoryChecksumFailed *bool `url:"repository_checksum_failed,omitempty" json:"repository_checksum_failed,omitempty"` + MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"` + IDAfter *int `url:"id_after,omitempty" json:"id_after,omitempty"` + IDBefore *int `url:"id_before,omitempty" json:"id_before,omitempty"` + LastActivityAfter *time.Time `url:"last_activity_after,omitempty" json:"last_activity_after,omitempty"` + LastActivityBefore *time.Time `url:"last_activity_before,omitempty" json:"last_activity_before,omitempty"` } // ListProjects gets a list of projects accessible by the authenticated user. @@ -444,39 +462,60 @@ func (s *ProjectsService) GetProjectEvents(pid interface{}, opt *GetProjectEvent // // GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#create-project type CreateProjectOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Path *string `url:"path,omitempty" json:"path,omitempty"` - DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` - NamespaceID *int `url:"namespace_id,omitempty" json:"namespace_id,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` - MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` - JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` - WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` - SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` - ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` - ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` - SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` - ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` - PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` - OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` - OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` - MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` - RemoveSourceBranchAfterMerge *bool `url:"remove_source_branch_after_merge,omitempty" json:"remove_source_branch_after_merge,omitempty"` - LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` - RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` - TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` - PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"` - BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` - CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` - ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` - Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` - MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` - InitializeWithReadme *bool `url:"initialize_with_readme,omitempty" json:"initialize_with_readme,omitempty"` - TemplateName *string `url:"template_name,omitempty" json:"template_name,omitempty"` - UseCustomTemplate *bool `url:"use_custom_template,omitempty" json:"use_custom_template,omitempty"` - GroupWithProjectTemplatesID *int `url:"group_with_project_templates_id,omitempty" json:"group_with_project_templates_id,omitempty"` + Name *string `url:"name,omitempty" json:"name,omitempty"` + Path *string `url:"path,omitempty" json:"path,omitempty"` + NamespaceID *int `url:"namespace_id,omitempty" json:"namespace_id,omitempty"` + DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + IssuesAccessLevel *AccessControlValue `url:"issues_access_level,omitempty" json:"issues_access_level,omitempty"` + RepositoryAccessLevel *AccessControlValue `url:"repository_access_level,omitempty" json:"repository_access_level,omitempty"` + MergeRequestsAccessLevel *AccessControlValue `url:"merge_requests_access_level,omitempty" json:"merge_requests_access_level,omitempty"` + ForkingAccessLevel *AccessControlValue `url:"forking_access_level,omitempty" json:"forking_access_level,omitempty"` + BuildsAccessLevel *AccessControlValue `url:"builds_access_level,omitempty" json:"builds_access_level,omitempty"` + WikiAccessLevel *AccessControlValue `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"` + SnippetsAccessLevel *AccessControlValue `url:"snippets_access_level,omitempty" json:"snippets_access_level,omitempty"` + PagesAccessLevel *AccessControlValue `url:"pages_access_level,omitempty" json:"pages_access_level,omitempty"` + EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"` + ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` + ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` + SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` + ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` + PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` + OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` + OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` + MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` + RemoveSourceBranchAfterMerge *bool `url:"remove_source_branch_after_merge,omitempty" json:"remove_source_branch_after_merge,omitempty"` + LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` + RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` + TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` + PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"` + BuildGitStrategy *string `url:"build_git_strategy,omitempty" json:"build_git_strategy,omitempty"` + BuildTimeout *int `url:"build_timeout,omitempty" json:"build_timeout,omitempty"` + AutoCancelPendingPipelines *string `url:"auto_cancel_pending_pipelines,omitempty" json:"auto_cancel_pending_pipelines,omitempty"` + BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` + CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` + AutoDevopsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"` + AutoDevopsDeployStrategy *string `url:"auto_devops_deploy_strategy,omitempty" json:"auto_devops_deploy_strategy,omitempty"` + ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` + ExternalAuthorizationClassificationLabel *string `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"` + Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` + MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` + InitializeWithReadme *bool `url:"initialize_with_readme,omitempty" json:"initialize_with_readme,omitempty"` + TemplateName *string `url:"template_name,omitempty" json:"template_name,omitempty"` + TemplateProjectID *int `url:"template_project_id,omitempty" json:"template_project_id,omitempty"` + UseCustomTemplate *bool `url:"use_custom_template,omitempty" json:"use_custom_template,omitempty"` + GroupWithProjectTemplatesID *int `url:"group_with_project_templates_id,omitempty" json:"group_with_project_templates_id,omitempty"` + PackagesEnabled *bool `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"` + ServiceDeskEnabled *bool `url:"service_desk_enabled,omitempty" json:"service_desk_enabled,omitempty"` + AutocloseReferencedIssues *bool `url:"autoclose_referenced_issues,omitempty" json:"autoclose_referenced_issues,omitempty"` + + // Deprecated members + IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` + MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` + JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` + WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` + SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` } // CreateProject creates a new project owned by the authenticated user. @@ -530,39 +569,57 @@ func (s *ProjectsService) CreateProjectForUser(user int, opt *CreateProjectForUs // // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project type EditProjectOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Path *string `url:"path,omitempty" json:"path,omitempty"` - DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` - MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` - JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` - WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` - SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` - ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` - ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` - SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` - ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` - PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` - OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` - OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` - MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` - RemoveSourceBranchAfterMerge *bool `url:"remove_source_branch_after_merge,omitempty" json:"remove_source_branch_after_merge,omitempty"` - LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` - RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` - TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` - BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` - CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` - CIDefaultGitDepth *int `url:"ci_default_git_depth,omitempty" json:"ci_default_git_depth,omitempty"` - ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` - ExternalAuthorizationClassificationLabel *string `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"` - Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` - MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` - MirrorUserID *int `url:"mirror_user_id,omitempty" json:"mirror_user_id,omitempty"` - OnlyMirrorProtectedBranches *bool `url:"only_mirror_protected_branches,omitempty" json:"only_mirror_protected_branches,omitempty"` - MirrorOverwritesDivergedBranches *bool `url:"mirror_overwrites_diverged_branches,omitempty" json:"mirror_overwrites_diverged_branches,omitempty"` - PackagesEnabled *bool `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"` + Name *string `url:"name,omitempty" json:"name,omitempty"` + Path *string `url:"path,omitempty" json:"path,omitempty"` + DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + IssuesAccessLevel *AccessControlValue `url:"issues_access_level,omitempty" json:"issues_access_level,omitempty"` + RepositoryAccessLevel *AccessControlValue `url:"repository_access_level,omitempty" json:"repository_access_level,omitempty"` + MergeRequestsAccessLevel *AccessControlValue `url:"merge_requests_access_level,omitempty" json:"merge_requests_access_level,omitempty"` + ForkingAccessLevel *AccessControlValue `url:"forking_access_level,omitempty" json:"forking_access_level,omitempty"` + BuildsAccessLevel *AccessControlValue `url:"builds_access_level,omitempty" json:"builds_access_level,omitempty"` + WikiAccessLevel *AccessControlValue `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"` + SnippetsAccessLevel *AccessControlValue `url:"snippets_access_level,omitempty" json:"snippets_access_level,omitempty"` + PagesAccessLevel *AccessControlValue `url:"pages_access_level,omitempty" json:"pages_access_level,omitempty"` + EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"` + ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` + ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` + SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` + ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` + PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` + OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` + OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` + MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` + RemoveSourceBranchAfterMerge *bool `url:"remove_source_branch_after_merge,omitempty" json:"remove_source_branch_after_merge,omitempty"` + LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` + RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` + TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` + BuildGitStrategy *string `url:"build_git_strategy,omitempty" json:"build_git_strategy,omitempty"` + BuildTimeout *int `url:"build_timeout,omitempty" json:"build_timeout,omitempty"` + AutoCancelPendingPipelines *string `url:"auto_cancel_pending_pipelines,omitempty" json:"auto_cancel_pending_pipelines,omitempty"` + BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` + CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` + CIDefaultGitDepth *int `url:"ci_default_git_depth,omitempty" json:"ci_default_git_depth,omitempty"` + AutoDevopsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"` + AutoDevopsDeployStrategy *string `url:"auto_devops_deploy_strategy,omitempty" json:"auto_devops_deploy_strategy,omitempty"` + ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` + ExternalAuthorizationClassificationLabel *string `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"` + Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` + MirrorUserID *int `url:"mirror_user_id,omitempty" json:"mirror_user_id,omitempty"` + MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` + OnlyMirrorProtectedBranches *bool `url:"only_mirror_protected_branches,omitempty" json:"only_mirror_protected_branches,omitempty"` + MirrorOverwritesDivergedBranches *bool `url:"mirror_overwrites_diverged_branches,omitempty" json:"mirror_overwrites_diverged_branches,omitempty"` + PackagesEnabled *bool `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"` + ServiceDeskEnabled *bool `url:"service_desk_enabled,omitempty" json:"service_desk_enabled,omitempty"` + AutocloseReferencedIssues *bool `url:"autoclose_referenced_issues,omitempty" json:"autoclose_referenced_issues,omitempty"` + + // Deprecated members + IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` + MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` + JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` + WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` + SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` } // EditProject updates an existing project. @@ -816,6 +873,7 @@ type ProjectHook struct { ConfidentialNoteEvents bool `json:"confidential_note_events"` ProjectID int `json:"project_id"` PushEvents bool `json:"push_events"` + PushEventsBranchFilter string `json:"push_events_branch_filter"` IssuesEvents bool `json:"issues_events"` ConfidentialIssuesEvents bool `json:"confidential_issues_events"` MergeRequestsEvents bool `json:"merge_requests_events"` @@ -891,6 +949,7 @@ type AddProjectHookOptions struct { URL *string `url:"url,omitempty" json:"url,omitempty"` ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` + PushEventsBranchFilter *string `url:"push_events_branch_filter,omitempty" json:"push_events_branch_filter,omitempty"` IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` @@ -936,6 +995,7 @@ type EditProjectHookOptions struct { URL *string `url:"url,omitempty" json:"url,omitempty"` ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` + PushEventsBranchFilter *string `url:"push_events_branch_filter,omitempty" json:"push_events_branch_filter,omitempty"` IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` diff --git a/vendor/github.com/xanzy/go-gitlab/protected_branches.go b/vendor/github.com/xanzy/go-gitlab/protected_branches.go index bc7d14cd2..8c1fcff1f 100644 --- a/vendor/github.com/xanzy/go-gitlab/protected_branches.go +++ b/vendor/github.com/xanzy/go-gitlab/protected_branches.go @@ -37,6 +37,8 @@ type ProtectedBranchesService struct { // https://docs.gitlab.com/ce/api/protected_branches.html#protected-branches-api type BranchAccessDescription struct { AccessLevel AccessLevelValue `json:"access_level"` + UserID int `json:"user_id"` + GroupID int `json:"group_id"` AccessLevelDescription string `json:"access_level_description"` } @@ -49,6 +51,7 @@ type ProtectedBranch struct { Name string `json:"name"` PushAccessLevels []*BranchAccessDescription `json:"push_access_levels"` MergeAccessLevels []*BranchAccessDescription `json:"merge_access_levels"` + UnprotectAccessLevels []*BranchAccessDescription `json:"unprotect_access_levels"` CodeOwnerApprovalRequired bool `json:"code_owner_approval_required"` } @@ -115,10 +118,24 @@ func (s *ProtectedBranchesService) GetProtectedBranch(pid interface{}, branch st // 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"` - CodeOwnerApprovalRequired *bool `url:"code_owner_approval_required,omitempty" json:"code_owner_approval_required,omitempty"` + 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"` + UnprotectAccessLevel *AccessLevelValue `url:"unprotect_access_level,omitempty" json:"unprotect_access_level,omitempty"` + AllowedToPush []*ProtectBranchPermissionOptions `url:"allowed_to_push,omitempty" json:"allowed_to_push,omitempty"` + AllowedToMerge []*ProtectBranchPermissionOptions `url:"allowed_to_merge,omitempty" json:"allowed_to_merge,omitempty"` + AllowedToUnprotect []*ProtectBranchPermissionOptions `url:"allowed_to_unprotect,omitempty" json:"allowed_to_unprotect,omitempty"` + CodeOwnerApprovalRequired *bool `url:"code_owner_approval_required,omitempty" json:"code_owner_approval_required,omitempty"` +} + +// ProtectBranchPermissionOptions represents a branch permission option. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches +type ProtectBranchPermissionOptions struct { + UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` + GroupID *int `url:"group_id,omitempty" json:"group_id,omitempty"` + AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` } // ProtectRepositoryBranches protects a single repository branch or several diff --git a/vendor/github.com/xanzy/go-gitlab/repository_files.go b/vendor/github.com/xanzy/go-gitlab/repository_files.go index 7cd21d0c5..cc954c27d 100644 --- a/vendor/github.com/xanzy/go-gitlab/repository_files.go +++ b/vendor/github.com/xanzy/go-gitlab/repository_files.go @@ -21,6 +21,7 @@ import ( "fmt" "net/url" "strconv" + "time" ) // RepositoryFilesService handles communication with the repository files @@ -35,15 +36,16 @@ type RepositoryFilesService struct { // // 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"` + 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"` + LastCommitID string `json:"last_commit_id"` } func (r File) String() string { @@ -123,13 +125,14 @@ func (s *RepositoryFilesService) GetFileMetaData(pid interface{}, fileName strin } 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"), + 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"), + LastCommitID: resp.Header.Get("X-Gitlab-Last-Commit-Id"), } if sizeString := resp.Header.Get("X-Gitlab-Size"); sizeString != "" { @@ -142,6 +145,66 @@ func (s *RepositoryFilesService) GetFileMetaData(pid interface{}, fileName strin return f, resp, err } +// FileBlameRange represents one item of blame information. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html +type FileBlameRange struct { + Commit struct { + ID string `json:"id"` + ParentIDs []string `json:"parent_ids"` + Message string `json:"message"` + AuthoredDate *time.Time `json:"authored_date"` + AuthorName string `json:"author_name"` + AuthorEmail string `json:"author_email"` + CommittedDate *time.Time `json:"committed_date"` + CommitterName string `json:"committer_name"` + CommitterEmail string `json:"committer_email"` + } `json:"commit"` + Lines []string `json:"lines"` +} + +func (b FileBlameRange) String() string { + return Stringify(b) +} + +// GetFileBlameOptions represents the available GetFileBlame() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#get-file-blame-from-repository +type GetFileBlameOptions struct { + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` +} + +// GetFileBlame allows you to receive blame information. Each blame range +// contains lines and corresponding commit info. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#get-file-blame-from-repository +func (s *RepositoryFilesService) GetFileBlame(pid interface{}, file string, opt *GetFileBlameOptions, options ...RequestOptionFunc) ([]*FileBlameRange, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf( + "projects/%s/repository/files/%s/blame", + pathEscape(project), + url.PathEscape(file), + ) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var br []*FileBlameRange + resp, err := s.client.Do(req, &br) + if err != nil { + return nil, resp, err + } + + return br, resp, err +} + // GetRawFileOptions represents the available GetRawFile() options. // // GitLab API docs: @@ -282,9 +345,11 @@ func (s *RepositoryFilesService) UpdateFile(pid interface{}, fileName string, op // 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"` + StartBranch *string `url:"start_branch,omitempty" json:"start_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"` + LastCommitID *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"` } // DeleteFile deletes an existing file in a repository diff --git a/vendor/github.com/xanzy/go-gitlab/runners.go b/vendor/github.com/xanzy/go-gitlab/runners.go index 775c3e11f..96c23467b 100644 --- a/vendor/github.com/xanzy/go-gitlab/runners.go +++ b/vendor/github.com/xanzy/go-gitlab/runners.go @@ -336,6 +336,44 @@ func (s *RunnersService) DisableProjectRunner(pid interface{}, runner int, optio return s.client.Do(req, nil) } +// ListGroupsRunnersOptions represents the available ListGroupsRunners() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/runners.html#list-groups-runners +type ListGroupsRunnersOptions struct { + ListOptions + 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"` +} + +// ListGroupsRunners lists all runners (specific and shared) available in the +// group as well it’s ancestor groups. Shared runners are listed if at least one +// shared runner is defined. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/runners.html#list-groups-runners +func (s *RunnersService) ListGroupsRunners(gid interface{}, opt *ListGroupsRunnersOptions, options ...RequestOptionFunc) ([]*Runner, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/runners", pathEscape(group)) + + 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 +} + // RegisterNewRunnerOptions represents the available RegisterNewRunner() // options. // diff --git a/vendor/github.com/xanzy/go-gitlab/services.go b/vendor/github.com/xanzy/go-gitlab/services.go index 0e649804e..0f36c4eb9 100644 --- a/vendor/github.com/xanzy/go-gitlab/services.go +++ b/vendor/github.com/xanzy/go-gitlab/services.go @@ -54,6 +54,30 @@ type Service struct { WikiPageEvents bool `json:"wiki_page_events"` } +// ListServices gets a list of all active services. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/services.html#list-all-active-services +func (s *ServicesService) ListServices(pid interface{}, options ...RequestOptionFunc) ([]*Service, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/services", pathEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var svcs []*Service + resp, err := s.client.Do(req, &svcs) + if err != nil { + return nil, resp, err + } + + return svcs, resp, err +} + // DroneCIService represents Drone CI service settings. // // GitLab API docs: @@ -251,7 +275,7 @@ type GithubService struct { // 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"` + StaticContext bool `json:"static_context,omitempty"` } // GetGithubService gets Github service settings for a project. @@ -665,7 +689,17 @@ type MicrosoftTeamsService struct { // GitLab API docs: // https://docs.gitlab.com/ce/api/services.html#microsoft-teams type MicrosoftTeamsServiceProperties struct { - WebHook string `json:"webhook"` + WebHook string `json:"webhook"` + NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines"` + BranchesToBeNotified string `json:"branches_to_be_notified"` + IssuesEvents BoolValue `json:"issues_events"` + ConfidentialIssuesEvents BoolValue `json:"confidential_issues_events"` + MergeRequestsEvents BoolValue `json:"merge_requests_events"` + TagPushEvents BoolValue `json:"tag_push_events"` + NoteEvents BoolValue `json:"note_events"` + ConfidentialNoteEvents BoolValue `json:"confidential_note_events"` + PipelineEvents BoolValue `json:"pipeline_events"` + WikiPageEvents BoolValue `json:"wiki_page_events"` } // GetMicrosoftTeamsService gets MicrosoftTeams service settings for a project. @@ -699,7 +733,18 @@ func (s *ServicesService) GetMicrosoftTeamsService(pid interface{}, options ...R // 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"` + WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"` + NotifyOnlyBrokenPipelines *bool `url:"notify_only_broken_pipelines" json:"notify_only_broken_pipelines"` + BranchesToBeNotified *string `url:"branches_to_be_notified,omitempty" json:"branches_to_be_notified,omitempty"` + PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` + IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` + ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` + MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` + TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` + NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` + ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` + PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` + WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` } // SetMicrosoftTeamsService sets Microsoft Teams service for a project @@ -756,6 +801,7 @@ type PipelinesEmailProperties struct { Recipients string `json:"recipients,omitempty"` NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines,omitempty"` NotifyOnlyDefaultBranch BoolValue `json:"notify_only_default_branch,omitempty"` + BranchesToBeNotified string `json:"branches_to_be_notified,omitempty"` } // GetPipelinesEmailService gets Pipelines Email service settings for a project. diff --git a/vendor/github.com/xanzy/go-gitlab/tags.go b/vendor/github.com/xanzy/go-gitlab/tags.go index 3c49dc26b..32fdeb4af 100644 --- a/vendor/github.com/xanzy/go-gitlab/tags.go +++ b/vendor/github.com/xanzy/go-gitlab/tags.go @@ -58,6 +58,7 @@ func (t Tag) String() string { type ListTagsOptions struct { ListOptions OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Search *string `url:"search,omitempty" json:"search,omitempty"` Sort *string `url:"sort,omitempty" json:"sort,omitempty"` } diff --git a/vendor/github.com/xanzy/go-gitlab/types.go b/vendor/github.com/xanzy/go-gitlab/types.go new file mode 100644 index 000000000..bebb980bd --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/types.go @@ -0,0 +1,430 @@ +package gitlab + +import ( + "encoding/json" + "errors" + "fmt" + "net/url" + "time" +) + +// AccessControlValue represents an access control value within GitLab, +// used for managing access to certain project features. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html +type AccessControlValue string + +// List of available access control values. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html +const ( + DisabledAccessControl AccessControlValue = "disabled" + EnabledAccessControl AccessControlValue = "enabled" + PrivateAccessControl AccessControlValue = "private" + PublicAccessControl AccessControlValue = "public" +) + +// AccessControl is a helper routine that allocates a new AccessControlValue +// to store v and returns a pointer to it. +func AccessControl(v AccessControlValue) *AccessControlValue { + p := new(AccessControlValue) + *p = v + return p +} + +// 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 +) + +// 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 +} + +// BuildStateValue represents a GitLab build state. +type BuildStateValue string + +// These constants represent all valid build states. +const ( + Pending BuildStateValue = "pending" + Created BuildStateValue = "created" + Running BuildStateValue = "running" + Success BuildStateValue = "success" + Failed BuildStateValue = "failed" + Canceled BuildStateValue = "canceled" + Skipped BuildStateValue = "skipped" + Manual BuildStateValue = "manual" +) + +// 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 +} + +// DeploymentStatusValue represents a Gitlab deployment status. +type DeploymentStatusValue string + +// These constants represent all valid deployment statuses. +const ( + DeploymentStatusCreated DeploymentStatusValue = "created" + DeploymentStatusRunning DeploymentStatusValue = "running" + DeploymentStatusSuccess DeploymentStatusValue = "success" + DeploymentStatusFailed DeploymentStatusValue = "failed" + DeploymentStatusCanceled DeploymentStatusValue = "canceled" +) + +// DeploymentStatus is a helper routine that allocates a new +// DeploymentStatusValue to store v and returns a pointer to it. +func DeploymentStatus(v DeploymentStatusValue) *DeploymentStatusValue { + p := new(DeploymentStatusValue) + *p = v + return p +} + +// 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, +} + +// 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 +} + +// 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" +) + +// 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 +} + +// ProjectCreationLevelValue represents a project creation level within GitLab. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +type ProjectCreationLevelValue string + +// List of available project creation levels. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +const ( + NoOneProjectCreation ProjectCreationLevelValue = "noone" + MaintainerProjectCreation ProjectCreationLevelValue = "maintainer" + DeveloperProjectCreation ProjectCreationLevelValue = "developer" +) + +// ProjectCreationLevel is a helper routine that allocates a new ProjectCreationLevelValue +// to store v and returns a pointer to it. +func ProjectCreationLevel(v ProjectCreationLevelValue) *ProjectCreationLevelValue { + p := new(ProjectCreationLevelValue) + *p = v + return p +} + +// SubGroupCreationLevelValue represents a sub group creation level within GitLab. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +type SubGroupCreationLevelValue string + +// List of available sub group creation levels. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +const ( + OwnerSubGroupCreationLevelValue SubGroupCreationLevelValue = "owner" + MaintainerSubGroupCreationLevelValue SubGroupCreationLevelValue = "maintainer" +) + +// SubGroupCreationLevel is a helper routine that allocates a new SubGroupCreationLevelValue +// to store v and returns a pointer to it. +func SubGroupCreationLevel(v SubGroupCreationLevelValue) *SubGroupCreationLevelValue { + p := new(SubGroupCreationLevelValue) + *p = v + return p +} + +// 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" +) + +// 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 +} + +// 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" +) + +// 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 +} + +// 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" +) + +// 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 +} + +// BoolValue is a boolean value with advanced json unmarshaling features. +type BoolValue bool + +// UnmarshalJSON allows 1, 0, "true", and "false" to be considered as boolean values +// Needed for: +// https://gitlab.com/gitlab-org/gitlab-ce/issues/50122 +// https://gitlab.com/gitlab-org/gitlab/-/issues/233941 +// https://github.com/gitlabhq/terraform-provider-gitlab/issues/348 +func (t *BoolValue) UnmarshalJSON(b []byte) error { + switch string(b) { + case `"1"`: + *t = true + return nil + case `"0"`: + *t = false + return nil + case `"true"`: + *t = true + return nil + case `"false"`: + *t = false + return nil + default: + var v bool + err := json.Unmarshal(b, &v) + *t = BoolValue(v) + return err + } +} diff --git a/vendor/github.com/xanzy/go-gitlab/users.go b/vendor/github.com/xanzy/go-gitlab/users.go index 36d8549ca..2b5a99239 100644 --- a/vendor/github.com/xanzy/go-gitlab/users.go +++ b/vendor/github.com/xanzy/go-gitlab/users.go @@ -112,6 +112,7 @@ type ListUsersOptions struct { 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"` + External *bool `url:"external,omitempty" json:"external,omitempty"` WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` } @@ -829,6 +830,7 @@ type UserActivity struct { // GitLap API docs: // https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only type GetUserActivitiesOptions struct { + ListOptions From *ISOTime `url:"from,omitempty" json:"from,omitempty"` } diff --git a/vendor/golang.org/x/time/rate/rate.go b/vendor/golang.org/x/time/rate/rate.go index a114b1aa5..a98fe7782 100644 --- a/vendor/golang.org/x/time/rate/rate.go +++ b/vendor/golang.org/x/time/rate/rate.go @@ -53,10 +53,9 @@ func Every(interval time.Duration) Limit { // // The methods AllowN, ReserveN, and WaitN consume n tokens. type Limiter struct { - limit Limit - burst int - mu sync.Mutex + limit Limit + burst int tokens float64 // last is the last time the limiter's tokens field was updated last time.Time @@ -76,6 +75,8 @@ func (lim *Limiter) Limit() Limit { // Burst values allow more events to happen at once. // A zero Burst allows no events, unless limit == Inf. func (lim *Limiter) Burst() int { + lim.mu.Lock() + defer lim.mu.Unlock() return lim.burst } @@ -229,7 +230,7 @@ func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) { lim.mu.Unlock() if n > burst && limit != Inf { - return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.burst) + return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, burst) } // Check if ctx is already cancelled select { @@ -359,6 +360,7 @@ func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duratio // advance calculates and returns an updated state for lim resulting from the passage of time. // lim is not changed. +// advance requires that lim.mu is held. func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time, newTokens float64) { last := lim.last if now.Before(last) { diff --git a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go index e25f4a409..54a6992a1 100644 --- a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go +++ b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go @@ -198,8 +198,12 @@ func TypeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Ty X: ast.NewIdent(pkgName), Sel: ast.NewIdent(t.Obj().Name()), } + case *types.Struct: + return ast.NewIdent(t.String()) + case *types.Interface: + return ast.NewIdent(t.String()) default: - return nil // TODO: anonymous structs, but who does that + return nil } } diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go index 0cb09e26a..62d9fe86a 100644 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/vendor/golang.org/x/tools/internal/imports/fix.go @@ -693,8 +693,8 @@ func candidateImportName(pkg *pkg) string { return "" } -// GetAllCandidates gets all of the packages starting with prefix that can be -// imported by filename, sorted by import path. +// GetAllCandidates calls wrapped for each package whose name starts with +// searchPrefix, and can be imported from filename with the package name filePkg. func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { callback := &scanCallback{ rootFound: func(gopathwalk.Root) bool { @@ -728,6 +728,35 @@ func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix return getCandidatePkgs(ctx, callback, filename, filePkg, env) } +// GetImportPaths calls wrapped for each package whose import path starts with +// searchPrefix, and can be imported from filename with the package name filePkg. +func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { + callback := &scanCallback{ + rootFound: func(gopathwalk.Root) bool { + return true + }, + dirFound: func(pkg *pkg) bool { + if !canUse(filename, pkg.dir) { + return false + } + return strings.HasPrefix(pkg.importPathShort, searchPrefix) + }, + packageNameLoaded: func(pkg *pkg) bool { + wrapped(ImportFix{ + StmtInfo: ImportInfo{ + ImportPath: pkg.importPathShort, + Name: candidateImportName(pkg), + }, + IdentName: pkg.packageName, + FixType: AddImport, + Relevance: pkg.relevance, + }) + return false + }, + } + return getCandidatePkgs(ctx, callback, filename, filePkg, env) +} + // A PackageExport is a package and its exports. type PackageExport struct { Fix *ImportFix diff --git a/vendor/modules.txt b/vendor/modules.txt index 69423a697..b3404f2fb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -420,7 +420,7 @@ github.com/gorilla/securecookie github.com/gorilla/sessions # github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/go-cleanhttp -# github.com/hashicorp/go-retryablehttp v0.6.6 +# github.com/hashicorp/go-retryablehttp v0.6.7 ## explicit github.com/hashicorp/go-retryablehttp # github.com/hashicorp/go-version v0.0.0-00010101000000-000000000000 => github.com/6543/go-version v1.2.3 @@ -728,7 +728,7 @@ 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.31.0 +# github.com/xanzy/go-gitlab v0.37.0 ## explicit github.com/xanzy/go-gitlab # github.com/xanzy/ssh-agent v0.2.1 @@ -846,10 +846,10 @@ golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm golang.org/x/text/width -# golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 +# golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e ## explicit golang.org/x/time/rate -# golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d +# golang.org/x/tools v0.0.0-20200825202427-b303f430e36d ## explicit golang.org/x/tools/cover golang.org/x/tools/go/analysis