Documentation
¶
Overview ¶
Package transition is the single owner of the gadak transition write (CLI, including `gadak close`, and REST). Both surfaces call Apply so identifier resolution, required screen fields, resolution lookup, field-alias remap, category-token idempotency, and the origin write cannot exist on one path and not the other.
Refused errors carry catalogue data only. The CLI formats flag names; REST maps them to HTTP 400. This package does not name CLI flags.
Mirror refresh is not here: it is the write-through tail shared by every write verb (CLI mutate / server mutate), not a property of this verb.
Index ¶
- func DuplicateDestinations(list []jira.Transition) [][]jira.Transition
- func FormatDuplicateDestinations(list []jira.Transition) string
- func FormatNamedIDs(list []jira.NamedID) string
- func FormatTransition(t jira.Transition) string
- func IsRefused(err error) bool
- func JoinTransitions(list []jira.Transition) string
- func MirrorStatusUse(ctx context.Context, db *store.DB, key string) func(string) int
- func PickTransition(key, want string, list []jira.Transition) (string, error)
- func PickTransitionWith(key, want string, list []jira.Transition, opt PickOptions) (string, error)
- func Preview(ctx context.Context, o Origin, key, target string, ...) (id string, changed bool, err error)
- func ReachableCategories(list []jira.Transition) []string
- func StatusCategoryToken(s string) (string, bool)
- type AmbiguousTransitionError
- type Origin
- type PickOptions
- type Refused
- type Request
- type RequiredFieldsError
- type Result
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DuplicateDestinations ¶ added in v0.22.0
func DuplicateDestinations(list []jira.Transition) [][]jira.Transition
DuplicateDestinations reports the groups of transitions whose destination status shares a display name and a category — the shape that makes a category token fold (GDK-1356), and the shape a reader staring at two identical rows in `gadak transition KEY` needs named rather than inferred. Groups are in payload order and always hold two or more members; a workflow with no duplicates returns nothing.
func FormatDuplicateDestinations ¶ added in v0.22.0
func FormatDuplicateDestinations(list []jira.Transition) string
FormatDuplicateDestinations renders DuplicateDestinations as one line per group, or "" when there are none.
func FormatNamedIDs ¶
FormatNamedIDs joins a catalog's names (ids where the name is empty) with ", " — the "available: …" list in resolution errors. Single owner; the `gadak agent` / `gadak edit` surfaces import it (GDK-619).
func FormatTransition ¶ added in v0.22.0
func FormatTransition(t jira.Transition) string
func IsRefused ¶
IsRefused reports whether err is a caller-side refusal (bad identifier, missing required field, unknown resolution). Origin errors are not.
func JoinTransitions ¶ added in v0.22.0
func JoinTransitions(list []jira.Transition) string
func MirrorStatusUse ¶ added in v0.22.0
MirrorStatusUse answers "how many issues does this project actually hold in that status", from the mirror, which is local and free. It is the tiebreak between two destination statuses that display the same name in the same category (GDK-1356): the gdk workspace carries an In Progress the 2026-09-01 cutover left behind with zero issues in it, beside the In Progress the board shows. nil when there is no mirror or no project key to scope by — the pick then falls back to payload order.
It lives in this package, not next to the CLI that first passed it (GDK-1521), because all three write surfaces need the identical answer: `gadak transition`, the REST transition write, and `gadak claim`'s Cloud fallback. internal/store does not import internal/transition, so the dependency closes without a cycle.
func PickTransition ¶ added in v0.22.0
func PickTransition(key, want string, list []jira.Transition) (string, error)
PickTransition resolves want with no mirror and no current-status read. See PickTransitionWith for the resolution order.
func PickTransitionWith ¶ added in v0.22.0
func PickTransitionWith(key, want string, list []jira.Transition, opt PickOptions) (string, error)
PickTransitionWith resolves want against the issue's available transitions. Order: transition id, target status id, transition name / target status name, then category tokens (new|inprogress|done). Two *distinguishable* landings in the same category refuse rather than picking the first; two landings the reader cannot tell apart — same destination status name, same category — are one landing and fold (GDK-1356). A token that is one transition's id and a different transition's to.id is also refused.
func Preview ¶
func Preview(ctx context.Context, o Origin, key, target string, statusUse func(statusID string) int) (id string, changed bool, err error)
Preview answers what Apply would do without writing: the resolved transition id when one would fire (changed=true), or the category no-op (changed=false, empty id). It exists so a dry-run cannot drift from the real write — both run resolveTransition. A pick miss that is not a no-op returns the pick error. statusUse is Request.StatusUse: a dry run that skipped it could name a different transition id than the write, which is the one thing a dry run must not do.
func ReachableCategories ¶ added in v0.22.0
func ReachableCategories(list []jira.Transition) []string
func StatusCategoryToken ¶ added in v0.22.0
StatusCategoryToken accepts only the three values data-model.md documents. Category and jql.mapStatusCategory both fold aliases (todo, indeterminate) onto those values; applying either to the user token would reopen the localization trap this command is closing. Apply's category no-op uses this same function so a token PickTransition would refuse cannot no-op.
Types ¶
type AmbiguousTransitionError ¶ added in v0.22.0
type AmbiguousTransitionError struct {
Key string
Want string
Candidates []jira.Transition
// Folded are the candidates a Candidate stands in for: same destination
// name, same category, so naming one of them could not have told the two
// readings apart (GDK-1356). Empty unless a category token folded. They
// are still reachable by transition id or target status id, and the
// message says so — a reader who saw them in `gadak transition KEY` must
// not conclude gadak stopped seeing them.
Folded []jira.Transition
}
AmbiguousTransitionError is the refusal when want lands on more than one transition (GDK-1174: a board with two in-progress statuses makes every bare `gadak claim` land here). The message is unchanged from the old fmt.Errorf; the type exists so a caller that owns a disambiguation flag can name its recourse — this package still never names CLI flags.
func (*AmbiguousTransitionError) Error ¶ added in v0.22.0
func (e *AmbiguousTransitionError) Error() string
type Origin ¶
type Origin interface {
Transitions(ctx context.Context, key string) ([]jira.Transition, error)
Transition(ctx context.Context, key, transitionID string, fields map[string]any, comment json.RawMessage) error
}
Origin is the origin verbs Apply needs. origin.Writer satisfies it.
type PickOptions ¶ added in v0.22.0
type PickOptions struct {
// CurrentStatusID is the issue's status id at resolution time. Inside a
// group of same-named destinations it rules that member out: "put me in
// In Progress" cannot mean the In Progress the issue already sits in.
// A lone candidate is never ruled out this way — dropping it would let
// a category token mean some *other* status of that category, which is a
// worse answer than the self-loop the workflow actually offers.
CurrentStatusID string
// StatusUse reports how many issues the local mirror holds in statusID.
// It breaks the tie inside a folded group only: of two statuses that
// display the same name in the same category, the one the project is
// actually using is the one the board shows and the reader means. It is
// consulted at most once per member of a group larger than one, so the
// common path never calls it. nil leaves payload order deciding.
StatusUse func(statusID string) int
}
PickOptions carries the two facts the transitions payload does not hold. Both are optional: the zero value is name folding on payload order, which is what a caller with no mirror and no status read gets.
type Refused ¶
type Refused struct {
Msg string
// Err is the refusal this was built from, when one exists — kept so a
// caller can still match the concrete kind (AmbiguousTransitionError
// under gadak claim, GDK-1174) through the type adapters map on.
Err error
}
Refused is a caller-side refusal: the origin was not written. Adapters map this to a 400 / CLI message; origin errors pass through unchanged.
type Request ¶
type Request struct {
Key string
Target string
Resolution string
Fields map[string]any
Comment string
// StatusUse is an optional read of the local mirror: how many issues sit
// in statusID right now. It is consulted only to break a tie between two
// destination statuses that display the same name in the same category
// (GDK-1356) — never to decide what Target means. nil is fine, and is
// what a caller without a mirror handle passes.
StatusUse func(statusID string) int
}
Request is one transition write. Target is whatever PickTransition accepts: transition id, target status id, transition/status name, or a status category token (new|inprogress|done). Fields are already parsed (CLI --field, REST JSON); aliases are remapped here. Resolution is a name or id; a name is resolved from the transition's allowedValues, else the origin's resolution catalog.
type RequiredFieldsError ¶
RequiredFieldsError is a Refused whose screen lists required fields the request did not supply. CLI appends flag names; REST uses Error as-is.
func (*RequiredFieldsError) Error ¶
func (e *RequiredFieldsError) Error() string
type Result ¶
type Result struct {
Changed bool `json:"changed"`
}
Result is a successful Apply. Changed is false when Target was a category token and the origin already reports that category: no POST (and no comment). A named or id miss is still an error, not a no-op.