diff --git a/README.md b/README.md index 9e4d271..25ae111 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,23 @@ if _, ok := err.(*github.RateLimitError); ok { Learn more about GitHub rate limiting at http://developer.github.com/v3/#rate-limiting. +### Accepted Status ### + +Some endpoints may return a 202 Accepted status code, meaning that the +information required is not yet ready and was scheduled to be gathered on +the GitHub side. Methods known to behave like this are documented specifying +this behavior. + +To detect this condition of error, you can check if its type is +`*github.AcceptedError`: + +```go +stats, _, err := client.Repositories.ListContributorsStats(org, repo) +if _, ok := err.(*github.AcceptedError); ok { + log.Println("scheduled on GitHub side") +} +``` + ### Conditional Requests ### The GitHub API has good support for conditional requests which will help diff --git a/github/doc.go b/github/doc.go index 2b61068..659dd82 100644 --- a/github/doc.go +++ b/github/doc.go @@ -86,6 +86,21 @@ To detect an API rate limit error, you can check if its type is *github.RateLimi Learn more about GitHub rate limiting at http://developer.github.com/v3/#rate-limiting. +Accepted Status + +Some endpoints may return a 202 Accepted status code, meaning that the +information required is not yet ready and was scheduled to be gathered on +the GitHub side. Methods known to behave like this are documented specifying +this behavior. + +To detect this condition of error, you can check if its type is +*github.AcceptedError: + + stats, _, err := client.Repositories.ListContributorsStats(org, repo) + if _, ok := err.(*github.AcceptedError); ok { + log.Println("scheduled on GitHub side") + } + Conditional Requests The GitHub API has good support for conditional requests which will help diff --git a/github/github.go b/github/github.go index d96fa85..d4f5069 100644 --- a/github/github.go +++ b/github/github.go @@ -501,6 +501,18 @@ 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 { @@ -564,14 +576,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 +// 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 } diff --git a/github/repos_forks.go b/github/repos_forks.go index 7ef4cb3..c88f3d3 100644 --- a/github/repos_forks.go +++ b/github/repos_forks.go @@ -50,6 +50,12 @@ type RepositoryCreateForkOptions struct { // CreateFork creates a fork of the specified repository. // +// This method might return an *AcceptedError and a status code of +// 202. This is because this is the status that GitHub returns to signify that +// it is now computing creating the fork in a background task. +// A follow up request, after a delay of a second or so, should result +// in a successful request. +// // GitHub API docs: https://developer.github.com/v3/repos/forks/#create-a-fork func (s *RepositoriesService) CreateFork(owner, repo string, opt *RepositoryCreateForkOptions) (*Repository, *Response, error) { u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) diff --git a/github/repos_stats.go b/github/repos_stats.go index e4f75a5..8657bd7 100644 --- a/github/repos_stats.go +++ b/github/repos_stats.go @@ -39,8 +39,8 @@ func (w WeeklyStats) String() string { // deletions and commit counts. // // If this is the first time these statistics are requested for the given -// repository, this method will return a non-nil error and a status code of -// 202. This is because this is the status that github returns to signify that +// repository, this method will return an *AcceptedError and a status code of +// 202. This is because this is the status that GitHub returns to signify that // it is now computing the requested statistics. A follow up request, after a // delay of a second or so, should result in a successful request. // @@ -78,8 +78,8 @@ func (w WeeklyCommitActivity) String() string { // starting on Sunday. // // If this is the first time these statistics are requested for the given -// repository, this method will return a non-nil error and a status code of -// 202. This is because this is the status that github returns to signify that +// repository, this method will return an *AcceptedError and a status code of +// 202. This is because this is the status that GitHub returns to signify that // it is now computing the requested statistics. A follow up request, after a // delay of a second or so, should result in a successful request. // @@ -104,6 +104,12 @@ func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]*WeeklyC // deletions pushed to a repository. Returned WeeklyStats will contain // additions and deletions, but not total commits. // +// If this is the first time these statistics are requested for the given +// repository, this method will return an *AcceptedError and a status code of +// 202. This is because this is the status that GitHub returns to signify that +// it is now computing the requested statistics. A follow up request, after a +// delay of a second or so, should result in a successful request. +// // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#code-frequency func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]*WeeklyStats, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/code_frequency", owner, repo) @@ -152,11 +158,10 @@ func (r RepositoryParticipation) String() string { // The array order is oldest week (index 0) to most recent week. // // If this is the first time these statistics are requested for the given -// repository, this method will return a non-nil error and a status code -// of 202. This is because this is the status that github returns to -// signify that it is now computing the requested statistics. A follow -// up request, after a delay of a second or so, should result in a -// successful request. +// repository, this method will return an *AcceptedError and a status code of +// 202. This is because this is the status that GitHub returns to signify that +// it is now computing the requested statistics. A follow up request, after a +// delay of a second or so, should result in a successful request. // // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#participation func (s *RepositoriesService) ListParticipation(owner, repo string) (*RepositoryParticipation, *Response, error) { @@ -185,6 +190,12 @@ type PunchCard struct { // ListPunchCard returns the number of commits per hour in each day. // +// If this is the first time these statistics are requested for the given +// repository, this method will return an *AcceptedError and a status code of +// 202. This is because this is the status that GitHub returns to signify that +// it is now computing the requested statistics. A follow up request, after a +// delay of a second or so, should result in a successful request. +// // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#punch-card func (s *RepositoriesService) ListPunchCard(owner, repo string) ([]*PunchCard, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/punch_card", owner, repo)