mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-01-23 14:02:02 -05:00
Updates google/go-github to the latest revision (#12604)
* Updates to the latest go-github * `github_repository_collaborator` uses invitations API
This commit is contained in:
committed by
Paul Stack
parent
abe2f9ead1
commit
85f759f296
437
vendor/github.com/google/go-github/github/github.go
generated
vendored
437
vendor/github.com/google/go-github/github/github.go
generated
vendored
@@ -3,10 +3,13 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen-accessors.go
|
||||
|
||||
package github
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -24,12 +27,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// StatusUnprocessableEntity is the status code returned when sending a request with invalid fields.
|
||||
StatusUnprocessableEntity = 422
|
||||
)
|
||||
|
||||
const (
|
||||
libraryVersion = "0.1"
|
||||
libraryVersion = "4"
|
||||
defaultBaseURL = "https://api.github.com/"
|
||||
uploadBaseURL = "https://uploads.github.com/"
|
||||
userAgent = "go-github/" + libraryVersion
|
||||
@@ -39,8 +37,12 @@ const (
|
||||
headerRateReset = "X-RateLimit-Reset"
|
||||
headerOTP = "X-GitHub-OTP"
|
||||
|
||||
mediaTypeV3 = "application/vnd.github.v3+json"
|
||||
defaultMediaType = "application/octet-stream"
|
||||
mediaTypeV3 = "application/vnd.github.v3+json"
|
||||
defaultMediaType = "application/octet-stream"
|
||||
mediaTypeV3SHA = "application/vnd.github.v3.sha"
|
||||
mediaTypeV3Diff = "application/vnd.github.v3.diff"
|
||||
mediaTypeV3Patch = "application/vnd.github.v3.patch"
|
||||
mediaTypeOrgPermissionRepo = "application/vnd.github.v3.repository+json"
|
||||
|
||||
// Media Type values to access preview APIs
|
||||
|
||||
@@ -50,24 +52,60 @@ const (
|
||||
// https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/
|
||||
mediaTypeStarringPreview = "application/vnd.github.v3.star+json"
|
||||
|
||||
// https://developer.github.com/changes/2015-06-24-api-enhancements-for-working-with-organization-permissions/
|
||||
mediaTypeOrgPermissionPreview = "application/vnd.github.ironman-preview+json"
|
||||
mediaTypeOrgPermissionRepoPreview = "application/vnd.github.ironman-preview.repository+json"
|
||||
|
||||
// https://developer.github.com/changes/2015-11-11-protected-branches-api/
|
||||
mediaTypeProtectedBranchesPreview = "application/vnd.github.loki-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-02-11-issue-locking-api/
|
||||
mediaTypeIssueLockingPreview = "application/vnd.github.the-key-preview+json"
|
||||
// https://help.github.com/enterprise/2.4/admin/guides/migrations/exporting-the-github-com-organization-s-repositories/
|
||||
mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/
|
||||
mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-02-19-source-import-preview-api/
|
||||
mediaTypeImportPreview = "application/vnd.github.barred-rock-preview"
|
||||
|
||||
// https://developer.github.com/changes/2016-05-12-reactions-api-preview/
|
||||
mediaTypeReactionsPreview = "application/vnd.github.squirrel-girl-preview"
|
||||
|
||||
// https://developer.github.com/changes/2016-04-01-squash-api-preview/
|
||||
// https://developer.github.com/changes/2016-09-26-pull-request-merge-api-update/
|
||||
mediaTypeSquashPreview = "application/vnd.github.polaris-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/
|
||||
mediaTypeGitSigningPreview = "application/vnd.github.cryptographer-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-05-23-timeline-preview-api/
|
||||
mediaTypeTimelinePreview = "application/vnd.github.mockingbird-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-06-14-repository-invitations/
|
||||
mediaTypeRepositoryInvitationsPreview = "application/vnd.github.swamp-thing-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-07-06-github-pages-preiew-api/
|
||||
mediaTypePagesPreview = "application/vnd.github.mister-fantastic-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-09-14-projects-api/
|
||||
mediaTypeProjectsPreview = "application/vnd.github.inertia-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-09-14-Integrations-Early-Access/
|
||||
mediaTypeIntegrationPreview = "application/vnd.github.machine-man-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-11-28-preview-org-membership/
|
||||
mediaTypeOrgMembershipPreview = "application/vnd.github.korra-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2017-01-05-commit-search-api/
|
||||
mediaTypeCommitSearchPreview = "application/vnd.github.cloak-preview+json"
|
||||
|
||||
// https://developer.github.com/changes/2016-12-14-reviews-api/
|
||||
mediaTypePullRequestReviewsPreview = "application/vnd.github.black-cat-preview+json"
|
||||
)
|
||||
|
||||
// A Client manages communication with the GitHub API.
|
||||
type Client struct {
|
||||
// HTTP client used to communicate with the API.
|
||||
client *http.Client
|
||||
clientMu sync.Mutex // clientMu protects the client during calls that modify the CheckRedirect func.
|
||||
client *http.Client // HTTP client used to communicate with the API.
|
||||
|
||||
// Base URL for API requests. Defaults to the public GitHub API, but can be
|
||||
// set to a domain endpoint to use with GitHub Enterprise. BaseURL should
|
||||
// Base URL for API requests. Defaults to the public GitHub API, but can be
|
||||
// set to a domain endpoint to use with GitHub Enterprise. BaseURL should
|
||||
// always be specified with a trailing slash.
|
||||
BaseURL *url.URL
|
||||
|
||||
@@ -77,21 +115,33 @@ type Client struct {
|
||||
// User agent used when communicating with the GitHub API.
|
||||
UserAgent string
|
||||
|
||||
rateMu sync.Mutex
|
||||
rate Rate // Rate limit for the client as determined by the most recent API call.
|
||||
rateMu sync.Mutex
|
||||
rateLimits [categories]Rate // Rate limits for the client as determined by the most recent API calls.
|
||||
|
||||
common service // Reuse a single struct instead of allocating one for each service on the heap.
|
||||
|
||||
// Services used for talking to different parts of the GitHub API.
|
||||
Activity *ActivityService
|
||||
Gists *GistsService
|
||||
Git *GitService
|
||||
Gitignores *GitignoresService
|
||||
Issues *IssuesService
|
||||
Organizations *OrganizationsService
|
||||
PullRequests *PullRequestsService
|
||||
Repositories *RepositoriesService
|
||||
Search *SearchService
|
||||
Users *UsersService
|
||||
Licenses *LicensesService
|
||||
Activity *ActivityService
|
||||
Admin *AdminService
|
||||
Authorizations *AuthorizationsService
|
||||
Gists *GistsService
|
||||
Git *GitService
|
||||
Gitignores *GitignoresService
|
||||
Integrations *IntegrationsService
|
||||
Issues *IssuesService
|
||||
Organizations *OrganizationsService
|
||||
Projects *ProjectsService
|
||||
PullRequests *PullRequestsService
|
||||
Repositories *RepositoriesService
|
||||
Search *SearchService
|
||||
Users *UsersService
|
||||
Licenses *LicensesService
|
||||
Migrations *MigrationService
|
||||
Reactions *ReactionsService
|
||||
}
|
||||
|
||||
type service struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// ListOptions specifies the optional parameters to various List methods that
|
||||
@@ -109,7 +159,23 @@ type UploadOptions struct {
|
||||
Name string `url:"name,omitempty"`
|
||||
}
|
||||
|
||||
// addOptions adds the parameters in opt as URL query parameters to s. opt
|
||||
// RawType represents type of raw format of a request instead of JSON.
|
||||
type RawType uint8
|
||||
|
||||
const (
|
||||
// Diff format.
|
||||
Diff RawType = 1 + iota
|
||||
// Patch format.
|
||||
Patch
|
||||
)
|
||||
|
||||
// RawOptions specifies parameters when user wants to get raw format of
|
||||
// a response instead of JSON.
|
||||
type RawOptions struct {
|
||||
Type RawType
|
||||
}
|
||||
|
||||
// addOptions adds the parameters in opt as URL query parameters to s. opt
|
||||
// must be a struct whose fields may contain "url" tags.
|
||||
func addOptions(s string, opt interface{}) (string, error) {
|
||||
v := reflect.ValueOf(opt)
|
||||
@@ -131,8 +197,8 @@ func addOptions(s string, opt interface{}) (string, error) {
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// NewClient returns a new GitHub API client. If a nil httpClient is
|
||||
// provided, http.DefaultClient will be used. To use API methods which require
|
||||
// NewClient returns a new GitHub API client. If a nil httpClient is
|
||||
// provided, http.DefaultClient will be used. To use API methods which require
|
||||
// authentication, provide an http.Client that will perform the authentication
|
||||
// for you (such as that provided by the golang.org/x/oauth2 library).
|
||||
func NewClient(httpClient *http.Client) *Client {
|
||||
@@ -143,23 +209,30 @@ func NewClient(httpClient *http.Client) *Client {
|
||||
uploadURL, _ := url.Parse(uploadBaseURL)
|
||||
|
||||
c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent, UploadURL: uploadURL}
|
||||
c.Activity = &ActivityService{client: c}
|
||||
c.Gists = &GistsService{client: c}
|
||||
c.Git = &GitService{client: c}
|
||||
c.Gitignores = &GitignoresService{client: c}
|
||||
c.Issues = &IssuesService{client: c}
|
||||
c.Organizations = &OrganizationsService{client: c}
|
||||
c.PullRequests = &PullRequestsService{client: c}
|
||||
c.Repositories = &RepositoriesService{client: c}
|
||||
c.Search = &SearchService{client: c}
|
||||
c.Users = &UsersService{client: c}
|
||||
c.Licenses = &LicensesService{client: c}
|
||||
c.common.client = c
|
||||
c.Activity = (*ActivityService)(&c.common)
|
||||
c.Admin = (*AdminService)(&c.common)
|
||||
c.Authorizations = (*AuthorizationsService)(&c.common)
|
||||
c.Gists = (*GistsService)(&c.common)
|
||||
c.Git = (*GitService)(&c.common)
|
||||
c.Gitignores = (*GitignoresService)(&c.common)
|
||||
c.Integrations = (*IntegrationsService)(&c.common)
|
||||
c.Issues = (*IssuesService)(&c.common)
|
||||
c.Licenses = (*LicensesService)(&c.common)
|
||||
c.Migrations = (*MigrationService)(&c.common)
|
||||
c.Organizations = (*OrganizationsService)(&c.common)
|
||||
c.Projects = (*ProjectsService)(&c.common)
|
||||
c.PullRequests = (*PullRequestsService)(&c.common)
|
||||
c.Reactions = (*ReactionsService)(&c.common)
|
||||
c.Repositories = (*RepositoriesService)(&c.common)
|
||||
c.Search = (*SearchService)(&c.common)
|
||||
c.Users = (*UsersService)(&c.common)
|
||||
return c
|
||||
}
|
||||
|
||||
// NewRequest creates an API request. A relative URL can be provided in urlStr,
|
||||
// in which case it is resolved relative to the BaseURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash. If
|
||||
// Relative URLs should always be specified without a preceding slash. If
|
||||
// specified, the value pointed to by body is JSON encoded and included as the
|
||||
// request body.
|
||||
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
|
||||
@@ -184,9 +257,12 @@ func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Requ
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("Accept", mediaTypeV3)
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
req.Header.Set("Accept", mediaTypeV3)
|
||||
if c.UserAgent != "" {
|
||||
req.Header.Add("User-Agent", c.UserAgent)
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
@@ -207,23 +283,23 @@ func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, m
|
||||
}
|
||||
req.ContentLength = size
|
||||
|
||||
if len(mediaType) == 0 {
|
||||
if mediaType == "" {
|
||||
mediaType = defaultMediaType
|
||||
}
|
||||
req.Header.Add("Content-Type", mediaType)
|
||||
req.Header.Add("Accept", mediaTypeV3)
|
||||
req.Header.Add("User-Agent", c.UserAgent)
|
||||
req.Header.Set("Content-Type", mediaType)
|
||||
req.Header.Set("Accept", mediaTypeV3)
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Response is a GitHub API response. This wraps the standard http.Response
|
||||
// Response is a GitHub API response. This wraps the standard http.Response
|
||||
// returned from GitHub and provides convenient access to things like
|
||||
// pagination links.
|
||||
type Response struct {
|
||||
*http.Response
|
||||
|
||||
// These fields provide the page values for paginating through a set of
|
||||
// results. Any or all of these may be set to the zero value for
|
||||
// results. Any or all of these may be set to the zero value for
|
||||
// responses that are not part of a paginated set, or for which there
|
||||
// are no additional pages.
|
||||
|
||||
@@ -304,34 +380,56 @@ func parseRate(r *http.Response) Rate {
|
||||
return rate
|
||||
}
|
||||
|
||||
// Rate specifies the current rate limit for the client as determined by the
|
||||
// most recent API call. If the client is used in a multi-user application,
|
||||
// this rate may not always be up-to-date. Call RateLimits() to check the
|
||||
// current rate.
|
||||
func (c *Client) Rate() Rate {
|
||||
c.rateMu.Lock()
|
||||
rate := c.rate
|
||||
c.rateMu.Unlock()
|
||||
return rate
|
||||
}
|
||||
|
||||
// Do sends an API request and returns the API response. The API response is
|
||||
// Do sends an API request and returns the API response. The API response is
|
||||
// JSON decoded and stored in the value pointed to by v, or returned as an
|
||||
// error if an API error has occurred. If v implements the io.Writer
|
||||
// error if an API error has occurred. If v implements the io.Writer
|
||||
// interface, the raw response body will be written to v, without attempting to
|
||||
// first decode it.
|
||||
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
// first decode it. If rate limit is exceeded and reset time is in the future,
|
||||
// Do returns *RateLimitError immediately without making a network API call.
|
||||
//
|
||||
// The provided ctx must be non-nil. If it is canceled or times out,
|
||||
// ctx.Err() will be returned.
|
||||
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
rateLimitCategory := category(req.URL.Path)
|
||||
|
||||
// If we've hit rate limit, don't make further requests before Reset time.
|
||||
if err := c.checkRateLimitBeforeDo(req, rateLimitCategory); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
// If we got an error, and the context has been canceled,
|
||||
// the context's error is probably more useful.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
// If the error type is *url.Error, sanitize its URL before returning.
|
||||
if e, ok := err.(*url.Error); ok {
|
||||
if url, err := url.Parse(e.URL); err == nil {
|
||||
e.URL = sanitizeURL(url).String()
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Drain up to 512 bytes and close the body to let the Transport reuse the connection
|
||||
io.CopyN(ioutil.Discard, resp.Body, 512)
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
response := newResponse(resp)
|
||||
|
||||
c.rateMu.Lock()
|
||||
c.rate = response.Rate
|
||||
c.rateLimits[rateLimitCategory] = response.Rate
|
||||
c.rateMu.Unlock()
|
||||
|
||||
err = CheckResponse(resp)
|
||||
@@ -351,18 +449,57 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
// checkRateLimitBeforeDo does not make any network calls, but uses existing knowledge from
|
||||
// current client state in order to quickly check if *RateLimitError can be immediately returned
|
||||
// from Client.Do, and if so, returns it so that Client.Do can skip making a network API call unnecessarily.
|
||||
// Otherwise it returns nil, and Client.Do should proceed normally.
|
||||
func (c *Client) checkRateLimitBeforeDo(req *http.Request, rateLimitCategory rateLimitCategory) error {
|
||||
c.rateMu.Lock()
|
||||
rate := c.rateLimits[rateLimitCategory]
|
||||
c.rateMu.Unlock()
|
||||
if !rate.Reset.Time.IsZero() && rate.Remaining == 0 && time.Now().Before(rate.Reset.Time) {
|
||||
// Create a fake response.
|
||||
resp := &http.Response{
|
||||
Status: http.StatusText(http.StatusForbidden),
|
||||
StatusCode: http.StatusForbidden,
|
||||
Request: req,
|
||||
Header: make(http.Header),
|
||||
Body: ioutil.NopCloser(strings.NewReader("")),
|
||||
}
|
||||
return &RateLimitError{
|
||||
Rate: rate,
|
||||
Response: resp,
|
||||
Message: fmt.Sprintf("API rate limit of %v still exceeded until %v, not making remote request.", rate.Limit, rate.Reset.Time),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
An ErrorResponse reports one or more errors caused by an API request.
|
||||
|
||||
GitHub API docs: http://developer.github.com/v3/#client-errors
|
||||
GitHub API docs: https://developer.github.com/v3/#client-errors
|
||||
*/
|
||||
type ErrorResponse struct {
|
||||
Response *http.Response // HTTP response that caused this error
|
||||
Message string `json:"message"` // error message
|
||||
Errors []Error `json:"errors"` // more detail on individual errors
|
||||
// Block is only populated on certain types of errors such as code 451.
|
||||
// See https://developer.github.com/changes/2016-03-17-the-451-status-code-is-now-supported/
|
||||
// for more information.
|
||||
Block *struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
CreatedAt *Timestamp `json:"created_at,omitempty"`
|
||||
} `json:"block,omitempty"`
|
||||
// Most errors will also include a documentation_url field pointing
|
||||
// to some content that might help you resolve the error, see
|
||||
// https://developer.github.com/v3/#client-errors
|
||||
DocumentationURL string `json:"documentation_url,omitempty"`
|
||||
}
|
||||
|
||||
func (r *ErrorResponse) Error() string {
|
||||
@@ -372,7 +509,7 @@ func (r *ErrorResponse) Error() string {
|
||||
}
|
||||
|
||||
// TwoFactorAuthError occurs when using HTTP Basic Authentication for a user
|
||||
// that has two-factor authentication enabled. The request can be reattempted
|
||||
// that has two-factor authentication enabled. The request can be reattempted
|
||||
// by providing a one-time password in the request.
|
||||
type TwoFactorAuthError ErrorResponse
|
||||
|
||||
@@ -392,8 +529,38 @@ func (r *RateLimitError) Error() string {
|
||||
r.Response.StatusCode, r.Message, r.Rate.Reset.Time.Sub(time.Now()))
|
||||
}
|
||||
|
||||
// AcceptedError occurs when GitHub returns 202 Accepted response with an
|
||||
// empty body, which means a job was scheduled on the GitHub side to process
|
||||
// the information needed and cache it.
|
||||
// Technically, 202 Accepted is not a real error, it's just used to
|
||||
// indicate that results are not ready yet, but should be available soon.
|
||||
// The request can be repeated after some time.
|
||||
type AcceptedError struct{}
|
||||
|
||||
func (*AcceptedError) Error() string {
|
||||
return "job scheduled on GitHub side; try again later"
|
||||
}
|
||||
|
||||
// AbuseRateLimitError occurs when GitHub returns 403 Forbidden response with the
|
||||
// "documentation_url" field value equal to "https://developer.github.com/v3#abuse-rate-limits".
|
||||
type AbuseRateLimitError struct {
|
||||
Response *http.Response // HTTP response that caused this error
|
||||
Message string `json:"message"` // error message
|
||||
|
||||
// RetryAfter is provided with some abuse rate limit errors. If present,
|
||||
// it is the amount of time that the client should wait before retrying.
|
||||
// Otherwise, the client should try again later (after an unspecified amount of time).
|
||||
RetryAfter *time.Duration
|
||||
}
|
||||
|
||||
func (r *AbuseRateLimitError) Error() string {
|
||||
return fmt.Sprintf("%v %v: %d %v",
|
||||
r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
|
||||
r.Response.StatusCode, r.Message)
|
||||
}
|
||||
|
||||
// sanitizeURL redacts the client_secret parameter from the URL which may be
|
||||
// exposed to the user, specifically in the ErrorResponse error message.
|
||||
// exposed to the user.
|
||||
func sanitizeURL(uri *url.URL) *url.URL {
|
||||
if uri == nil {
|
||||
return nil
|
||||
@@ -418,13 +585,17 @@ These are the possible validation error codes:
|
||||
the formatting of a field is invalid
|
||||
already_exists:
|
||||
another resource has the same valid as this field
|
||||
custom:
|
||||
some resources return this (e.g. github.User.CreateKey()), additional
|
||||
information is set in the Message field of the Error
|
||||
|
||||
GitHub API docs: http://developer.github.com/v3/#client-errors
|
||||
GitHub API docs: https://developer.github.com/v3/#client-errors
|
||||
*/
|
||||
type Error struct {
|
||||
Resource string `json:"resource"` // resource on which the error occurred
|
||||
Field string `json:"field"` // field on which the error occurred
|
||||
Code string `json:"code"` // validation error code
|
||||
Message string `json:"message"` // Message describing the error. Errors with Code == "custom" will always have this set.
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
@@ -433,14 +604,19 @@ func (e *Error) Error() string {
|
||||
}
|
||||
|
||||
// CheckResponse checks the API response for errors, and returns them if
|
||||
// present. A response is considered an error if it has a status code outside
|
||||
// the 200 range. API error responses are expected to have either no response
|
||||
// body, or a JSON response body that maps to ErrorResponse. Any other
|
||||
// present. A response is considered an error if it has a status code outside
|
||||
// the 200 range or equal to 202 Accepted.
|
||||
// API error responses are expected to have either no response
|
||||
// body, or a JSON response body that maps to ErrorResponse. Any other
|
||||
// response body will be silently ignored.
|
||||
//
|
||||
// The error type will be *RateLimitError for rate limit exceeded errors,
|
||||
// *AcceptedError for 202 Accepted status codes,
|
||||
// and *TwoFactorAuthError for two-factor authentication errors.
|
||||
func CheckResponse(r *http.Response) error {
|
||||
if r.StatusCode == http.StatusAccepted {
|
||||
return &AcceptedError{}
|
||||
}
|
||||
if c := r.StatusCode; 200 <= c && c <= 299 {
|
||||
return nil
|
||||
}
|
||||
@@ -458,6 +634,20 @@ func CheckResponse(r *http.Response) error {
|
||||
Response: errorResponse.Response,
|
||||
Message: errorResponse.Message,
|
||||
}
|
||||
case r.StatusCode == http.StatusForbidden && errorResponse.DocumentationURL == "https://developer.github.com/v3#abuse-rate-limits":
|
||||
abuseRateLimitError := &AbuseRateLimitError{
|
||||
Response: errorResponse.Response,
|
||||
Message: errorResponse.Message,
|
||||
}
|
||||
if v := r.Header["Retry-After"]; len(v) > 0 {
|
||||
// According to GitHub support, the "Retry-After" header value will be
|
||||
// an integer which represents the number of seconds that one should
|
||||
// wait before resuming making requests.
|
||||
retryAfterSeconds, _ := strconv.ParseInt(v[0], 10, 64) // Error handling is noop.
|
||||
retryAfter := time.Duration(retryAfterSeconds) * time.Second
|
||||
abuseRateLimitError.RetryAfter = &retryAfter
|
||||
}
|
||||
return abuseRateLimitError
|
||||
default:
|
||||
return errorResponse
|
||||
}
|
||||
@@ -466,15 +656,15 @@ func CheckResponse(r *http.Response) error {
|
||||
// parseBoolResponse determines the boolean result from a GitHub API response.
|
||||
// Several GitHub API methods return boolean responses indicated by the HTTP
|
||||
// status code in the response (true indicated by a 204, false indicated by a
|
||||
// 404). This helper function will determine that result and hide the 404
|
||||
// error if present. Any other error will be returned through as-is.
|
||||
// 404). This helper function will determine that result and hide the 404
|
||||
// error if present. Any other error will be returned through as-is.
|
||||
func parseBoolResponse(err error) (bool, error) {
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound {
|
||||
// Simply false. In this one case, we do not pass the error through.
|
||||
// Simply false. In this one case, we do not pass the error through.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -500,14 +690,16 @@ func (r Rate) String() string {
|
||||
|
||||
// RateLimits represents the rate limits for the current client.
|
||||
type RateLimits struct {
|
||||
// The rate limit for non-search API requests. Unauthenticated
|
||||
// requests are limited to 60 per hour. Authenticated requests are
|
||||
// The rate limit for non-search API requests. Unauthenticated
|
||||
// requests are limited to 60 per hour. Authenticated requests are
|
||||
// limited to 5,000 per hour.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/#rate-limiting
|
||||
Core *Rate `json:"core"`
|
||||
|
||||
// The rate limit for search API requests. Unauthenticated requests
|
||||
// are limited to 5 requests per minutes. Authenticated requests are
|
||||
// limited to 20 per minute.
|
||||
// The rate limit for search API requests. Unauthenticated requests
|
||||
// are limited to 10 requests per minutes. Authenticated requests are
|
||||
// limited to 30 per minute.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#rate-limit
|
||||
Search *Rate `json:"search"`
|
||||
@@ -517,18 +709,27 @@ func (r RateLimits) String() string {
|
||||
return Stringify(r)
|
||||
}
|
||||
|
||||
// Deprecated: RateLimit is deprecated, use RateLimits instead.
|
||||
func (c *Client) RateLimit() (*Rate, *Response, error) {
|
||||
limits, resp, err := c.RateLimits()
|
||||
if limits == nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
type rateLimitCategory uint8
|
||||
|
||||
return limits.Core, resp, err
|
||||
const (
|
||||
coreCategory rateLimitCategory = iota
|
||||
searchCategory
|
||||
|
||||
categories // An array of this length will be able to contain all rate limit categories.
|
||||
)
|
||||
|
||||
// category returns the rate limit category of the endpoint, determined by Request.URL.Path.
|
||||
func category(path string) rateLimitCategory {
|
||||
switch {
|
||||
default:
|
||||
return coreCategory
|
||||
case strings.HasPrefix(path, "/search/"):
|
||||
return searchCategory
|
||||
}
|
||||
}
|
||||
|
||||
// RateLimits returns the rate limits for the current client.
|
||||
func (c *Client) RateLimits() (*RateLimits, *Response, error) {
|
||||
func (c *Client) RateLimits(ctx context.Context) (*RateLimits, *Response, error) {
|
||||
req, err := c.NewRequest("GET", "rate_limit", nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -537,12 +738,23 @@ func (c *Client) RateLimits() (*RateLimits, *Response, error) {
|
||||
response := new(struct {
|
||||
Resources *RateLimits `json:"resources"`
|
||||
})
|
||||
resp, err := c.Do(req, response)
|
||||
resp, err := c.Do(ctx, req, response)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return response.Resources, resp, err
|
||||
if response.Resources != nil {
|
||||
c.rateMu.Lock()
|
||||
if response.Resources.Core != nil {
|
||||
c.rateLimits[coreCategory] = *response.Resources.Core
|
||||
}
|
||||
if response.Resources.Search != nil {
|
||||
c.rateLimits[searchCategory] = *response.Resources.Search
|
||||
}
|
||||
c.rateMu.Unlock()
|
||||
}
|
||||
|
||||
return response.Resources, resp, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -558,7 +770,7 @@ that need to use a higher rate limit associated with your OAuth application.
|
||||
This will append the querystring params client_id=xxx&client_secret=yyy to all
|
||||
requests.
|
||||
|
||||
See http://developer.github.com/v3/#unauthenticated-rate-limited-requests for
|
||||
See https://developer.github.com/v3/#unauthenticated-rate-limited-requests for
|
||||
more information.
|
||||
*/
|
||||
type UnauthenticatedRateLimitedTransport struct {
|
||||
@@ -612,7 +824,7 @@ func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper {
|
||||
}
|
||||
|
||||
// BasicAuthTransport is an http.RoundTripper that authenticates all requests
|
||||
// using HTTP Basic Authentication with the provided username and password. It
|
||||
// using HTTP Basic Authentication with the provided username and password. It
|
||||
// additionally supports users who have two-factor authentication enabled on
|
||||
// their GitHub account.
|
||||
type BasicAuthTransport struct {
|
||||
@@ -630,7 +842,7 @@ func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error
|
||||
req = cloneRequest(req) // per RoundTrip contract
|
||||
req.SetBasicAuth(t.Username, t.Password)
|
||||
if t.OTP != "" {
|
||||
req.Header.Add(headerOTP, t.OTP)
|
||||
req.Header.Set(headerOTP, t.OTP)
|
||||
}
|
||||
return t.transport().RoundTrip(req)
|
||||
}
|
||||
@@ -664,25 +876,12 @@ func cloneRequest(r *http.Request) *http.Request {
|
||||
|
||||
// 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
|
||||
}
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
// 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
|
||||
}
|
||||
// Int is a helper routine that allocates a new int value
|
||||
// to store v and returns a pointer to it.
|
||||
func Int(v int) *int { return &v }
|
||||
|
||||
// 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
|
||||
}
|
||||
func String(v string) *string { return &v }
|
||||
|
||||
Reference in New Issue
Block a user