Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions example/otel/go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module github.com/google/go-github/v82/example/otel
module github.com/google/go-github/v81/example/otel

go 1.24.0

require (
github.com/google/go-github/v82 v82.0.0
github.com/google/go-github/v82/otel v0.0.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0
github.com/google/go-github/v81 v81.0.0
github.com/google/go-github/v81/otel v0.0.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.27.0
go.opentelemetry.io/otel/sdk v1.27.0
)

Expand All @@ -19,6 +19,6 @@ require (
golang.org/x/sys v0.39.0 // indirect
)

replace github.com/google/go-github/v82 => ../../
replace github.com/google/go-github/v81 => ../../

replace github.com/google/go-github/v82/otel => ../../otel
replace github.com/google/go-github/v81/otel => ../../otel
4 changes: 2 additions & 2 deletions example/otel/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.27.0 h1:/0YaXu3755A/cFbtXp+21lkXgI0QE5avTWA2HjU9/WE=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.27.0/go.mod h1:m7SFxp0/7IxmJPLIY3JhOcU9CoFzDaCPL6xxQIxhA+o=
go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik=
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI=
Expand Down
5 changes: 2 additions & 3 deletions example/otel/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
"log"
"net/http"

"github.com/google/go-github/v82/github"
"github.com/google/go-github/v82/otel"
"github.com/google/go-github/v81/github"
"github.com/google/go-github/v81/otel"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/sdk/trace"
)
Expand Down Expand Up @@ -43,7 +43,6 @@ func main() {
),
}

// Create GitHub client
client := github.NewClient(httpClient)

