Help us shape the future of Go! Take the 2026 Go Developer Survey

ghclient

package
v0.63.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package ghclient is the desktop's own GitHub REST/GraphQL client: in-app authentication (OAuth device flow, PAT validation via User) and the typed API calls the connector needs (batched search, notifications, single-issue hydration). It owns no feed concepts — caching, polling cadence, and unread state live in cmd/desktop/internal/app/sources/github/feed — and no persistence: callers hold whatever token they have and pass it in via WithTokenCopy.

HTTP plumbing — the failure taxonomy, status mapping, conditional requests, request logging — comes from sources/sourcehttp.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BranchRef

type BranchRef struct {
	Owner  string
	Repo   string
	Branch string
}

BranchRef addresses one branch's pull request.

type CheckState

type CheckState string

CheckState condenses a pull request's check rollup. GitHub reports one rollup state per commit, so unlike the CLI's per-check array there is nothing to fold together here.

const (
	// CheckStateNone is a head commit with no checks configured.
	CheckStateNone    CheckState = ""
	CheckStatePassing CheckState = "passing"
	CheckStatePending CheckState = "pending"
	CheckStateFailing CheckState = "failing"
)

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a GitHub REST v3 / GraphQL client. The zero value is not usable; construct with NewClient.

func NewClient

func NewClient(opts ...Option) *Client

func (*Client) ItemStates

func (c *Client) ItemStates(ctx context.Context, refs []ItemRef) ([]ItemState, error)

ItemStates resolves the current lifecycle state of each ref via a batched, aliased GraphQL query, chunked at itemStateChunk refs per request. out is always len(refs), including alongside an error: a failing chunk stops the rest, and the states already resolved are still in out.

A ref whose repository is deleted or private resolves to a null alias plus a NOT_FOUND error, which is tolerated: that ref comes back Found:false while the rest of its chunk resolves normally, so one gone repo cannot strand the whole batch.

func (*Client) Notifications

func (c *Client) Notifications(ctx context.Context, limit int, prev sourcehttp.Validators) (NotificationsResult, error)

Notifications lists the user's notification inbox, including read threads, so the app can mirror the full inbox and keep triage state locally. Non-empty prev validators make the request conditional: authenticated 304 responses are free of rate-limit cost, so polling an unchanged inbox costs nothing.

func (*Client) PollDeviceFlow

func (c *Client) PollDeviceFlow(ctx context.Context, clientID string, auth DeviceAuth) (string, error)

PollDeviceFlow polls the token endpoint until the user authorizes the device, the code expires, or ctx is canceled. It blocks; run it in a goroutine and honor ctx for cancellation.

func (*Client) PullRequestsByBranch

func (c *Client) PullRequestsByBranch(ctx context.Context, refs []BranchRef) ([]PullRequest, error)

PullRequestsByBranch resolves each ref's pull request in a single GraphQL request, aliased so out[i] answers refs[i].

