github

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package github binds GitHub in as a target-system plugin (the same pattern as the gitlab package): a REST client for the agent actions, an optional webhook intake (HMAC-SHA256) and the polling checks that carry the review loop. The unit of work is the issue.

One difference to GitLab runs through everything: a repository is addressed by its NAME ("owner/repo"), not by a numeric id. That is GitHub's natural identifier — it stands in every URL the agent reads, so it does not have to look an id up first.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IssueCorrelationKey

func IssueCorrelationKey(repo string, number int) string

IssueCorrelationKey is the stable correlation key for an issue thread. A blocked task carries it and is woken by the matching comment.

func PullCorrelationKey

func PullCorrelationKey(repo string, number int) string

PullCorrelationKey is the counterpart for a pull request thread.

func VerifySignature

func VerifySignature(secret string, body []byte, header string) bool

VerifySignature checks the HMAC-SHA256 signature from the X-Hub-Signature-256 header ("sha256=<hex>"). An empty secret = check disabled (dev only — an open endpoint lets anyone create tasks in a foreign org).

Types

type Branch

type Branch struct {
	Name      string `json:"name"`
	Protected bool   `json:"protected"`
	Default   bool   `json:"default,omitempty"`
	Commit    struct {
		SHA string `json:"sha"`
	} `json:"commit"`
}

Branch is a branch with the head commit it points at.

type CheckRun

type CheckRun struct {
	Name       string `json:"name"`
	Status     string `json:"status"`
	Conclusion string `json:"conclusion"`
	HTMLURL    string `json:"html_url"`
}

CheckRun is a check on a commit — GitHub Actions writes them, and so does every external CI hanging off the Checks API. get_pull reports them, because the mergeability alone does not say whether the tests are green.

type CheckoutResult

type CheckoutResult struct {
	Path  string `json:"path"`
	Repo  string `json:"repo"`
	Ref   string `json:"ref,omitempty"`
	Files int    `json:"files"`
	Hint  string `json:"hint"`
}

CheckoutResult is the answer of the checkout action to the agent: where the code lies and how it goes on working with it.

func Checkout

func Checkout(ctx context.Context, gc *Client, repo, ref, workdir string) (CheckoutResult, error)

Checkout materialises a repository's source in the sandbox: it downloads the archive through the API (the brokered token stays in the daemon, it never lands in the file system — unlike with a git clone using a credential remote) and unpacks it under <workdir>/repos/. An existing state of the same repository/ref is replaced — the agent always works on the current code.

Unlike GitLab, GitHub's archive endpoint knows no sub-path: the tarball always carries the whole repository. A repo too large for the sandbox is therefore not narrowed here but read selectively through list_tree/read_file; the error message says so.

type Client

type Client struct {
	BaseURL string
	Token   string
	HTTP    *http.Client
}

Client speaks the GitHub REST API with a (brokered) token. The token comes from the SecretStore per call — it is never persisted.

func NewClient

func NewClient(baseURL, token string) *Client

NewClient normalises the endpoint. Three spellings arrive here and all three have to work, because whoever enters github_url takes it from their browser:

""                          → https://api.github.com  (github.com)
https://ghe.example.com     → https://ghe.example.com/api/v3  (Enterprise)
https://ghe.example.com/api/v3 → taken as it stands

The rule is deliberately mechanical: an address that does not already carry an API path and whose host is not an "api." host gets GitHub Enterprise Server's /api/v3 appended.

func (*Client) AddAssignees

func (c *Client) AddAssignees(ctx context.Context, repo string, number int, logins []string) (Issue, error)

AddAssignees — POST …/issues/{number}/assignees. GitHub adds; it does not replace. That is what the action wants: a handover names an additional person, it does not wipe the existing assignment.

func (*Client) ApprovePull

func (c *Client) ApprovePull(ctx context.Context, repo string, number int, body string) (Comment, error)

