discovery

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package discovery maintains a private GitHub inbox cache. It performs no git fetch, generation or write to GitHub.

Index

Constants

This section is empty.

Variables

View Source
var PushedDelays = []time.Duration{0, 5 * time.Second, 10 * time.Second, 15 * time.Second, 30 * time.Second}

PushedDelays are the waits between the polls after baum itself pushed a pull request's head (a fix). A poll right after the push finds the head before GitHub has queued its checks: no checks and a clean merge state, which reads as ready to merge. The checks usually appear within seconds, and neither the probe (check results do not move a pull request's update time) nor the settle poll (the background scheduler does not see a poll it did not make) would notice them before the usual backoff.

Functions

func AfterPush

func AfterPush(ctx context.Context, poll func(context.Context, github.Repository) (Snapshot, error), repository github.Repository, number int, head string, changed func(), delays []time.Duration)

AfterPush polls repository at PushedDelays (delays, in tests) until the pull request shows head with its checks reported, or is no longer open, and calls changed after each poll that succeeded. A repository without checks reports none for every poll, so the polls stop with the delays. poll is Service.PollNow, which still honors the shared rate budgets.

func DefaultDirectory

func DefaultDirectory() (string, error)

DefaultDirectory is the shared application database directory.

Types

type Observation

type Observation struct {
	Identity  string    `json:"-"`
	Number    int       `json:"number"`
	HeadSHA   string    `json:"head_sha"`
	Title     string    `json:"title"`
	State     string    `json:"state"`
	Draft     bool      `json:"draft"`
	FetchedAt time.Time `json:"fetched_at"`
	Checks    string    `json:"checks"`
}

Observation contains only safe current GitHub metadata, never description bodies, signed image URLs or session contents.

type PullRequest

type PullRequest struct {
	Repository string `json:"repository"`
	Number     int    `json:"number"`
	HeadSHA    string `json:"head_sha"`
	// HeadRef is the head branch's name, which links a local session on that
	// branch to the pull request. It is empty in a snapshot cached before it
	// was kept, until the next poll.
	HeadRef string `json:"head_ref"`
	// HeadRepository is the canonical host/repository owning the head branch.
	HeadRepository string `json:"head_repository,omitempty"`
	// BaseRef is the base branch's name; a pull request whose base is
	// another open pull request's head branch is stacked on it. Empty in a
	// snapshot cached before it was kept, until the next poll.
	BaseRef string `json:"base_ref"`
	// Additions, Deletions and ChangedFiles size the change as GitHub counts
	// it. They are zero in a snapshot cached before they were kept, until the
	// next poll.
	Additions    int    `json:"additions"`
	Deletions    int    `json:"deletions"`
	ChangedFiles int    `json:"changed_files"`
	Title        string `json:"title"`
	URL          string `json:"url"`
	Author       string `json:"author"`
	// AuthorBot is true for a GitHub App or other bot author. Snapshots cached
	// before it existed decode as false.
	AuthorBot             bool   `json:"author_bot"`
	State                 string `json:"state"`
	Draft                 bool   `json:"draft"`
	Fork                  bool   `json:"fork"`
	AuthoredByMe          bool   `json:"authored_by_me"`
	ReviewRequestedFromMe bool   `json:"review_requested_from_me"`
	// AssignedToMe is true when the viewer is one of the first 20 assignees.
	// Snapshots cached before it existed decode as false.
	AssignedToMe bool `json:"assigned_to_me"`
	// Nil means the token could not establish repository write permission.
	AuthorHasWrite *bool `json:"author_has_write"`
	// ViewerCanPush is whether the signed-in account may push to the
	// repository (GitHub's viewerPermission is write, maintain or admin),
	// which a fix needs; nil when GitHub did not say.
	ViewerCanPush *bool `json:"viewer_can_push"`
	// False means team membership was unavailable; false review-request flags
	// must not be interpreted as proof that no team requested this viewer.
	TeamMembershipKnown bool   `json:"team_membership_known"`
	Review              string `json:"review"`
	Checks              string `json:"checks"`
	Merge               string `json:"merge"`
	// Behind is GitHub's report (mergeStateStatus BEHIND) that the head
	// branch is out of date with its base and not conflicting, which Update
	// branch fixes. A draft never reports it.
	Behind           bool `json:"behind"`
	Unresolved       *int `json:"unresolved"`
	UnresolvedCapped bool `json:"unresolved_capped"`
	// UpdatedAt is GitHub's last update of the pull request: a push, an edit,
	// a review or a comment. The background refresh re-reads a saved review's
	// evidence when it is newer than the last read.
	UpdatedAt time.Time `json:"updated_at,omitzero"`
}

