Documentation
¶
Overview ¶
Package gh holds GitHub client plumbing shared by the sync engine and the fake GitHub test server.
Index ¶
- Constants
- Variables
- func DecodeWebhookPayload(contentType string, body []byte) ([]byte, error)
- func IsSupportedReviewRequestTeam(team *github.Team) bool
- func IsSupportedReviewRequestUser(user *github.User) bool
- func SignBody(secret, body []byte) string
- func VerifySignature(secret, body []byte, header string) bool
- type ActorNode
- type AppHookDelivery
- type AppTokens
- type BigInt
- type CheckRun
- type CodeownersSource
- type DeliveriesClient
- type GraphQLClient
- type GraphQLClientOptions
- type GraphQLError
- type GraphQLErrors
- type GraphQLResponse
- type HTTPError
- type InstallationTokenOptions
- type InstallationTokens
- type IssueCommentNode
- type ListAppHookDeliveriesOptions
- type ListCheckRunsOptions
- type ListPullRequestFilesOptions
- type ListPullsOptions
- type ListRepositoriesOptions
- type ListStacksOptions
- type PageInfo
- type PullRequest
- type PullRequestBranch
- type PullRequestChangedFileNode
- type PullRequestFile
- type PullRequestFilesConnection
- type PullRequestNode
- type PullRequestReviewNode
- type RESTClient
- func (c *RESTClient) FindCodeowners(ctx context.Context, class budget.Class, owner string, repo string, ref string) (CodeownersSource, error)
- func (c *RESTClient) GetPull(ctx context.Context, class budget.Class, owner string, repo string, number int, ...) (*PullRequest, *RESTResponse, error)
- func (c *RESTClient) GetRepository(ctx context.Context, class budget.Class, owner string, repo string, ...) (*Repository, *RESTResponse, error)
- func (c *RESTClient) GetStack(ctx context.Context, class budget.Class, owner string, repo string, number int, ...) (*Stack, *RESTResponse, error)
- func (c *RESTClient) ListCheckRuns(ctx context.Context, class budget.Class, owner string, repo string, ...) ([]CheckRun, *RESTResponse, error)
- func (c *RESTClient) ListInstallationRepositories(ctx context.Context, class budget.Class, options ListRepositoriesOptions, ...) ([]Repository, *RESTResponse, error)
- func (c *RESTClient) ListPullRequestFiles(ctx context.Context, class budget.Class, owner string, repo string, number int, ...) ([]PullRequestFile, *RESTResponse, error)
- func (c *RESTClient) ListPulls(ctx context.Context, class budget.Class, owner string, repo string, ...) ([]PullRequest, *RESTResponse, error)
- func (c *RESTClient) ListRepositoryRules(ctx context.Context, class budget.Class, owner string, repo string, ...) ([]RepositoryRule, *RESTResponse, error)
- func (c *RESTClient) ListStacks(ctx context.Context, class budget.Class, owner string, repo string, ...) ([]Stack, *RESTResponse, error)
- func (c *RESTClient) PullRequestFileRenames(ctx context.Context, class budget.Class, owner string, repo string, number int) (map[string]string, bool, error)
- type RESTResponse
- type Repository
- type RepositoryNode
- type RepositoryRule
- type ReviewCommentNode
- type ReviewRequestNode
- type ReviewThreadNode
- type Stack
- type StackBase
- type StackPullRequest
- type StackRef
- type StaticToken
- type TokenProvider
Constants ¶
const ( CodeownersPresent = "present" CodeownersMissing = "missing" CodeownersOversized = "oversized" // so no source can be read without silently falling back to another ref. CodeownersUnavailable = "unavailable" )
const ( // WebhookJSONContentType identifies GitHub's direct JSON delivery mode. WebhookJSONContentType = "application/json" // WebhookFormContentType identifies GitHub's form-wrapped JSON mode. WebhookFormContentType = "application/x-www-form-urlencoded" )
const ( // MaxCodeownersBytes is GitHub's effective CODEOWNERS size boundary. // Files at or above this size are not loaded by GitHub. MaxCodeownersBytes = 3 << 20 )
const MaxPullRequestBatch = 25
MaxPullRequestBatch is GitHub's nodes-per-gang cap used by the coordinator.
const MaxPullRequestFiles = 3000
MaxPullRequestFiles is GitHub's documented changed-file listing cap. The mirror stops at this boundary and records explicit truncation when the connection reports more files or remains pageable.
Variables ¶
var ErrUnsupportedWebhookContentType = errors.New(
"unsupported webhook content type",
)
ErrUnsupportedWebhookContentType marks content types GitHub does not use.
Functions ¶
func DecodeWebhookPayload ¶
DecodeWebhookPayload validates a GitHub webhook body and returns its JSON payload. Form deliveries keep their encoded wire body in durable storage; callers use the decoded bytes only for classification.
func IsSupportedReviewRequestTeam ¶ added in v0.3.0
IsSupportedReviewRequestTeam reports whether a REST requested_team has the stable identities and slug required by the v1 review-request contract.
func IsSupportedReviewRequestUser ¶ added in v0.3.0
IsSupportedReviewRequestUser reports whether a REST requested_reviewer is a complete GitHub User identity covered by the v1 review-request contract. GitHub also uses this shape for Bots and other account types; those are not user requests and must not be mislabeled as one.
func VerifySignature ¶
VerifySignature reports whether header is a valid signature for body. Constant-time; unverifiable deliveries must be rejected before parsing (SYNC_ENGINE C-I2).
Types ¶
type ActorNode ¶ added in v0.3.0
type ActorNode struct {
Typename string `json:"__typename"`
ID string `json:"id"`
Login string `json:"login"`
}
ActorNode preserves every GraphQL Actor variant instead of projecting only users. Author is nil when GitHub retains the fact but no longer exposes the deleted actor.
type AppHookDelivery ¶
type AppHookDelivery struct {
ID int64 `json:"id"`
GUID string `json:"guid"`
DeliveredAt time.Time `json:"delivered_at"`
Redelivery bool `json:"redelivery"`
Status string `json:"status"`
StatusCode int `json:"status_code"`
Event string `json:"event"`
Action string `json:"action"`
InstallationID int64 `json:"installation_id"`
RepositoryID int64 `json:"repository_id"`
}
AppHookDelivery is the compact delivery-list representation used by C-R4. The list endpoint intentionally omits request payloads.
type AppTokens ¶
type AppTokens struct {
// contains filtered or unexported fields
}
AppTokens signs short-lived GitHub App JWTs for App-only endpoints such as the webhook deliveries API used by C-R4.
func NewAppTokens ¶
NewAppTokens constructs an App-JWT provider for App-only endpoints.
type BigInt ¶ added in v0.3.0
type BigInt int64
BigInt decodes GitHub's GraphQL BigInt scalar, which is serialized as a decimal string because it may exceed GraphQL's 32-bit Int range.
func (*BigInt) UnmarshalJSON ¶ added in v0.3.0
type CheckRun ¶
type CheckRun struct {
ID int64 `json:"id"`
NodeID string `json:"node_id"`
HeadSHA string `json:"head_sha"`
Name string `json:"name"`
Status string `json:"status"`
Conclusion string `json:"conclusion"`
DetailsURL string `json:"details_url"`
AppSlug string `json:"-"`
StartedAt *time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at"`
Raw json.RawMessage `json:"-"`
}
CheckRun is the cache-relevant check-run shape.
func (*CheckRun) UnmarshalJSON ¶
UnmarshalJSON flattens GitHub's nested App slug.
type CodeownersSource ¶ added in v0.3.0
CodeownersSource is the first source found in GitHub's precedence order.
type DeliveriesClient ¶
type DeliveriesClient struct {
// contains filtered or unexported fields
}
DeliveriesClient is separate from RESTClient because GitHub requires an App JWT for /app/hook/deliveries and rejects installation access tokens.
func NewDeliveriesClient ¶
func NewDeliveriesClient( baseURL string, gate budget.Doer, appTokens TokenProvider, ) (*DeliveriesClient, error)
NewDeliveriesClient constructs an App-JWT-authenticated deliveries client.
func (*DeliveriesClient) ListAppHookDeliveries ¶
func (c *DeliveriesClient) ListAppHookDeliveries( ctx context.Context, options ListAppHookDeliveriesOptions, etag string, ) ([]AppHookDelivery, *RESTResponse, error)
ListAppHookDeliveries fetches deliveries newest first.
func (*DeliveriesClient) RedeliverAppHookDelivery ¶
func (c *DeliveriesClient) RedeliverAppHookDelivery( ctx context.Context, deliveryID int64, ) error
RedeliverAppHookDelivery requests a new attempt for one delivery.
type GraphQLClient ¶
type GraphQLClient struct {
// contains filtered or unexported fields
}
GraphQLClient executes budget-gated installation GraphQL calls.
func NewGraphQLClient ¶
func NewGraphQLClient( baseURL string, gate budget.Doer, tokens TokenProvider, options ...GraphQLClientOptions, ) (*GraphQLClient, error)
NewGraphQLClient validates dependencies and constructs a GraphQL client.
func (*GraphQLClient) BatchPullRequests ¶
func (c *GraphQLClient) BatchPullRequests( ctx context.Context, class budget.Class, nodeIDs []string, ) ([]*PullRequestNode, *GraphQLResponse, error)
BatchPullRequests satisfies up to 25 due PR refreshes with one nodes() call (C-P4). The returned order matches the input node-ID order.
func (*GraphQLClient) Call ¶
func (c *GraphQLClient) Call( ctx context.Context, class budget.Class, query string, variables map[string]any, target any, ) (*GraphQLResponse, error)
Call executes a query that includes a top-level data.rateLimit block. extractGraphQLRate reads that block for Gate before Call decodes data.
type GraphQLClientOptions ¶
type GraphQLClientOptions struct {
MaxResponseBytes int64
}
GraphQLClientOptions bounds response buffering.
type GraphQLError ¶
type GraphQLError struct {
Type string `json:"type"`
Message string `json:"message"`
Path []any `json:"path"`
Extensions map[string]any `json:"extensions"`
}
GraphQLError is one GitHub GraphQL error entry.
type GraphQLErrors ¶
type GraphQLErrors []GraphQLError
GraphQLErrors implements error for a non-empty GraphQL error list.
func (GraphQLErrors) Error ¶
func (e GraphQLErrors) Error() string
Error reports the first GraphQL error message.
type GraphQLResponse ¶
type GraphQLResponse struct {
RateLimit budget.GraphQLRate
Errors []GraphQLError
}
GraphQLResponse carries authoritative point accounting and GraphQL errors.
type HTTPError ¶
HTTPError is a non-success response from GitHub. Response bodies are bounded before being retained.
type InstallationTokenOptions ¶
type InstallationTokenOptions struct {
BaseURL string
AppID int64
InstallationID int64
PrivateKey *rsa.PrivateKey
PrivateKeyPEM []byte
RefreshBefore time.Duration
Clock interface{ Now() time.Time }
}
InstallationTokenOptions configures App-to-installation token exchange.
type InstallationTokens ¶
type InstallationTokens struct {
// contains filtered or unexported fields
}
InstallationTokens exchanges an App JWT for installation access tokens, caches them until shortly before expiry, and collapses concurrent renewals. The hand-rolled exchange keeps the token endpoint inside Gate.Do; it uses ghinstallation's signer rather than its RoundTripper, whose internal refresh request would otherwise bypass C-B1.
func NewInstallationTokens ¶
func NewInstallationTokens( gate budget.Doer, options InstallationTokenOptions, ) (*InstallationTokens, error)
NewInstallationTokens validates App credentials and constructs a cached installation-token provider.
func (*InstallationTokens) Expiry ¶
func (m *InstallationTokens) Expiry() time.Time
Expiry returns the cached installation-token expiry, or zero before renewal.
type IssueCommentNode ¶ added in v0.3.0
type IssueCommentNode struct {
ID string `json:"id"`
FullDatabaseID *BigInt `json:"fullDatabaseId"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
Author *ActorNode `json:"author"`
}
IssueCommentNode is one ordinary pull-request issue comment. Body is intentionally not queried because participation is the public contract.
type ListAppHookDeliveriesOptions ¶
ListAppHookDeliveriesOptions controls newest-first delivery pagination.
type ListCheckRunsOptions ¶
ListCheckRunsOptions controls checks pagination.
type ListPullRequestFilesOptions ¶ added in v0.3.0
ListPullRequestFilesOptions controls changed-file REST pagination.
type ListPullsOptions ¶
ListPullsOptions controls pull-request filtering and pagination.
type ListRepositoriesOptions ¶
ListRepositoriesOptions controls installation repository pagination.
type ListStacksOptions ¶
ListStacksOptions controls stack filtering and pagination.
type PullRequest ¶
type PullRequest struct {
*github.PullRequest
Stack *StackRef `json:"stack,omitempty"`
ReviewDecision string `json:"review_decision,omitempty"`
}
PullRequest keeps google/go-github's typed pull request while preserving the preview-only stack extension that the library does not yet model.
func (*PullRequest) UnmarshalJSON ¶
func (p *PullRequest) UnmarshalJSON(data []byte) error
UnmarshalJSON preserves the private-preview stack extension.
type PullRequestBranch ¶
PullRequestBranch identifies one pull request branch.
type PullRequestChangedFileNode ¶ added in v0.3.0
type PullRequestChangedFileNode struct {
Path string `json:"path"`
PreviousPath string `json:"-"`
ChangeType string `json:"changeType"`
}
PullRequestChangedFileNode is one GraphQL changed-file fact. GitHub's GraphQL type does not expose the prior path for a rename; the fetch layer supplements renamed nodes from the bounded REST files endpoint.
type PullRequestFile ¶ added in v0.3.0
type PullRequestFile struct {
Path string `json:"filename"`
PreviousPath string `json:"previous_filename"`
Status string `json:"status"`
}
PullRequestFile is the REST rename supplement for a GraphQL changed file.
type PullRequestFilesConnection ¶ added in v0.3.0
type PullRequestFilesConnection struct {
Nodes []PullRequestChangedFileNode `json:"nodes"`
PageInfo PageInfo `json:"pageInfo"`
TotalCount int `json:"totalCount"`
Truncated bool `json:"-"`
}
PullRequestFilesConnection carries the authoritative page set and its completeness state. Truncated is derived locally from GitHub's 3,000-file cap, an inconsistent total, or an unfinished cursor.
type PullRequestNode ¶
type PullRequestNode struct {
ID string `json:"id"`
DatabaseID int64 `json:"databaseId"`
Number int `json:"number"`
Title string `json:"title"`
State string `json:"state"`
IsDraft bool `json:"isDraft"`
UpdatedAt time.Time `json:"updatedAt"`
ReviewDecision string `json:"reviewDecision"`
Mergeable string `json:"mergeable"`
HeadRefName string `json:"headRefName"`
HeadRefOID string `json:"headRefOid"`
BaseRefName string `json:"baseRefName"`
BaseRefOID string `json:"baseRefOid"`
ChangedFiles int `json:"changedFiles"`
Author struct {
Login string `json:"login"`
} `json:"author"`
Repository RepositoryNode `json:"repository"`
Files *PullRequestFilesConnection `json:"files"`
ReviewRequests struct {
Nodes []ReviewRequestNode `json:"nodes"`
PageInfo PageInfo `json:"pageInfo"`
} `json:"reviewRequests"`
Reviews struct {
Nodes []PullRequestReviewNode `json:"nodes"`
PageInfo PageInfo `json:"pageInfo"`
} `json:"reviews"`
Comments struct {
Nodes []IssueCommentNode `json:"nodes"`
PageInfo PageInfo `json:"pageInfo"`
} `json:"comments"`
ReviewThreads struct {
Nodes []ReviewThreadNode `json:"nodes"`
PageInfo PageInfo `json:"pageInfo"`
} `json:"reviewThreads"`
}
PullRequestNode is the authoritative GraphQL detail shape used by the M3 nodes() coordinator. Stack membership is intentionally absent from the query because the private-preview stack extension is REST-only; the resolve_stack_membership worker covers that authoritative dimension.
type PullRequestReviewNode ¶ added in v0.3.0
type PullRequestReviewNode struct {
ID string `json:"id"`
FullDatabaseID *BigInt `json:"fullDatabaseId"`
State string `json:"state"`
SubmittedAt *time.Time `json:"submittedAt"`
UpdatedAt time.Time `json:"updatedAt"`
Author *ActorNode `json:"author"`
Commit *struct {
OID string `json:"oid"`
} `json:"commit"`
}
PullRequestReviewNode is one identity-keyed review fact.
type RESTClient ¶
type RESTClient struct {
// contains filtered or unexported fields
}
RESTClient fetches installation-authenticated GitHub REST resources.
func NewRESTClient ¶
func NewRESTClient( baseURL string, gate budget.Doer, tokens TokenProvider, ) (*RESTClient, error)
NewRESTClient validates dependencies and constructs a REST client.
func (*RESTClient) FindCodeowners ¶ added in v0.3.0
func (c *RESTClient) FindCodeowners( ctx context.Context, class budget.Class, owner string, repo string, ref string, ) (CodeownersSource, error)
FindCodeowners reads the first source present at an exact Git ref using GitHub's .github, repository-root, then docs precedence. A missing source is a successful explicit state; an oversized first source is effective empty ownership and does not fall through to lower-precedence files.
func (*RESTClient) GetPull ¶
func (c *RESTClient) GetPull( ctx context.Context, class budget.Class, owner string, repo string, number int, etag string, ) (*PullRequest, *RESTResponse, error)
GetPull fetches one pull request. A conditional 304 returns (nil, response, nil); callers must inspect response.NotModified before dereferencing the pull request.
func (*RESTClient) GetRepository ¶
func (c *RESTClient) GetRepository( ctx context.Context, class budget.Class, owner string, repo string, etag string, ) (*Repository, *RESTResponse, error)
GetRepository fetches one repository. A conditional 304 returns (nil, response, nil); callers must inspect response.NotModified before dereferencing the repository.
func (*RESTClient) GetStack ¶
func (c *RESTClient) GetStack( ctx context.Context, class budget.Class, owner string, repo string, number int, etag string, ) (*Stack, *RESTResponse, error)
GetStack fetches one stack. A conditional 304 returns (nil, response, nil); callers must inspect response.NotModified before dereferencing the stack.
func (*RESTClient) ListCheckRuns ¶
func (c *RESTClient) ListCheckRuns( ctx context.Context, class budget.Class, owner string, repo string, headSHA string, options ListCheckRunsOptions, etag string, ) ([]CheckRun, *RESTResponse, error)
ListCheckRuns fetches one checks page for a head SHA.
func (*RESTClient) ListInstallationRepositories ¶
func (c *RESTClient) ListInstallationRepositories( ctx context.Context, class budget.Class, options ListRepositoriesOptions, etag string, ) ([]Repository, *RESTResponse, error)
ListInstallationRepositories fetches one installation repository page.
func (*RESTClient) ListPullRequestFiles ¶ added in v0.3.0
func (c *RESTClient) ListPullRequestFiles( ctx context.Context, class budget.Class, owner string, repo string, number int, options ListPullRequestFilesOptions, ) ([]PullRequestFile, *RESTResponse, error)
ListPullRequestFiles fetches one REST changed-file page. The GraphQL files connection remains authoritative; this endpoint supplies previous_filename, which the GraphQL PullRequestChangedFile type does not expose.
func (*RESTClient) ListPulls ¶
func (c *RESTClient) ListPulls( ctx context.Context, class budget.Class, owner string, repo string, options ListPullsOptions, etag string, ) ([]PullRequest, *RESTResponse, error)
ListPulls fetches one pull-request page.
func (*RESTClient) ListRepositoryRules ¶
func (c *RESTClient) ListRepositoryRules( ctx context.Context, class budget.Class, owner string, repo string, etag string, ) ([]RepositoryRule, *RESTResponse, error)
ListRepositoryRules fetches the complete ruleset page for one repository.
func (*RESTClient) ListStacks ¶
func (c *RESTClient) ListStacks( ctx context.Context, class budget.Class, owner string, repo string, options ListStacksOptions, etag string, ) ([]Stack, *RESTResponse, error)
ListStacks fetches one gh-stack preview page.
func (*RESTClient) PullRequestFileRenames ¶ added in v0.3.0
func (c *RESTClient) PullRequestFileRenames( ctx context.Context, class budget.Class, owner string, repo string, number int, ) (map[string]string, bool, error)
PullRequestFileRenames follows the REST listing to GitHub's documented 3,000-file cap and returns only rename source paths. Truncated is true if a cursor remains at the cap.
type RESTResponse ¶
type RESTResponse struct {
StatusCode int
ETag string
NotModified bool
NextPage int
NextCursor string
}
RESTResponse is typed 304/pagination metadata. NotModified is a successful conditional result, not an error (C-B4).
type Repository ¶
type Repository struct {
ID int64 `json:"id"`
NodeID string `json:"node_id"`
Owner string `json:"-"`
Name string `json:"name"`
FullName string `json:"full_name"`
DefaultBranch string `json:"default_branch"`
Archived bool `json:"archived"`
UpdatedAt time.Time `json:"updated_at"`
PushedAt time.Time `json:"pushed_at"`
}
Repository is the subset of repository truth needed by the mirror.
func (*Repository) UnmarshalJSON ¶
func (r *Repository) UnmarshalJSON(data []byte) error
UnmarshalJSON flattens GitHub's nested owner login.
type RepositoryNode ¶
type RepositoryNode struct {
ID string `json:"id"`
DatabaseID int64 `json:"databaseId"`
Name string `json:"name"`
NameWithOwner string `json:"nameWithOwner"`
IsArchived bool `json:"isArchived"`
UpdatedAt time.Time `json:"updatedAt"`
DefaultBranchRef *struct {
Name string `json:"name"`
Target struct {
OID string `json:"oid"`
} `json:"target"`
} `json:"defaultBranchRef"`
Owner struct {
Login string `json:"login"`
} `json:"owner"`
}
RepositoryNode is the cache-relevant repository GraphQL shape.
type RepositoryRule ¶
type RepositoryRule struct {
ID int64
UpdatedAt *time.Time
Raw json.RawMessage
}
RepositoryRule preserves the complete ruleset payload while exposing the immutable key and optional semantic timestamp used by the mirror CAS.
func (*RepositoryRule) UnmarshalJSON ¶
func (r *RepositoryRule) UnmarshalJSON(data []byte) error
UnmarshalJSON retains the complete raw rule while extracting CAS metadata.
type ReviewCommentNode ¶
type ReviewCommentNode struct {
ID string `json:"id"`
Body string `json:"body"`
UpdatedAt time.Time `json:"updatedAt"`
Author *struct {
Login string `json:"login"`
} `json:"author"`
}
ReviewCommentNode is one review-comment connection node.
type ReviewRequestNode ¶ added in v0.3.0
type ReviewRequestNode struct {
RequestedReviewer struct {
Typename string `json:"__typename"`
ID string `json:"id"`
DatabaseID int64 `json:"databaseId"`
Login string `json:"login"`
Slug string `json:"slug"`
} `json:"requestedReviewer"`
}
ReviewRequestNode is one current GitHub review request. RequestedReviewer is nullable and the live union also includes Bot, Mannequin, EnterpriseTeam, and potentially future members. The v1 projection consumes only complete User and Team variants; __typename lets the converter exclude the rest without misclassifying them.
type ReviewThreadNode ¶
type ReviewThreadNode struct {
ID string `json:"id"`
IsResolved bool `json:"isResolved"`
IsOutdated bool `json:"isOutdated"`
Path string `json:"path"`
Line *int `json:"line"`
Comments struct {
Nodes []ReviewCommentNode `json:"nodes"`
PageInfo PageInfo `json:"pageInfo"`
} `json:"comments"`
}
ReviewThreadNode is one review-thread connection node.
type Stack ¶
type Stack struct {
ID int64 `json:"id"`
Number int `json:"number"`
NodeID string `json:"node_id"`
URL string `json:"url"`
Base StackBase `json:"base"`
Open bool `json:"open"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
PullRequests []StackPullRequest `json:"pull_requests"` // bottom to top
}
Stack is the gh-stack private-preview REST resource.
type StackPullRequest ¶
type StackPullRequest struct {
Number int `json:"number"`
State string `json:"state"`
Draft bool `json:"draft"`
MergedAt *time.Time `json:"merged_at"`
UpdatedAt time.Time `json:"updated_at"`
Head PullRequestBranch `json:"head"`
}
StackPullRequest is one ordered layer in a stack.
type StackRef ¶
type StackRef struct {
ID int64 `json:"id"`
Number int `json:"number"`
Size int `json:"size"`
Position int `json:"position"`
Base StackBase `json:"base"`
}
StackRef is the private-preview extension carried by ordinary pull request responses.