ApprovePull — POST …/pulls/{number}/reviews with event=APPROVE: the formal green signal of a reviewer. The merging itself stays with a human.

func (*Client) Comment

func (c *Client) Comment(ctx context.Context, repo string, number int, body string) (Comment, error)

Comment — POST …/issues/{number}/comments. GitHub knows no internal comments: every contribution is visible to whoever can see the repository. The plugin says so instead of pretending to an "internal" that does not exist.

func (*Client) CreateIssue

func (c *Client) CreateIssue(ctx context.Context, repo, title, body string, labels, assignees []string) (Issue, error)

CreateIssue — POST /repos/{owner}/{repo}/issues.

func (*Client) CreatePull

func (c *Client) CreatePull(ctx context.Context, repo, head, base, title, body string, draft bool) (PullRequest, error)

CreatePull — POST …/pulls. head is the source branch, base the target.

func (*Client) CurrentUser

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

CurrentUser — GET /user: the bot's own identity. Needed everywhere a decision hangs off "did I write that myself?".

func (*Client) DownloadTarball

func (c *Client) DownloadTarball(ctx context.Context, repo, ref string) (io.ReadCloser, error)

DownloadTarball — GET …/tarball/{ref}: the repository archive. GitHub redirects to codeload.github.com; Go follows and drops the Authorization header on the host change, which is right — the redirect target carries its own signature. Deliberately not routed through do(): the body is binary and can be large; the caller closes the reader.

func (*Client) Escalate

func (c *Client) Escalate(ctx context.Context, repo string, number int, note string) error

Escalate posts a comment and hands the item back: the bot removes its OWN assignment so that a human takes the issue over. GitHub knows no internal comments, so the note is visible to whoever can see the repository — the prompt says so, and the agent phrases it accordingly.

func (*Client) GetCommitDiff

func (c *Client) GetCommitDiff(ctx context.Context, repo, sha string) ([]CommitDiff, error)

GetCommitDiff — GET …/commits/{sha}: the commit with its file changes. Long patches are cut off; the flag says so, so that the agent does not read a half-diff as the whole truth.

func (*Client) GetIssue

func (c *Client) GetIssue(ctx context.Context, repo string, number int) (Issue, error)

GetIssue — GET /repos/{owner}/{repo}/issues/{number}.

func (*Client) GetJobLog

func (c *Client) GetJobLog(ctx context.Context, repo string, jobID int64) (string, bool, error)

GetJobLog — GET …/actions/jobs/{id}/logs: GitHub redirects to a signed blob URL, Go follows it. Returns the log's end plus a flag saying it was cut.

func (*Client) GetPull

func (c *Client) GetPull(ctx context.Context, repo string, number int) (PullRequest, error)

GetPull — GET …/pulls/{number}: a single PR with its merge state.

func (*Client) GetRepo

func (c *Client) GetRepo(ctx context.Context, repo string) (Repo, error)

GetRepo — GET /repos/{owner}/{repo}: needed above all for the default branch, which commit and create_pull_request fall back to.

func (*Client) ListBranches

func (c *Client) ListBranches(ctx context.Context, repo, search string) ([]Branch, error)

ListBranches — GET …/branches. search filters afterwards; GitHub's endpoint has no such parameter.

func (*Client) ListCheckRuns

func (c *Client) ListCheckRuns(ctx context.Context, repo, ref string) ([]CheckRun, error)

ListCheckRuns — GET …/commits/{ref}/check-runs.

func (*Client) ListComments

func (c *Client) ListComments(ctx context.Context, repo string, number int) ([]Comment, error)

ListComments — GET /repos/{owner}/{repo}/issues/{number}/comments. Works for pull requests too: to GitHub a PR is an issue with a branch attached, and its conversation runs through the same endpoint.

Fetched NEWEST first and turned round afterwards. The client does not page, and on a thread longer than perPage the natural (oldest-first) order would hand back the opening exchange and cut off the end — the very part every decision here hangs on ("who wrote last?", "has my question been answered?"). Losing the beginning of a long thread costs context; losing the end produces wrong answers.