A repository the token cannot see resolves to a null alias rather than failing the batch (postGraphQL's tolerateNotFound), and reports Found: false like a branch with no pull request. A transport or auth failure is what arrives as an error, for the whole batch.

func (*Client) SearchIssuesBatch

func (c *Client) SearchIssuesBatch(ctx context.Context, reqs []SearchRequest) ([][]SearchItem, error)

SearchIssuesBatch runs requests as aliased search fields, newest-updated first. GitHub times out when statusCheckRollup is resolved for large search batches, so each request carries at most two aliases with pages of 25. Results map back by request index: out[i] answers reqs[i].

func (*Client) StartDeviceFlow

func (c *Client) StartDeviceFlow(ctx context.Context, clientID string, scopes []string) (DeviceAuth, error)

StartDeviceFlow requests a device + user code pair for the OAuth device flow. clientID is the public OAuth app client ID.

func (*Client) User

func (c *Client) User(ctx context.Context) (User, error)

User returns the authenticated user. It doubles as token validation: ErrUnauthorized means the token is missing, revoked, or expired.

func (*Client) WithTokenCopy

func (c *Client) WithTokenCopy(token string) *Client

WithTokenCopy returns a copy of the client using the given token. Every request-scoped call clones through here rather than mutating a shared client, which is what lets one Client template safely back every connected account: multi-account fetches never race each other's token.

type DeviceAuth

type DeviceAuth struct {
	DeviceCode      string `json:"device_code"`
	UserCode        string `json:"user_code"`
	VerificationURI string `json:"verification_uri"`
	ExpiresIn       int    `json:"expires_in"`
	Interval        int    `json:"interval"`
}

DeviceAuth is the pending device authorization the UI presents: the user opens VerificationURI and enters UserCode.

type ItemRef

type ItemRef struct {
	Owner  string
	Name   string
	Number int
}

ItemRef identifies one issue or pull request to look up in ItemStates.

type ItemState

type ItemState struct {
	Author    string
	Number    int
	State     string // "open", "closed", or "merged"
	UpdatedAt time.Time
	Found     bool // false when the alias resolved null: repo gone or private, or no such number
}

ItemState is the lifecycle state of one ItemRef as of the query.

type Label

type Label struct {
	Name string `json:"name"`
}

Label is an issue/PR label.

type Notification

type Notification struct {
	ID         string              `json:"id"`
	Unread     bool                `json:"unread"`
	Reason     string              `json:"reason"`
	UpdatedAt  time.Time           `json:"updated_at"`
	Subject    NotificationSubject `json:"subject"`
	Repository Repository          `json:"repository"`
}

Notification is one thread from the notifications inbox.

type NotificationSubject

type NotificationSubject struct {
	Title string `json:"title"`
	URL   string `json:"url"`
	Type  string `json:"type"` // "Issue" | "PullRequest" | "Release" | ...
}

NotificationSubject describes what a notification thread is about.

func (NotificationSubject) Number

func (s NotificationSubject) Number() int

Number parses the issue/PR number from the subject API URL. Returns 0 for subjects without one (releases, discussions).

type NotificationsResult

type NotificationsResult struct {
	Items        []Notification
	NotModified  bool
	Validators   sourcehttp.Validators
	PollInterval int
}

NotificationsResult is one notifications poll. When NotModified is true the inbox has not changed and Items is nil — the caller keeps its cached copy. Validators are echoed back on the next request, and PollInterval is the server-mandated minimum seconds between polls (X-Poll-Interval, 0 when the header is absent).

type Option

type Option func(*options)

func WithAPIBase

func WithAPIBase(base string) Option

WithAPIBase overrides the REST API base URL (tests, cmd/desktop/devserver).

func WithAuthBase

func WithAuthBase(base string) Option

WithAuthBase overrides the OAuth base URL used by the device flow (tests).

func WithLogger

func WithLogger(logger zerolog.Logger) Option

WithLogger enables request logging at debug level.

type PullRequest

type PullRequest struct {
	Found          bool
	Number         int
	State          string // OPEN, CLOSED, MERGED
	IsDraft        bool
	URL            string
	Title          string
	ReviewDecision string // APPROVED, CHANGES_REQUESTED, REVIEW_REQUIRED, or empty
	Checks         CheckState
	// Additions and Deletions are the pull request's own line counts, which are
	// not the working tree's: the branch may have moved since it was opened.
	Additions int
	Deletions int
}

PullRequest is the branch's most recently updated pull request. Found is false when the branch has none; the caller must keep that distinct from a failed lookup, which arrives as an error instead.

type Repository

type Repository struct {
	FullName string `json:"full_name"`
}

Repository identifies the repository a notification belongs to.

type ReviewState

type ReviewState string

ReviewState condenses GitHub's draft and review-decision fields.

const (
	ReviewStateOpen             ReviewState = "open"
	ReviewStateDraft            ReviewState = "draft"
	ReviewStateApproved         ReviewState = "approved"
	ReviewStateChangesRequested ReviewState = "changes_requested"
	ReviewStateReviewRequired   ReviewState = "review_required"
)

type SearchItem

type SearchItem struct {
	Number        int
	Title         string
	Body          string
	State         string
	URL           string // html URL
	Repo          string // "owner/name" (repository.nameWithOwner)
	Author        string // author.login; "" for deleted (ghost) users
	Labels        []Label
	IsPullRequest bool // __typename == "PullRequest"
	Draft         bool // isDraft; always false for issues
	Review        ReviewState
	Checks        CheckState
	Additions     int
	Deletions     int
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

SearchItem is one issue or pull request from the batched GraphQL search.

type SearchRequest

type SearchRequest struct {
	Query string // GitHub search syntax; "sort:updated-desc" is appended by the client
	Limit int    // max items for this search (GraphQL `first`)
}

SearchRequest is one search in a batched GraphQL issue/PR search.

type User

type User struct {
	Login     string `json:"login"`
	Name      string `json:"name"`
	AvatarURL string `json:"avatar_url"`
}

User is the authenticated GitHub user.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL