github

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package github is the GitHub adapter for botbooter. It receives issue and PR comments as issue_comment webhook events over an inbound HTTP server and replies by creating issue comments through the GitHub REST API (go-github). It implements core.Adapter. Optional Config callbacks (OnPullRequest, OnPush) additionally route pull_request and push deliveries on the same webhook endpoint; unset, those deliveries are acked and dropped.

Like the WhatsApp and Teams adapters, Connect binds a listener and serves until the run context is canceled; Disconnect shuts it down and drains in-flight dispatch. Bind a local Addr, put a TLS-terminating proxy in front, and register the public HTTPS URL as the repository or App webhook URL (content type application/json, events: issue_comment plus pull_request and/or push when the matching callback is set, with a secret).

Implementation split (mirrors Teams): github.go (config, auth wiring, accessors), server.go (webhook lifecycle), send.go (replies), message.go (payload mapping), reactions.go (opt-in polled reaction ingress — GitHub sends no webhook for reactions).

Index

Constants

This section is empty.

Variables

View Source
var ErrAmbiguousAuth = errors.New("github: configure either Token or AppID/InstallationID/PrivateKey, not both")

ErrAmbiguousAuth is returned by New when both PAT and App auth are configured.

View Source
var ErrBadChannelID = errors.New(`github: channel ID must be "owner/repo#number"`)

ErrBadChannelID is returned by Send when channelID is not "owner/repo#number".

View Source
var ErrBadReactionConfig = errors.New("github: invalid reaction polling config")

ErrBadReactionConfig is returned by New when a reaction-polling Config field is malformed: a ReactionPollRepos entry that is not "owner/name" or the wildcard "owner/*", or a negative ReactionPollInterval.

View Source
var ErrMissingConfig = errors.New("github: missing required config field")

ErrMissingConfig is returned by New when a required Config field is empty.

Functions

func Addr

func Addr(b *core.Bot) string

Addr returns the address the bot's webhook listener is bound to (host:port), or "" if b is not a GitHub bot or is not currently connected. It lets a caller that passed cfg.Addr ":0" discover the OS-assigned port.

func Client

func Client(b *core.Bot) *gogithub.Client

Client returns the underlying go-github client, or nil if b is not a GitHub bot. Use it for API calls beyond the adapter's send path (labels, reactions, checks); it is safe for concurrent use.

func New

func New(cfg Config) (*core.Bot, error)

New creates a GitHub bot. It returns ErrMissingConfig if a required field is absent and ErrAmbiguousAuth if both auth modes are set, and otherwise applies defaults for Path and HTTPClient. The webhook server is not started until the bot connects.

Types

type Config