// Make a request (Get Rate Limits is public and cheap)
Expand Down
Binary file added example/otel/otel
Binary file not shown.
19 changes: 8 additions & 11 deletions github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ const (
defaultUserAgent = "go-github" + "/" + Version
uploadBaseURL = "https://uploads.github.com/"

headerAPIVersion = "X-Github-Api-Version"
headerRateLimit = "X-Ratelimit-Limit"
headerRateRemaining = "X-Ratelimit-Remaining"
headerRateUsed = "X-Ratelimit-Used"
HeaderRateLimit = "X-Ratelimit-Limit"
HeaderRateRemaining = "X-Ratelimit-Remaining"
HeaderRateUsed = "X-Ratelimit-Used"
HeaderRateReset = "X-Ratelimit-Reset"
HeaderRateResource = "X-Ratelimit-Resource"
headerAPIVersion = "X-Github-Api-Version"
headerOTP = "X-Github-Otp"
headerRetryAfter = "Retry-After"

Expand Down Expand Up @@ -785,13 +785,13 @@ func (r *Response) populatePageValues() {
// parseRate parses the rate related headers.
func parseRate(r *http.Response) Rate {
var rate Rate
if limit := r.Header.Get(headerRateLimit); limit != "" {
if limit := r.Header.Get(HeaderRateLimit); limit != "" {
rate.Limit, _ = strconv.Atoi(limit)
}
if remaining := r.Header.Get(headerRateRemaining); remaining != "" {
if remaining := r.Header.Get(HeaderRateRemaining); remaining != "" {
rate.Remaining, _ = strconv.Atoi(remaining)
}
if used := r.Header.Get(headerRateUsed); used != "" {
if used := r.Header.Get(HeaderRateUsed); used != "" {
rate.Used, _ = strconv.Atoi(used)
}
if reset := r.Header.Get(HeaderRateReset); reset != "" {
Expand Down Expand Up @@ -1451,10 +1451,7 @@ func CheckResponse(r *http.Response) error {
switch {
case r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required"):
return (*TwoFactorAuthError)(errorResponse)
// Primary rate limit exceeded: GitHub returns 403 or 429 with X-RateLimit-Remaining: 0
// See: https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api
case (r.StatusCode == http.StatusForbidden || r.StatusCode == http.StatusTooManyRequests) &&
r.Header.Get(headerRateRemaining) == "0":
case r.StatusCode == http.StatusForbidden && r.Header.Get(HeaderRateRemaining) == "0":
return &RateLimitError{
Rate: parseRate(r),
Response: errorResponse.Response,
Expand Down
93 changes: 49 additions & 44 deletions github/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1230,9 +1230,9 @@
client, mux, _ := setup(t)

mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "59")
w.Header().Set(headerRateUsed, "1")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "59")
w.Header().Set(HeaderRateUsed, "1")
w.Header().Set(HeaderRateReset, "1372700873")
w.Header().Set(HeaderRateResource, "core")
})
Expand Down Expand Up @@ -1349,9 +1349,9 @@
client, mux, _ := setup(t)

mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "59")
w.Header().Set(headerRateUsed, "1")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "59")
w.Header().Set(HeaderRateUsed, "1")
w.Header().Set(HeaderRateReset, "1372700873")
w.Header().Set(HeaderRateResource, "core")
http.Error(w, "Bad Request", 400)
Expand Down Expand Up @@ -1390,9 +1390,9 @@
client, mux, _ := setup(t)

mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "0")
w.Header().Set(headerRateUsed, "60")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "0")
w.Header().Set(HeaderRateUsed, "60")
w.Header().Set(HeaderRateReset, "1372700873")
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1440,9 +1440,9 @@
reset := time.Now().UTC().Add(time.Minute).Round(time.Second) // Rate reset is a minute from now, with 1 second precision.

mux.HandleFunc("/first", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "0")
w.Header().Set(headerRateUsed, "60")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "0")
w.Header().Set(HeaderRateUsed, "60")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1508,9 +1508,9 @@
// By adding the X-From-Cache header we pretend this is served from a cache.
mux.HandleFunc("/first", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("X-From-Cache", "1")
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "0")
w.Header().Set(headerRateUsed, "60")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "0")
w.Header().Set(HeaderRateUsed, "60")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1556,9 +1556,9 @@
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
if firstRequest {
firstRequest = false
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "0")
w.Header().Set(headerRateUsed, "60")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "0")
w.Header().Set(HeaderRateUsed, "60")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand All @@ -1569,9 +1569,9 @@
}`)
return
}
w.Header().Set(headerRateLimit, "5000")
w.Header().Set(headerRateRemaining, "5000")
w.Header().Set(headerRateUsed, "0")
w.Header().Set(HeaderRateLimit, "5000")
w.Header().Set(HeaderRateRemaining, "5000")
w.Header().Set(HeaderRateUsed, "0")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Add(time.Hour).Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1600,9 +1600,9 @@
requestCount := 0
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
requestCount++
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "0")
w.Header().Set(headerRateUsed, "60")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "0")
w.Header().Set(HeaderRateUsed, "60")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1634,9 +1634,9 @@
requestCount := 0
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
requestCount++
w.Header().Set(headerRateLimit, "5000")
w.Header().Set(headerRateRemaining, "5000")
w.Header().Set(headerRateUsed, "0")
w.Header().Set(HeaderRateLimit, "5000")
w.Header().Set(HeaderRateRemaining, "5000")
w.Header().Set(HeaderRateUsed, "0")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Add(time.Hour).Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1667,9 +1667,9 @@
requestCount := 0
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
requestCount++
w.Header().Set(headerRateLimit, "60")
w.Header().Set(headerRateRemaining, "0")
w.Header().Set(headerRateUsed, "60")
w.Header().Set(HeaderRateLimit, "60")
w.Header().Set(HeaderRateRemaining, "0")
w.Header().Set(HeaderRateUsed, "60")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1702,9 +1702,9 @@
requestCount := 0
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
requestCount++
w.Header().Set(headerRateLimit, "5000")
w.Header().Set(headerRateRemaining, "5000")
w.Header().Set(headerRateUsed, "0")
w.Header().Set(HeaderRateLimit, "5000")
w.Header().Set(HeaderRateRemaining, "5000")
w.Header().Set(HeaderRateUsed, "0")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Add(time.Hour).Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1858,7 +1858,7 @@
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set(HeaderRateReset, strconv.Itoa(int(blockUntil)))
w.Header().Set(headerRateRemaining, "1") // set remaining to a value > 0 to distinct from a primary rate limit
w.Header().Set(HeaderRateRemaining, "1") // set remaining to a value > 0 to distinct from a primary rate limit
w.WriteHeader(http.StatusForbidden)
fmt.Fprintln(w, `{
"message": "You have triggered an abuse detection mechanism ...",
Expand Down Expand Up @@ -1917,7 +1917,7 @@
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set(HeaderRateReset, strconv.Itoa(int(blockUntil)))
w.Header().Set(headerRateRemaining, "1") // set remaining to a value > 0 to distinct from a primary rate limit
w.Header().Set(HeaderRateRemaining, "1") // set remaining to a value > 0 to distinct from a primary rate limit
w.WriteHeader(http.StatusForbidden)
fmt.Fprintln(w, `{
"message": "You have triggered an abuse detection mechanism ...",
Expand Down Expand Up @@ -1956,9 +1956,14 @@
requestCount := 0
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
requestCount++
w.Header().Set(headerRateLimit, "5000")
w.Header().Set(headerRateRemaining, "5000")
w.Header().Set(headerRateUsed, "0")
w.Header().Set(HeaderRateLimit, "5000")
w.Header().Set(HeaderRateRemaining, "5000")
w.Header().Set(HeaderRateUsed, "0")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Add(time.Hour).Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set(HeaderRateLimit, "5000")
w.Header().Set(HeaderRateRemaining, "5000")
w.Header().Set(HeaderRateUsed, "0")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Add(time.Hour).Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -1992,9 +1997,9 @@
requestCount := 0
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
requestCount++
w.Header().Set(headerRateLimit, "5000")
w.Header().Set(headerRateRemaining, "5000")
w.Header().Set(headerRateUsed, "0")
w.Header().Set(HeaderRateLimit, "5000")
w.Header().Set(HeaderRateRemaining, "5000")
w.Header().Set(HeaderRateUsed, "0")
w.Header().Set(HeaderRateReset, fmt.Sprint(reset.Add(time.Hour).Unix()))
w.Header().Set(HeaderRateResource, "core")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down Expand Up @@ -2135,9 +2140,9 @@
Body: io.NopCloser(strings.NewReader(`{"message":"m",
"documentation_url": "url"}`)),
}
res.Header.Set(headerRateLimit, "60")
res.Header.Set(headerRateRemaining, "0")
res.Header.Set(headerRateUsed, "1")
res.Header.Set(HeaderRateLimit, "60")
res.Header.Set(HeaderRateRemaining, "0")
res.Header.Set(HeaderRateUsed, "1")
res.Header.Set(HeaderRateReset, "243424")
res.Header.Set(HeaderRateResource, "core")

Expand Down Expand Up @@ -2195,9 +2200,9 @@
Body: io.NopCloser(strings.NewReader(`{"message":"m",
"documentation_url": "url"}`)),
}
res.Header.Set(headerRateLimit, "60")

Check failure on line 2203 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateLimit

Check failure on line 2203 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateLimit

Check failure on line 2203 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateLimit

Check failure on line 2203 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.x, ubuntu-latest)

undefined: headerRateLimit

Check failure on line 2203 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.x, windows-latest)

undefined: headerRateLimit

Check failure on line 2203 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.24.0, ubuntu-latest)

undefined: headerRateLimit
res.Header.Set(headerRateRemaining, "0")

Check failure on line 2204 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateRemaining

Check failure on line 2204 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateRemaining

Check failure on line 2204 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateRemaining

Check failure on line 2204 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.x, ubuntu-latest)

undefined: headerRateRemaining

Check failure on line 2204 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.x, windows-latest)

undefined: headerRateRemaining

Check failure on line 2204 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.24.0, ubuntu-latest)

undefined: headerRateRemaining
res.Header.Set(headerRateUsed, "60")

Check failure on line 2205 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateUsed (typecheck)

Check failure on line 2205 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateUsed (typecheck)

Check failure on line 2205 in github/github_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: headerRateUsed (typecheck)

Check failure on line 2205 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.x, ubuntu-latest)

undefined: headerRateUsed

Check failure on line 2205 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.x, windows-latest)

undefined: headerRateUsed

Check failure on line 2205 in github/github_test.go

View workflow job for this annotation

GitHub Actions / test (1.24.0, ubuntu-latest)

undefined: headerRateUsed
res.Header.Set(HeaderRateReset, "243424")
res.Header.Set(HeaderRateResource, "core")

Expand Down
6 changes: 3 additions & 3 deletions otel/go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module github.com/google/go-github/v82/otel
module github.com/google/go-github/v81/otel

go 1.24.0

require (
github.com/google/go-github/v82 v82.0.0
github.com/google/go-github/v81 v81.0.0
go.opentelemetry.io/otel v1.27.0
go.opentelemetry.io/otel/metric v1.27.0
go.opentelemetry.io/otel/sdk v1.27.0
Expand All @@ -17,4 +17,4 @@ require (
golang.org/x/sys v0.39.0 // indirect
)

replace github.com/google/go-github/v82 => ../
replace github.com/google/go-github/v81 => ../
6 changes: 3 additions & 3 deletions otel/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"net/http"
"strconv"

"github.com/google/go-github/v82/github"
"github.com/google/go-github/v81/github"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
Expand Down Expand Up @@ -80,12 +80,12 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
// Capture response attributes
span.SetAttributes(attribute.Int("http.status_code", resp.StatusCode))
// Capture GitHub Specifics
if limit := resp.Header.Get("X-Ratelimit-Limit"); limit != "" {
if limit := resp.Header.Get(github.HeaderRateLimit); limit != "" {
if v, err := strconv.Atoi(limit); err == nil {
span.SetAttributes(attribute.Int("github.rate_limit.limit", v))
}
}
if remaining := resp.Header.Get("X-Ratelimit-Remaining"); remaining != "" {
if remaining := resp.Header.Get(github.HeaderRateRemaining); remaining != "" {
if v, err := strconv.Atoi(remaining); err == nil {
span.SetAttributes(attribute.Int("github.rate_limit.remaining", v))
}
Expand Down
6 changes: 3 additions & 3 deletions otel/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"net/http/httptest"
"testing"

"github.com/google/go-github/v82/github"
"github.com/google/go-github/v81/github"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
Expand Down Expand Up @@ -57,8 +57,8 @@ func TestRoundTrip_Spans(t *testing.T) {

// Setup Headers
headers := http.Header{}
headers.Set("X-Ratelimit-Limit", "5000")
headers.Set("X-Ratelimit-Remaining", "4999")
headers.Set(github.HeaderRateLimit, "5000")
headers.Set(github.HeaderRateRemaining, "4999")
headers.Set(github.HeaderRateReset, "1372700873")
headers.Set("X-Github-Request-Id", "1234-5678")
headers.Set(github.HeaderRateResource, "core")
Expand Down
Loading