summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/xanzy/go-gitlab/gitlab.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/xanzy/go-gitlab/gitlab.go')
-rw-r--r--vendor/github.com/xanzy/go-gitlab/gitlab.go496
1 files changed, 73 insertions, 423 deletions
diff --git a/vendor/github.com/xanzy/go-gitlab/gitlab.go b/vendor/github.com/xanzy/go-gitlab/gitlab.go
index 4fdca56351..f8e4ee22d6 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
- }
-}