func (*Client) ListCommits

func (c *Client) ListCommits(ctx context.Context, repo, ref, path, since string) ([]Commit, error)

ListCommits — GET …/commits. All filters are optional: sha (branch/tag/SHA), path (only commits touching that file) and since (an ISO date).

func (*Client) ListIssues

func (c *Client) ListIssues(ctx context.Context, repo, state, labels, search, milestone string, assigned bool) ([]Issue, error)

ListIssues finds issues — with repo through GET /repos/{owner}/{repo}/issues, without one (repo == "") through the global GET /issues, which returns the issues of every repository the token can see.

Two filters GitHub's list endpoint does not offer are applied here, on the answer: search (a substring of title/body) and milestone by TITLE — GitHub wants the milestone NUMBER, which differs per repository and which the agent therefore cannot know. Filtering afterwards keeps the parameter meaning the same as in the GitLab plugin.

Pull requests are sorted out: GitHub delivers them through the issue endpoints too, but they are worked on through the pull actions.

func (*Client) ListMyOpenPulls

func (c *Client) ListMyOpenPulls(ctx context.Context) ([]Issue, error)

ListMyOpenPulls finds the PRs the bot opened itself, across repositories — GitHub offers no such list endpoint, so it goes through the search API. The PRs come back thin (search returns issue objects); the caller fetches what it needs in detail.

func (*Client) ListPullComments

func (c *Client) ListPullComments(ctx context.Context, repo string, number int) ([]Comment, error)

ListPullComments merges a PR's whole conversation into one chronological list: the ordinary comments, the submitted reviews (with their verdict) and the review comments on lines of the diff. GitHub keeps the three apart; to the agent they are one thread, and a review that only appears in one of the three lists is feedback it would otherwise miss.

func (*Client) ListPulls

func (c *Client) ListPulls(ctx context.Context, repo, state, search, base string) ([]PullRequest, error)

ListPulls — GET …/pulls. state accepts GitLab's vocabulary too; search and base filter afterwards.

func (*Client) ListRepos

func (c *Client) ListRepos(ctx context.Context) ([]Repo, error)

ListRepos — GET /user/repos: the repositories the bot user can reach. The entry point for agents that do not yet know their repo names.

func (*Client) ListReviewPulls

func (c *Client) ListReviewPulls(ctx context.Context) ([]Issue, error)

ListReviewPulls finds the PRs in which the bot is entered as reviewer — the QA/test agent's working set.

func (*Client) ListRunJobs

func (c *Client) ListRunJobs(ctx context.Context, repo string, runID int64) ([]Job, error)

ListRunJobs — GET …/actions/runs/{id}/jobs.

func (*Client) ListTree

func (c *Client) ListTree(ctx context.Context, repo, path, ref string, recursive bool) ([]TreeEntry, error)

ListTree lists the repository tree. Two routes, because GitHub splits the job: non-recursively the contents API (one directory), recursively the git trees API filtered by the path prefix. Both are capped at perPage entries — a whole tree does not belong in an agent's context.

func (*Client) ListWorkflowRuns

func (c *Client) ListWorkflowRuns(ctx context.Context, repo, branch string) ([]WorkflowRun, error)

ListWorkflowRuns — GET …/actions/runs, optionally narrowed to one branch.

func (*Client) LookupUser

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

LookupUser — GET /users/{login}: checks that a login exists before it is entered as an assignee or reviewer. GitHub silently swallows an unknown assignee (the request succeeds, the assignment does not happen) — that is the kind of failure that only shows up days later.

func (*Client) ReadFile

func (c *Client) ReadFile(ctx context.Context, repo, filePath, ref string) (content string, truncated bool, err error)

ReadFile — GET …/contents/{path}: a single file's content. GitHub delivers it base64-encoded; large files come back without content and need the blob API, which is deliberately not taken here — that size belongs in a checkout.

