Documentation
¶
Overview ¶
Package board picks the next item of work from a GitHub project board: it reads the board's open items once, ranks them by the configured order and says for every item above the pick why it was skipped. Which items a session already serves is the caller's to decide; the rank is pure.
Index ¶
- Constants
- func ByPriority(cands []Candidate, r Ranks, parent func(string) string)
- func Matches(st config.BoardStep, it Item, now time.Time) bool
- func Ref(s string) (owner, repo string, n int, err error)
- func Resolve(field string, values []string, in string) (string, error)
- func ResolveOrder(order []config.BoardStep, statuses, kinds []string) ([]config.BoardStep, error)
- func Unoffered(order []config.BoardStep, it Item, now time.Time) string
- type Candidate
- type Client
- func (c *Client) AnswerThread(ctx context.Context, ref string) (*Thread, error)
- func (c *Client) Block(ctx context.Context, ref, by string) (*Held, error)
- func (c *Client) Closes(ctx context.Context, refs []string) (map[string][]string, error)
- func (c *Client) Comment(ctx context.Context, t *Thread, body string) (string, error)
- func (c *Client) Epics(ctx context.Context) ([]Epic, error)
- func (c *Client) FindPlans(ctx context.Context, refs []string) (map[string]*Plan, error)
- func (c *Client) Move(ctx context.Context, ref, in string) (*Moved, error)
- func (c *Client) Open(ctx context.Context, ref string) (bool, error)
- func (c *Client) Priorities(ctx context.Context) (Priorities, error)
- func (c *Client) Rank(ctx context.Context, ref string, at Place) (*Ranked, error)
- func (c *Client) Read(ctx context.Context, now time.Time) (*Snapshot, error)
- func (c *Client) RecordGo(ctx context.Context, g *Go, body string) (string, error)
- func (c *Client) SetPriority(ctx context.Context, ref string, rank int) (*Prioritized, error)
- func (c *Client) Unblock(ctx context.Context, ref, by string) (*Held, error)
- type Epic
- type Gate
- type Go
- type GraphQLError
- type Held
- type Item
- type Moved
- type Partial
- type Place
- type Plan
- type Priorities
- type Prioritized
- type Ranked
- type RankedEpic
- type Ranks
- type Refusal
- type Snapshot
- type Thread
Constants ¶
const ( StatusField = "Status" KindField = "Kind" TeamField = "Team" )
The board's fields the order and the moves read.
const LeaseLabel = "lease/"
LeaseLabel is the prefix of an issue label naming a lease the work needs: lease/agentlab-1.
const PriorityField = "Priority"
PriorityField is the board's number field that holds the priority list: an epic's rank, 1 the top. Only the person sets it (beekeeper priority set --as <person>); board next applies it.
Variables ¶
This section is empty.
Functions ¶
func ByPriority ¶ added in v0.131.0
ByPriority orders cands by the rank each has (Ranks.Of, from its own parent and upward through parent) first, unranked after ranked, and keeps their order within a rank: the priority list over the configured order. It records the rank applied on each candidate.
func Resolve ¶
Resolve returns the one value of values that in stands for: the value itself, or the only one whose words (case, emoji and punctuation ignored) begin with or contain in's. Anything else is an error that lists the values.
func ResolveOrder ¶
ResolveOrder returns order with its Status and Kind values replaced by the board's canonical ones.
Types ¶
type Candidate ¶
type Candidate struct {
Item
// Step is the name of the step that offers it; Epic the epic whose
// sub-issue it is.
Step string `json:"step"`
Epic string `json:"epic,omitempty"`
// Skip says why it is not free, empty when it is.
Skip string `json:"skip,omitempty"`
// Priority is the rank ByPriority applied, 0 for none; PriorityOf the
// epic it is the rank of, the candidate itself or an ancestor.
Priority int `json:"priority,omitempty"`
PriorityOf string `json:"priorityOf,omitempty"`
}
Candidate is an item the order offers, in its place.
func Rank ¶
Rank returns the candidates of every step in order, each item once, in the first step that matches it. A SubIssues step offers an item with open sub-issues through them (its remainder) and is the item's only step; an item without is offered itself. A sub-issue that is a board item, of any Team or Status, is held to the order like any other: one no step offers on its own (an old Backlog item, a blocked one, one in Inbox) is marked skipped with the reason. Items with an open recorded blocker, without activity for b.StaleAfter or assigned to anybody outside b.People are marked skipped too. The epic gate (snap.Gate) holds an epic in planning and every issue under it whatever the step: the epic is marked skipped with its plan, never offered through its sub-issues, and an issue whose nearest epic among its parents on the board is in planning is marked skipped naming it. What GitHub answered with an error is never read as absent: a sub-issue whose board fields are unknown takes them from its item among snap.Items, else is marked skipped naming them, and an item whose sub-issues are unknown is offered skipped itself.
func (Candidate) PriorityText ¶ added in v0.131.0
PriorityText says the rank applied: "priority 2", "priority 2 of epic owner/repo#n" when inherited; "" for none.
type Client ¶
Client reads and moves the items of one board through the GitHub GraphQL API; Plans are the plans repositories (owner/repo) an epic's plan is found in.
func (*Client) AnswerThread ¶ added in v0.142.0
AnswerThread is the thread an answer about ref is recorded on: one read of ref and its parents acting on ref's repository, and one search for the plans naming it or its parents when its repository is public. A ref that does not exist, or a public one with no private thread, is refused.
func (*Client) Block ¶ added in v0.128.0
Block records the issue by as a blocker of the issue ref, a GitHub blocked-by dependency (addBlockedBy): board next skips ref while one of its blockers is open and offers it again once they closed, with no session acting. A dependency recorded already is left as it is.
func (*Client) Closes ¶ added in v0.102.0
Closes reads the issues each pull request among refs closes (its closing references, the Closes and Fixes keywords resolved across repositories), keyed by the lower-cased ref as given, closesBatch refs of one owner per request, acting on their repository (github.ActingOn). An issue among refs, or a ref that is no issue, closes nothing; nil when nothing was asked.
func (*Client) Comment ¶ added in v0.142.0
Comment posts body on the thread, acting on its repository, and returns the comment's URL.
func (*Client) Epics ¶ added in v0.127.0
Epics reads the board's epics in planning or past their go, the team's, with their plans: one request for the fields, one per 100 items, one per plansBatch epics. Nil when the gate is off.
func (*Client) FindPlans ¶ added in v0.127.0
FindPlans finds the plan of each epic of refs, keyed by the lower-cased ref: one search of the plans repositories (Client.Plans) per epic for pull requests naming it, plansBatch searches per request, acting on the first plans repository. Of those whose description's Epic line names the epic (its URL or owner/repo#n), the most recently updated open one is the plan, else the most recently updated merged one; a closed one never is. Nil when no plans repository is configured.
func (*Client) Move ¶
Move sets the Status of the board item of the issue ref to the status in stands for (see Resolve): the item the issue's projectItems name, else the one addProjectV2ItemById answers, which is the issue's existing item or a new one, with board.team as its Team when it has none; no read of the board's items. An issue of a repository outside the board's owner whose projectItems name no item of the board is never added to it: its item on a project of its repository's own owner (a personal account's user project) moves there by that project's Status values, Moved.Board naming it, without a Team or the epic gate; with no such item, or more than one, it is refused, naming the recipe. Every call acts on the issue's repository (github.ActingOn), so a gh link choosing its login by the owner reaches the issue. An unknown or ambiguous status, and a board.team that is none of the Team field's values, are refused with the board's values before anything is written; an issue GitHub does not resolve is refused as no issue, with GitHub's reason. A move of an epic to the epic gate's go status is the go: Moved.Go names its plan and the private thread to record it on (RecordGo), and an epic with a plan but no private thread is refused before anything is written.
func (*Client) Open ¶ added in v0.73.2
Open reports whether the issue or pull request ref is open, acting on its repository (github.ActingOn).
func (*Client) Priorities ¶ added in v0.131.0
func (c *Client) Priorities(ctx context.Context) (Priorities, error)
Priorities reads the priority list: the open epics of board.team (the epic gate's kinds) whose Priority field holds a rank, by rank and, within one, in the board's order. A board without a Priority field has an empty list. It is the one read every consumer of the priorities calls (board next; lease, lanes and capacity next), with Ranks and Ranks.Of on top.
func (*Client) Rank ¶ added in v0.126.0
Rank moves the board item of the issue ref to the place at with updateProjectV2ItemPosition, the board's position being the order board next reads its items in. An issue without an item is added first, as Move adds it, with board.team as its Team. The item of a Before or After issue is found by that issue's projectItems and must be on the board already; Before is two moves, the item after the other one and the other one after the item, so nothing reads the board's items to find the other one's predecessor. Each call acts on the repository of the issue it asks about. No issue, a reference without an item on the board and an item placed against itself are refused before anything is written.
func (*Client) Read ¶
Read reads the board items the order can offer and the epic gate holds, the open sub-issues of the items a SubIssues step matches, the search steps' issues and the plans of the epics the gate watches: one request for the fields, one per 100 items, one per extrasBudget sub-issues for the sub-issues and searches, one per plansBatch epics.
func (*Client) RecordGo ¶ added in v0.127.0
RecordGo posts the go's comment on its private thread, acting on the thread's repository, and returns the comment's URL.
func (*Client) SetPriority ¶ added in v0.131.0
SetPriority puts the epic ref at rank in the priority list, 1 the top: the epics at and below the rank move down one, and the list stays ranked 1..n (a rank past its end is its end). rank 0 takes the epic off the list, the epics below it moving up one. Only the items whose rank changes are written, each by its id; the list is read with Priorities, the epic's item from its projectItems (added to the board as Move adds one). The caller is the one to check that the person asked for it. Refused before anything is written: a board without a number field Priority, an issue that does not exist, is closed or is no epic of the epic gate's kinds.
type Epic ¶ added in v0.127.0
type Epic struct {
Ref string `json:"ref"`
URL string `json:"url"`
Title string `json:"title"`
Status string `json:"status"`
Plan *Plan `json:"plan"`
}
Epic is an epic the gate watches, in planning or past its go, with its plan, nil when no plan pull request names it.
type Gate ¶ added in v0.127.0
Gate is the epic gate (config.EpicGate) in the board's canonical values; the zero Gate is off.
func ResolveGate ¶ added in v0.127.0
ResolveGate resolves e against the board's statuses and kinds. A value board.epics names must be the board's; a default the board has not turns the gate off (no epic kind, no planning status) or the go unrecorded.
func (Gate) InPlanning ¶ added in v0.127.0
InPlanning reports whether it is an epic in planning.
type Go ¶ added in v0.127.0
type Go struct {
Epic string `json:"epic"`
Plan *Plan `json:"plan,omitempty"`
Thread string `json:"thread,omitempty"`
// Comment is the URL of the comment that records the go.
Comment string `json:"comment,omitempty"`
// contains filtered or unexported fields
}
Go is the go a move is: an epic moved to the gate's go status. Plan is its plan, nil for none, and Thread the private thread the go is recorded on (owner/repo#n): the epic itself in a private repository, else its plan pull request in a private one.
type GraphQLError ¶ added in v0.129.0
GraphQLError is one error GitHub answered beside the data: Path is the field it could not resolve (aliases, field names and list indexes), Type GitHub's kind of error (NOT_FOUND, RESOURCE_LIMITS_EXCEEDED, …).
type Held ¶ added in v0.128.0
type Held struct {
Ref string `json:"ref"`
By string `json:"by"`
// ByOpen says the blocker is open: the hold keeps the item from board
// next until it closes.
ByOpen bool `json:"byOpen"`
// Changed says the dependency was added or removed; false when it was
// recorded already (block) or not recorded (unblock).
Changed bool `json:"changed"`
// Blockers and OpenBlockers are the issue's recorded blockers after the
// change, all and the open ones.
Blockers int `json:"blockers"`
OpenBlockers int `json:"openBlockers"`
}
Held is a hold recorded on an issue, or removed from it: the issue's GitHub blocked-by dependency on another issue, which board next reads.
type Item ¶
type Item struct {
// Ref is owner/repo#n.
Ref string `json:"ref"`
URL string `json:"url"`
Title string `json:"title"`
// OnBoard says it is an item of the board project, Status and Kind
// its board fields.
OnBoard bool `json:"onBoard,omitempty"`
Status string `json:"status,omitempty"`
Kind string `json:"kind,omitempty"`
Labels []string `json:"labels,omitempty"`
Assignees []string `json:"assignees,omitempty"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
// Blockers counts the recorded blockers, OpenBlockers the open ones.
Blockers int `json:"blockers,omitempty"`
OpenBlockers int `json:"openBlockers,omitempty"`
// OpenSubIssues counts the open sub-issues; SubIssues are they, read
// for a SubIssues step only.
OpenSubIssues int `json:"openSubIssues,omitempty"`
SubIssues []Item `json:"subIssues,omitempty"`
// Parent is the issue it is a sub-issue of, owner/repo#n.
Parent string `json:"parent,omitempty"`
// Missing names the fields of it GitHub answered with an error instead
// of their value ("<field>: <message>"): they are unknown, not absent.
Missing []string `json:"missing,omitempty"`
// contains filtered or unexported fields
}
Item is an open issue: a board item or a sub-issue or search result.
type Moved ¶
type Moved struct {
Ref string `json:"ref"`
From string `json:"from,omitempty"`
To string `json:"to"`
// Added says the issue had no item on the board: one was added before
// the move. Team is the Team the item was given, board.team, "" when
// it had one or the board names none.
Added bool `json:"added,omitempty"`
Team string `json:"team,omitempty"`
// Go is the go the move is, an epic moved to the epic gate's go
// status; nil for any other move.
Go *Go `json:"go,omitempty"`
// Board is the project the item moved on when it is not the configured
// board: the project of the issue's repository's own owner
// (owner/number); "" for the configured board.
Board string `json:"board,omitempty"`
}
Moved is a move of an item to a status.
type Partial ¶ added in v0.129.0
type Partial struct{ Errors []GraphQLError }
Partial is an answer with errors beside its data: the data is decoded, and every field an error's path names is missing from it, never absent.
type Place ¶ added in v0.126.0
Place is where Rank puts an item: at the top of the board, or right before or right after the item of another issue, one of the three.
type Plan ¶ added in v0.127.0
type Plan struct {
Ref string `json:"ref"`
URL string `json:"url"`
Title string `json:"title"`
// State is draft, open or merged; Head the head commit.
State string `json:"state"`
Head string `json:"head"`
Private bool `json:"private"`
// contains filtered or unexported fields
}
Plan is an epic's plan: the open or merged pull request of a plans repository whose description names the epic.
type Priorities ¶ added in v0.131.0
type Priorities []RankedEpic
Priorities is the priority list, by rank.
func (Priorities) Ranks ¶ added in v0.131.0
func (p Priorities) Ranks() Ranks
Ranks is the priority list as each epic's rank by its lower-cased ref.
type Prioritized ¶ added in v0.131.0
type Prioritized struct {
Ref string `json:"ref"`
From int `json:"from,omitempty"`
To int `json:"to,omitempty"`
List Priorities `json:"list"`
// Added says the epic had no item on the board, Team the Team it was
// given; as in Moved.
Added bool `json:"added,omitempty"`
Team string `json:"team,omitempty"`
}
Prioritized is a change of the priority list: the epic, its rank before and after (0 for none), and the list as it is now.
type Ranked ¶ added in v0.126.0
type Ranked struct {
Ref string `json:"ref"`
// Above and Below are the item's new neighbours that the move itself
// names: the item it went after or before, and for the top the item
// now below it; "" for one no request read. A neighbour that is no
// issue is "a draft".
Above string `json:"above,omitempty"`
Below string `json:"below,omitempty"`
Top bool `json:"top,omitempty"`
// Added and Team are as in Moved: the issue had no item on the board.
Added bool `json:"added,omitempty"`
Team string `json:"team,omitempty"`
}
Ranked is a move of an item to a place on the board.
type RankedEpic ¶ added in v0.131.0
type RankedEpic struct {
Rank int `json:"rank"`
Ref string `json:"ref"`
URL string `json:"url"`
Title string `json:"title"`
Status string `json:"status,omitempty"`
// contains filtered or unexported fields
}
RankedEpic is an epic of the priority list.
type Ranks ¶ added in v0.131.0
Ranks are the epics' ranks by their lower-cased ref.
type Refusal ¶
type Refusal struct{ Reason string }
Refusal is a move the board's values or items do not allow.
type Snapshot ¶
type Snapshot struct {
// Order is the configured order, its Status and Kind values the
// board's canonical names.
Order []config.BoardStep
// Items are the open board items in the board's order.
Items []Item
// Search holds each search step's issues by its index in Order.
Search map[int][]Item
// Statuses are the board's Status values, in the board's order.
Statuses []string
// Gate is the epic gate; Plans the plans of the epics it watches by
// their lower-cased ref.
Gate Gate
Plans map[string]*Plan
// Missing names what GitHub answered with an error and no item's
// Missing holds ("<path>: <message>"), a search step's issues for one.
Missing []string
}
Snapshot is what one read of the board returned.
type Thread ¶ added in v0.142.0
type Thread struct {
About string `json:"about"`
Ref string `json:"thread"`
Via string `json:"via,omitempty"`
// contains filtered or unexported fields
}
Thread is where an answer about an issue or pull request is recorded: Ref itself in a private repository; else the first private plan pull request naming it or an epic above it, then the nearest epic above it in a private repository. Via says why Ref is not About, "" when it is.