type RateLimit

type RateLimit struct {
	Cost      *int      `json:"cost,omitempty"`
	Remaining *int      `json:"remaining"`
	Reset     time.Time `json:"reset"`
	RetryAt   time.Time `json:"retry_at"`
}

type Service

type Service struct {

	// Updated, when set before use, is called after anything Cached reads
	// changes: a cache write, or live freshness. It may run with the
	// service's locks held, so it must not call the service.
	Updated func()
	// contains filtered or unexported fields
}

func New

func New(client *github.Client, directory string) *Service

New uses app.sqlite in directory, or the shared application database when empty.

func (*Service) Cached

func (s *Service) Cached(ctx context.Context, repository github.Repository) (Snapshot, error)

Cached never makes a network request. Resolving the configured local token partitions results by credential, so changing accounts cannot reuse an inbox. Disk snapshots are always stale until a successful conditional poll.

func (*Service) Epoch

func (s *Service) Epoch() uint64

func (*Service) Merged

func (s *Service) Merged(ctx context.Context, repository github.Repository, number int, head string) error

Merged records that the app just merged the pull request at head: GitHub accepted the merge, so it leaves the open pull requests and is observed merged without another read. Its title and draft state are the cached ones.

func (*Service) Observe

func (s *Service) Observe(ctx context.Context, repository github.Repository, value Observation) error

Observe retains fresh free metadata for open and saved historical PRs. A separate service instance still treats the disk cache as stale on startup. An observation older than the one kept is dropped: a read under way when the app merged the pull request (Merged) does not undo it.

func (*Service) Poll

func (s *Service) Poll(ctx context.Context, repository github.Repository) (Snapshot, error)

Poll refreshes GraphQL pull pages and conditional REST metadata without waiting through a rate limit. Callers schedule NextPoll; unchanged results back off from 30s to 15m. Failure returns the last complete snapshot, explicitly stale, and an error.

func (*Service) PollNow

func (s *Service) PollNow(ctx context.Context, repository github.Repository) (Snapshot, error)

PollNow is Poll without waiting for NextPoll: something local (a push, an agent session ending) says the pull requests changed. It still honors the shared REST and GraphQL rate budgets.

func (*Service) Probe

func (s *Service) Probe(ctx context.Context, repositories []github.Repository) (map[string]bool, error)

Probe asks GitHub whether each repository's open pull requests changed since its last complete poll, and returns the ones that did, keyed by Repository.String(). It sends one GraphQL query per probeBatch repositories, about one point each, on the polls' shared budget. A repository never polled, or one GitHub does not return (renamed, or access lost), is left to its scheduled poll, as is one whose credential differs from the first repository's.

func (*Service) ResetIdentity

func (s *Service) ResetIdentity()

ResetIdentity cancels the old transaction and invalidates live discovery. Disk partitions remain private and are keyed by their original credential.

func (*Service) Unresolved

func (s *Service) Unresolved(ctx context.Context, repository github.Repository, number, count int) (bool, error)

Unresolved records the count of an open pull request's unresolved review threads that the app just read from GitHub, ahead of the next poll: GitHub reports no update to a pull request when a thread is resolved, so a probe cannot see it. It reports whether the count changed.

type Snapshot

type Snapshot struct {
	Epoch        uint64        `json:"-"`
	Repository   string        `json:"repository"`
	Observations []Observation `json:"observations,omitempty"`
	Viewer       string        `json:"viewer"`
	PullRequests []PullRequest `json:"pull_requests"`
	Stale        bool          `json:"stale"`
	FetchedAt    time.Time     `json:"fetched_at"`
	NextPoll     time.Time     `json:"next_poll"`
	Rate         RateLimit     `json:"rate"`
	Error        string        `json:"error,omitempty"`
	// Settling: this poll found a new head or a mergeability GitHub forgot,
	// or GitHub still works one out since, so NextPoll comes after
	// settleInterval.
	Settling bool `json:"settling,omitempty"`
}

Jump to

Keyboard shortcuts

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