func (*Client) RequestChanges

func (c *Client) RequestChanges(ctx context.Context, repo string, number int, body string) (Comment, error)

RequestChanges — POST …/pulls/{number}/reviews with event=REQUEST_CHANGES: the reviewer's counterpart to the approval. GitHub blocks the merge with it where the branch protection demands a review, so a defect found does not only stand in a comment but actually holds the PR up.

func (*Client) RequestReviewers

func (c *Client) RequestReviewers(ctx context.Context, repo string, number int, logins []string) (PullRequest, error)

RequestReviewers — POST …/pulls/{number}/requested_reviewers.

func (*Client) RerunFailedJobs

func (c *Client) RerunFailedJobs(ctx context.Context, repo string, runID int64) error

RerunFailedJobs — POST …/actions/runs/{id}/rerun-failed-jobs: starts the failed jobs of a run afresh. For a red pipeline whose cause lay outside the change (a runner missing, a registry down) and has been fixed since.

func (*Client) SetLabels

func (c *Client) SetLabels(ctx context.Context, repo string, number int, add, remove []string) ([]string, error)

SetLabels works additively/subtractively instead of overwriting the whole list — otherwise every state change takes the subject-matter labels with it. GitHub has one endpoint per direction, so this is two calls at most.

func (*Client) SetState

func (c *Client) SetState(ctx context.Context, repo string, number int, state string) (Issue, error)

SetState — PATCH …/issues/{number}. Accepts GitLab's verbs ("close"/"reopen") as well as GitHub's states ("closed"/"open").

type Comment

type Comment struct {
	ID        int64  `json:"id"`
	Kind      string `json:"kind,omitempty"` // comment | review | review_comment
	Body      string `json:"body"`
	User      User   `json:"user"`
	CreatedAt string `json:"created_at"`
	HTMLURL   string `json:"html_url"`
	// State carries a review's verdict (APPROVED, CHANGES_REQUESTED,
	// COMMENTED); empty for ordinary comments.
	State string `json:"state,omitempty"`
	// Path/Line locate a review comment in the diff.
	Path string `json:"path,omitempty"`
	Line int    `json:"line,omitempty"`
	// SubmittedAt is a review's timestamp; normalised into CreatedAt.
	SubmittedAt string `json:"submitted_at,omitempty"`
}

Comment is a contribution to an issue or pull request. GitHub keeps three kinds apart that mean the same thing to the agent — an issue comment, a review (with a verdict) and a review comment on a line of the diff. The plugin merges them into ONE chronological list; Kind says where the entry comes from.

type Commit

type Commit struct {
	SHA    string `json:"sha"`
	Commit struct {
		Message string `json:"message"`
		Author  struct {
			Name string `json:"name"`
			Date string `json:"date"`
		} `json:"author"`
	} `json:"commit"`
	HTMLURL string `json:"html_url"`
}

Commit is an entry of the commit history.

type CommitDiff

type CommitDiff struct {
	Filename  string `json:"filename"`
	Status    string `json:"status"`
	Additions int    `json:"additions"`
	Deletions int    `json:"deletions"`
	Patch     string `json:"patch,omitempty"`
	Truncated bool   `json:"truncated,omitempty"`
}

CommitDiff is one file's change within a commit.

type CommitResult

type CommitResult struct {
	Repo          string   `json:"repo"`
	Branch        string   `json:"branch"`
	BranchCreated bool     `json:"branch_created"`
	Commit        Commit   `json:"commit"`
	Files         []string `json:"files"`
	Deleted       []string `json:"deleted,omitempty"`
	Hint          string   `json:"hint"`
}

CommitResult is the answer of the commit action: what was pushed and how things continue (opening a pull request).

func CommitFromCheckout

func CommitFromCheckout(ctx context.Context, gc *Client, repo, branch, startBranch, message, checkoutPath string, files, deleted []string, workdir string) (CommitResult, error)