type Config struct {
	// Token is a personal access token (classic or fine-grained) for PAT mode.
	// The bot posts comments as the token's user.
	Token string

	// AppID is the GitHub App ID for App mode.
	AppID int64
	// InstallationID is the App installation to act as; it is also visible in
	// webhook payloads and on the installation settings page.
	InstallationID int64
	// PrivateKey is the App's RSA private key, PEM-encoded.
	PrivateKey []byte

	// WebhookSecret verifies the X-Hub-Signature-256 HMAC on inbound webhook
	// requests. Required: without it the endpoint would accept spoofed payloads.
	WebhookSecret string
	// Addr is the local TCP address the webhook server binds, e.g. ":8080". A
	// bare port ("8080") is accepted as shorthand for ":8080".
	Addr string
	// Path is the webhook route; it defaults to /webhook.
	Path string

	// OnPullRequest, when set, receives pull_request webhook deliveries whose
	// action is "opened", "reopened" or "synchronize" — the deliveries that
	// create or change a PR's reviewable content. Other actions, and PRs
	// authored by any bot or by this bot's own account, are acked and dropped,
	// mirroring the comment path's reply-loop filter. The callback runs on a
	// dispatch goroutine covered by Disconnect's drain (same contract as
	// message dispatch), so it should hand long work off and return promptly.
	// Nil (the default) keeps the previous behavior: pull_request deliveries
	// are acked and dropped. The webhook must also be subscribed to the
	// pull_request event, or GitHub never delivers one.
	OnPullRequest func(ctx context.Context, event *gogithub.PullRequestEvent)

	// OnPush, when set, receives push webhook deliveries, unfiltered — ref
	// filtering (e.g. default branch only) is the callback's job. Same
	// goroutine and drain contract as OnPullRequest. Nil (the default) acks
	// and drops; the webhook must also be subscribed to the push event.
	OnPush func(ctx context.Context, event *gogithub.PushEvent)

	// HTTPClient is the base client for outbound GitHub API calls; a default
	// client with a 30s timeout is used when nil. In App mode only its
	// Transport (http.DefaultTransport when nil) and Timeout are used — the
	// Transport becomes the inner transport of the ghinstallation
	// token-refreshing transport, and other fields (Jar, CheckRedirect) are
	// ignored.
	HTTPClient *http.Client

	// ReactionPollRepos lists repositories whose newest issue comments are
	// polled for emoji reactions, because GitHub sends no webhook for them.
	// An entry is either explicit ("owner/name") or a wildcard ("owner/*"):
	// every repository of that owner the credentials can see, minus archived
	// ones — the authenticated user's own repos (private included) in PAT
	// mode when the owner is the bot itself, that owner's public repos
	// otherwise, and the installation's repos in App mode. Wildcards are
	// re-resolved every ~10 poll cycles, so new repositories are picked up
	// without a restart. Empty (the default) disables polling and OnReaction
	// never fires. The poller also requires an OnReaction handler registered
	// before the bot connects — with repos listed but no handler, no poller
	// starts and no API requests are spent. Coverage is deliberately partial
	// — only reactions on each repo's newest comments are seen — and each
	// polled repo costs at least one API request per poll cycle (worst case
	// ~11, when every window comment's reaction count changed). Duplicate
	// entries collapse to one.
	ReactionPollRepos []string
	// ReactionPollInterval is the delay between reaction poll cycles; it
	// defaults to 30 seconds and is also the reaction delivery latency.
	// When the polled repo count at this interval would exceed the poller's
	// API request budget (3000 requests/hour), the adapter logs a warning and
	// automatically raises the effective interval to fit — unless
	// ReactionPollNoAutoInterval is set. Reaction dedup across cycles is
	// in-process only: a restart forgets what was handled, and only reactions
	// added while connected are dispatched, so reactions added while the bot
	// was down are missed.
	ReactionPollInterval time.Duration
	// ReactionPollNoAutoInterval disables the automatic raising of the
	// effective poll interval when the polled repo count would exceed the API
	// request budget. The over-budget warning is still logged; the configured
	// ReactionPollInterval is honored and the rate limit may be exhausted.
	ReactionPollNoAutoInterval bool
}

Config configures a GitHub bot. Exactly one auth mode must be set: Token (PAT mode) or the AppID/InstallationID/PrivateKey triple (App mode).

type Message

type Message struct {
	Event *gogithub.IssueCommentEvent
}

Message is the typed raw payload stored in core.Message.Raw for GitHub bots. Consumers can distinguish PR comments from issue comments via Event.GetIssue().IsPullRequest().

func RawEvent

func RawEvent(m *core.Message) (*Message, bool)

RawEvent returns the typed issue_comment event carried on m, reporting whether m originated from GitHub.

type ReactionPayload

type ReactionPayload struct {
	Reaction *gogithub.Reaction
	Comment  *gogithub.IssueComment
}

ReactionPayload is the typed raw payload stored in core.Reaction.Raw for GitHub bots: the reaction and the issue comment it was added to. There is no webhook event to carry — GitHub sends none for reactions; the adapter discovered the reaction by polling (see Config.ReactionPollRepos).

func RawReaction

func RawReaction(r *core.Reaction) (*ReactionPayload, bool)

RawReaction returns the typed reaction payload carried on r, reporting whether r originated from GitHub. Reaction.GetContent gives the bare REST content name ("+1", "hooray") behind the unicode Emoji.

Jump to

Keyboard shortcuts

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