diff --git a/README.md b/README.md index c7b9dcef090..397a7a74c79 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ repos, _, err := client.Repositories.List(context.WithValue(ctx, github.SleepUnt ``` You can use [gofri/go-github-ratelimit](https://github.com/gofri/go-github-ratelimit) to handle -secondary rate limit sleep-and-retry for you. +secondary rate limit sleep-and-retry for you, as well as primary rate limit abuse-prevention and callback triggering. Learn more about GitHub secondary rate limiting in ["About secondary rate limits"](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#about-secondary-rate-limits). @@ -347,6 +347,13 @@ for repo := range repos.All() { For complete usage of `enrichman/gh-iter`, see the full [package docs](https://github.com/enrichman/gh-iter). +#### Middleware #### + +You can use [gofri/go-github-pagination](https://github.com/gofri/go-github-pagination) to handle +pagination for you. It supports both sync and async modes, as well as customizations. +By default, the middleware automatically paginates through all pages, aggregates results, and returns them as an array. +See `example/ratelimit/main.go` for usage. + ### Webhooks ### `go-github` provides structs for almost all [GitHub webhook events][] as well as functions to validate them and unmarshal JSON payloads from `http.Request` structs. diff --git a/example/go.mod b/example/go.mod index 58560bac535..e65cfeff63f 100644 --- a/example/go.mod +++ b/example/go.mod @@ -5,7 +5,8 @@ go 1.23.0 require ( github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 - github.com/gofri/go-github-ratelimit v1.0.3 + github.com/gofri/go-github-pagination v1.0.0 + github.com/gofri/go-github-ratelimit/v2 v2.0.2 github.com/google/go-github/v69 v69.2.0 github.com/sigstore/sigstore-go v0.6.1 golang.org/x/crypto v0.32.0 diff --git a/example/go.sum b/example/go.sum index 1c2cbf5ba24..28c7b50ebfb 100644 --- a/example/go.sum +++ b/example/go.sum @@ -134,8 +134,10 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofri/go-github-ratelimit v1.0.3 h1:Ocs2jaYokZDzgvqaajX+g04dqFyVqL0JQzoO7d2wmlk= -github.com/gofri/go-github-ratelimit v1.0.3/go.mod h1:OnCi5gV+hAG/LMR7llGhU7yHt44se9sYgKPnafoL7RY= +github.com/gofri/go-github-pagination v1.0.0 h1:nnCi+1xT5ybqY/plctISgiQPWZOtfSciVQlbx/hM/Yw= +github.com/gofri/go-github-pagination v1.0.0/go.mod h1:Qij55Fb4fNPjam3SB+8cLnqp4pgR8RGMyIspYXcyHX0= +github.com/gofri/go-github-ratelimit/v2 v2.0.2 h1:gS8wAS1jTmlWGdTjAM7KIpsLjwY1S0S/gKK5hthfSXM= +github.com/gofri/go-github-ratelimit/v2 v2.0.2/go.mod h1:YBQt4gTbdcbMjJFT05YFEaECwH78P5b0IwrnbLiHGdE= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= diff --git a/example/ratelimit/main.go b/example/ratelimit/main.go index 32596bc3a96..70c7424c437 100644 --- a/example/ratelimit/main.go +++ b/example/ratelimit/main.go @@ -3,16 +3,20 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The ratelimit command demonstrates using the github_ratelimit.SecondaryRateLimitWaiter. +// The ratelimit command demonstrates using the github_ratelimit as well as github_pagination. // By using the waiter, the client automatically sleeps and retry requests // when it hits secondary rate limits. +// It also prevents the client from abusing the API in case of a primary rate limit. package main import ( "context" "fmt" - "github.com/gofri/go-github-ratelimit/github_ratelimit" + "github.com/gofri/go-github-pagination/githubpagination" + "github.com/gofri/go-github-ratelimit/v2/github_ratelimit" + "github.com/gofri/go-github-ratelimit/v2/github_ratelimit/github_primary_ratelimit" + "github.com/gofri/go-github-ratelimit/v2/github_ratelimit/github_secondary_ratelimit" "github.com/google/go-github/v69/github" ) @@ -21,22 +25,28 @@ func main() { fmt.Print("Enter GitHub username: ") fmt.Scanf("%s", &username) - rateLimiter, err := github_ratelimit.NewRateLimitWaiterClient(nil) - if err != nil { - fmt.Printf("Error: %v\n", err) - return - } + rateLimiter := github_ratelimit.New(nil, + github_primary_ratelimit.WithLimitDetectedCallback(func(ctx *github_primary_ratelimit.CallbackContext) { + fmt.Printf("Primary rate limit detected: category %s, reset time: %v\n", ctx.Category, ctx.ResetTime) + }), + github_secondary_ratelimit.WithLimitDetectedCallback(func(ctx *github_secondary_ratelimit.CallbackContext) { + fmt.Printf("Secondary rate limit detected: reset time: %v, total sleep time: %v\n", ctx.ResetTime, ctx.TotalSleepTime) + }), + ) - client := github.NewClient(rateLimiter) + paginator := githubpagination.NewClient(rateLimiter, + githubpagination.WithPerPage(100), // default to 100 results per page + ) + client := github.NewClient(paginator) // arbitrary usage of the client - organizations, _, err := client.Organizations.List(context.Background(), username, nil) + repos, _, err := client.Repositories.ListByUser(context.Background(), username, nil) if err != nil { fmt.Printf("Error: %v\n", err) return } - for i, organization := range organizations { - fmt.Printf("%v. %v\n", i+1, organization.GetLogin()) + for i, repo := range repos { + fmt.Printf("%v. %v\n", i+1, repo.GetName()) } }