CommitFromCheckout pushes locally edited files from the sandbox checkout as ONE commit onto a feature branch — through the Git Data API (see gitdata.go), so that the brokered token stays in the daemon (no git remote with credentials in the sandbox). If the branch does not exist yet, it is branched off the start branch (default: the repository's default branch). Direct commits onto the default branch are forbidden fail-closed — the route into the main branch leads exclusively through a pull request.

type DownloadAttachmentResult

type DownloadAttachmentResult struct {
	Path        string `json:"path"`
	Filename    string `json:"filename"`
	ContentType string `json:"content_type,omitempty"`
	Bytes       int64  `json:"bytes"`
	Hint        string `json:"hint"`
}

DownloadAttachmentResult is the answer of the download_attachment action: where the image lies in the sandbox and how the agent looks at it.

func DownloadAttachmentToSandbox

func DownloadAttachmentToSandbox(ctx context.Context, gc *Client, rawURL, workdir string) (DownloadAttachmentResult, error)

DownloadAttachmentToSandbox fetches an image attached to an issue/PR into the sandbox in brokered fashion — the token stays in the daemon, the file lands under <workdir>/uploads/. The agent then reads it with the Read tool (vision) and can actually look at the screenshot.

GitHub redirects attachment links to signed storage URLs. Go drops the Authorization header on the host change, which is right: the redirect target carries its own signature and would refuse a foreign token.

type Issue

type Issue struct {
	Repo      string  `json:"repo"`
	Number    int     `json:"number"`
	Title     string  `json:"title"`
	Body      string  `json:"body"`
	State     string  `json:"state"`
	Labels    []Label `json:"labels"`
	HTMLURL   string  `json:"html_url"`
	User      User    `json:"user"`
	Assignees []User  `json:"assignees"`
	// Milestone attaches the issue to an undertaking (a release, a sprint).
	// GitHub returns null when there is none.
	Milestone *struct {
		Title string `json:"title"`
		DueOn string `json:"due_on"`
		State string `json:"state"`
	} `json:"milestone"`
	Comments  int    `json:"comments"`
	CreatedAt string `json:"created_at"`
	UpdatedAt string `json:"updated_at"`
	// PullRequest is set by GitHub when this "issue" is in fact a PR.
	PullRequest *struct {
		HTMLURL string `json:"html_url"`
	} `json:"pull_request,omitempty"`
	// Repository comes back from the global GET /issues only; for the
	// repository endpoint the plugin fills Repo in itself.
	Repository *struct {
		FullName string `json:"full_name"`
	} `json:"repository,omitempty"`
}

Issue is an issue. GitHub also lists pull requests through the issue endpoints — PullRequest != nil marks exactly that case, and the plugin sorts those out (a PR is worked on through the pull actions).

func (Issue) IsPullRequest

func (i Issue) IsPullRequest() bool

IsPullRequest reports whether an entry from an issue list is in truth a pull request.

type Job

type Job struct {
	ID         int64  `json:"id"`
	Name       string `json:"name"`
	Status     string `json:"status"`
	Conclusion string `json:"conclusion"`
	HTMLURL    string `json:"html_url"`
	StartedAt  string `json:"started_at"`
}

Job is one job of a workflow run.

type Label

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

Label carries the name only; colour and description do not belong in the agent's context.

type PullRequest

type PullRequest struct {
	Repo   string `json:"repo"`
	Number int    `json:"number"`
	Title  string `json:"title"`
	Body   string `json:"body"`
	State  string `json:"state"` // open | closed
	Draft  bool   `json:"draft"`
	// Merged comes back from the single-PR endpoint only. MergedAt is in the
	// list answer too, so a "merged" filter over a list costs no extra request
	// per entry — which at 100 hits is the difference between one request and
	// a hundred.
	Merged   bool   `json:"merged"`
	MergedAt string `json:"merged_at,omitempty"`
	HTMLURL  string `json:"html_url"`
	User     User   `json:"user"`
	Head     struct {
		Ref string `json:"ref"`
		SHA string `json:"sha"`
	} `json:"head"`
	Base struct {
		Ref string `json:"ref"`
	} `json:"base"`
	Assignees          []User `json:"assignees"`
	RequestedReviewers []User `json:"requested_reviewers"`
	// Mergeable/MergeableState are GitHub's review state. Mergeable is null
	// while GitHub is still computing the merge — a fact the agent has to see,
	// hence the pointer.
	Mergeable      *bool  `json:"mergeable"`
	MergeableState string `json:"mergeable_state,omitempty"`
	CreatedAt      string `json:"created_at"`
	UpdatedAt      string `json:"updated_at"`
}

PullRequest is a pull request — GitHub's counterpart to the merge request.

type Repo

type Repo struct {
	Full          string `json:"repo"`
	FullName      string `json:"full_name"`
	Description   string `json:"description"`
	HTMLURL       string `json:"html_url"`
	DefaultBranch string `json:"default_branch"`
	Private       bool   `json:"private"`
	Archived      bool   `json:"archived"`
	Permissions   struct {
		Push bool `json:"push"`
	} `json:"permissions"`
}

Repo is a repository. Full ("owner/name") is the identifier every action takes.

type System

type System struct{}

System binds GitHub in as a target-system plugin to the target registry: the webhook entry (HMAC-verified, idempotent), the polling checks for the heartbeat, the agent actions and the action documentation for the system prompt.

func (System) ActionSubject

func (System) ActionSubject(action string, params json.RawMessage) string

ActionSubject maps action+params onto the guard-rail subject. Unlike Zammad and GitLab there is no internal/external split: GitHub knows no internal comments, every contribution is visible to whoever can see the repository. The writing actions therefore each carry their own subject, so a rule can govern "may comment" and "may push" separately.

func (System) Execute

func (System) Execute(ctx context.Context, actionName string, params json.RawMessage, cred target.Credential) (any, error)

func (System) HasWork

func (System) HasWork(ctx context.Context, cred target.Credential) (bool, error)

HasWork (target.WorkChecker): the control plane's cheap pre-check for nur-wenn: heartbeats — it saves the (expensive) agent wake when there is nothing to do at the moment. Work is present when ONE of the following holds:

  • There is an open issue in the intake scope on which the bot has not yet commented last.
  • The bot has an open pull request it opened itself with unanswered review feedback. That carries the review loop.

What counts everywhere is the EDGE (has something happened since the bot's last move?), not the level (is anything open anywhere?) — otherwise the same unfinished item wakes the agent afresh in every interval.

func (System) HasWorkKind

func (System) HasWorkKind(ctx context.Context, cred target.Credential, kind string) (bool, error)

HasWorkKind (target.KindWorkChecker) gates a single kind of work so that several heartbeats fire separately:

  • "issues"/"issue" → is ANY open issue in the intake scope waiting for a reaction?
  • "issues:assigned"/"assigned" → is an open issue waiting that is ASSIGNED to the bot itself? Exactly that is what an agent needs whose playbook works only on its own issues.
  • "pr"/"prs"/"mr" → is one of the PRs the bot opened ITSELF waiting for an answer (the author's view, the developer review loop)?
  • "review"/"reviews" → is one of the PRs in which the bot is entered as REVIEWER waiting for its review (the QA/test view)?
  • otherwise → both of HasWork, fail-open on an unknown scope.

func (System) HasWorkSigned

func (System) HasWorkSigned(ctx context.Context, cred target.Credential, kind string) (bool, string, error)

HasWorkSigned (target.SignedWorkChecker) is the actual check: besides the yes/no it returns the signature of the waiting items so that the control plane does not wake twice on the same state. An agent may thereby end a run silently — the QA colleague's feedback was an approval, there is nothing to do — without being woken again in the next interval. If a new contribution or a push comes along, the signature changes and the agent wakes. Whether a piece of feedback means work (reported defects) or only information (an approval) is thus decided by the agent and not by the gate.

func (System) Name

func (System) Name() string

func (System) ParseWebhook

func (System) ParseWebhook(body []byte) (target.WebhookEvent, error)

ParseWebhook (target.Webhooker) turns the payload into the wake event.

func (System) Probe

func (System) Probe(ctx context.Context, cred target.Credential) (string, error)

Probe reads the account behind the token. `/user` costs one read against the rate limit, changes nothing, and answers the question the setup assistant asks: is this token alive, and whose is it.

func (System) PromptDoc

func (System) PromptDoc() string

func (System) VerifyWebhook

func (System) VerifyWebhook(secret string, body []byte, header http.Header) bool

VerifyWebhook (target.Webhooker) checks GitHub's HMAC-SHA256 signature.

type TreeEntry

type TreeEntry struct {
	Path string `json:"path"`
	Type string `json:"type"` // blob | tree
	Size int    `json:"size,omitempty"`
	SHA  string `json:"sha,omitempty"`
}

TreeEntry is one entry of the repository tree.

type User

type User struct {
	Login string `json:"login"`
	Type  string `json:"type"` // "User" | "Bot" | "Organization"
}

User is an account. Login is what every action expects as "username" — the numeric id plays no part in GitHub's API.

type WebhookPayload

type WebhookPayload struct {
	Action     string `json:"action"`
	Repository struct {
		FullName string `json:"full_name"`
	} `json:"repository"`
	Sender User `json:"sender"`
	Issue  *struct {
		Number      int    `json:"number"`
		Title       string `json:"title"`
		Body        string `json:"body"`
		HTMLURL     string `json:"html_url"`
		User        User   `json:"user"`
		PullRequest *struct {
			HTMLURL string `json:"html_url"`
		} `json:"pull_request,omitempty"`
	} `json:"issue"`
	PullRequest *struct {
		Number  int    `json:"number"`
		Title   string `json:"title"`
		HTMLURL string `json:"html_url"`
		Merged  bool   `json:"merged"`
	} `json:"pull_request"`
	Comment *struct {
		ID   int64  `json:"id"`
		Body string `json:"body"`
		User User   `json:"user"`
		Path string `json:"path"`
	} `json:"comment"`
	Review *struct {
		ID    int64  `json:"id"`
		Body  string `json:"body"`
		State string `json:"state"`
		User  User   `json:"user"`
	} `json:"review"`
}

WebhookPayload is the relevant excerpt of the GitHub webhook JSON. GitHub sends one shape per event type; the fields that do not belong to the event at hand stay nil.

func ParseWebhook

func ParseWebhook(body []byte) (WebhookPayload, error)

ParseWebhook decodes the payload and rejects anything without a repository — every event Covey acts on carries one.

func (WebhookPayload) Event

Event turns a payload into the wake event for the orchestrator. Anything not recognised answers with Wake=false: the delivery is registered (and thereby acknowledged) but changes nothing — GitHub sends whatever the hook was subscribed to, and an unknown shape is not a reason to invent work.

func (WebhookPayload) Kind

func (p WebhookPayload) Kind() string

Kind derives the event kind from the payload shape (see the constants).

type WorkflowRun

type WorkflowRun struct {
	ID         int64  `json:"id"`
	Name       string `json:"name"`
	Status     string `json:"status"`     // queued | in_progress | completed
	Conclusion string `json:"conclusion"` // success | failure | cancelled | …
	HeadBranch string `json:"head_branch"`
	HeadSHA    string `json:"head_sha"`
	Event      string `json:"event"`
	HTMLURL    string `json:"html_url"`
	CreatedAt  string `json:"created_at"`
	UpdatedAt  string `json:"updated_at"`
}

WorkflowRun is a GitHub Actions run — the counterpart to the GitLab pipeline.

Jump to

Keyboard shortcuts

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