Documentation
¶
Overview ¶
Package gitprovider holds the small slice of REST-client plumbing that is genuinely identical across internal/githubapp, internal/gitlabapp, and internal/bitbucketapp: sending a built request and turning its response into either a decoded value or a uniform API error. Request construction (auth scheme, headers, pagination shape) stays in each provider's own package, since that is exactly where the three providers' real, non-coincidental differences live.
Index ¶
- Constants
- func Execute(client *http.Client, req *http.Request, prefix, api, label string, out any) error
- func ExecuteETag(client *http.Client, req *http.Request, prefix, api, label, etag string, ...) (newETag string, notModified bool, err error)
- func IsNotFound(err error) bool
- func IsRateLimited(err error) (retryAfter string, ok bool)
- func NewGuardedClient() *http.Client
- func ParseRetryAfter(v string, now time.Time) (time.Duration, bool)
- func WithRetry(ctx context.Context, p RetryPolicy, provider string, fn func() error) error
- type APIError
- type Comment
- type ListOptions
- type ListResult
- type RateLimitError
- type RetryPolicy
Constants ¶
const AllowPrivateEnv = "APP_GIT_ALLOW_PRIVATE_NETWORKS"
AllowPrivateEnv lets git provider clients reach internal addresses, for example GitHub Enterprise or Bitbucket Server on a private network.
const CommentPageSize = 100
CommentPageSize is the page size every provider's comment listing asks for.
const MaxCommentPages = 10
MaxCommentPages bounds how many pages a comment lookup walks, so a PR with a huge thread cannot turn one status update into unbounded requests.
const MaxErrorBodySnippet = 512
MaxErrorBodySnippet caps how much of a non-2xx response body an APIError retains, so a misbehaving upstream can't inflate a log line unboundedly.
Variables ¶
This section is empty.
Functions ¶
func Execute ¶
Execute sends req and, on a 2xx response, decodes its body into out (skipped when out is nil). prefix and api identify the caller for both wrapped errors and a returned *APIError's own message; label is the method/URL text those wrapped errors describe, since GitHub's own caller wraps a relative path while GitLab's and Bitbucket's wrap a full URL.
func ExecuteETag ¶
func ExecuteETag(client *http.Client, req *http.Request, prefix, api, label, etag string, out any) (newETag string, notModified bool, err error)
ExecuteETag is Execute with conditional-request support: a non-empty etag is sent as If-None-Match, a 304 reply returns notModified true with out untouched, and the response's own ETag is returned for the next call.
func IsNotFound ¶
IsNotFound reports whether err is a provider 404, meaning the resource (typically a comment an operator deleted) no longer exists.
func IsRateLimited ¶
IsRateLimited reports whether err is a provider API error caused by rate limiting, and the Retry-After value it carried, if any.
func NewGuardedClient ¶
NewGuardedClient returns an SSRF-guarded HTTP client with the shared git provider timeout.
func ParseRetryAfter ¶
ParseRetryAfter reads a Retry-After header: delta seconds or an HTTP date.
Types ¶
type APIError ¶
type APIError struct {
Prefix string
API string
StatusCode int
Body string
// RetryAfter is the response's Retry-After header, empty when absent.
RetryAfter string
// RateLimited is true for a 429, or a 403 the provider marks as rate
// limited (an exhausted X-RateLimit-Remaining or a "rate limit" body).
RateLimited bool
}
APIError is returned for any non-2xx response from a git provider's REST API. Prefix and API identify the caller (e.g. "gitlabapp", "gitlab") so Error() reproduces that client's own message shape.
type ListOptions ¶
type ListOptions struct {
// MaxItems stops paging once this many items are collected (0 = no cap).
MaxItems int
Retry RetryPolicy
}
ListOptions bounds a paginated repository listing.
func (ListOptions) Reached ¶
func (o ListOptions) Reached(n int) bool
Reached reports whether n collected items meets the cap.
type ListResult ¶
type ListResult struct {
// Truncated is true when the MaxItems cap stopped paging while the
// provider still had more.
Truncated bool
}
ListResult reports how a paginated listing ended.
type RateLimitError ¶
type RateLimitError struct {
Provider string
RetryAfter time.Duration
NextCheck time.Time
Err error
}
RateLimitError is returned once a bounded retry gave up on a rate limit. NextCheck is when the provider said (or the default backoff implies) a call may succeed again.
func AsRateLimit ¶
func AsRateLimit(err error) (*RateLimitError, bool)
AsRateLimit reports whether err is (or wraps) a RateLimitError.
func (*RateLimitError) Error ¶
func (e *RateLimitError) Error() string
func (*RateLimitError) Unwrap ¶
func (e *RateLimitError) Unwrap() error
type RetryPolicy ¶
type RetryPolicy struct {
Retries int
MaxWait time.Duration
DefaultBackoff time.Duration
Sleep func(ctx context.Context, d time.Duration) error
Now func() time.Time
}
RetryPolicy bounds how a rate-limited provider call is retried inside one request. A Retry-After longer than MaxWait is not slept on: the caller gets a RateLimitError carrying the next-check time instead.
func RetryPolicyFromEnv ¶
func RetryPolicyFromEnv() RetryPolicy
RetryPolicyFromEnv reads the retry bounds from APP_GIT_RATE_LIMIT_*.