Documentation
¶
Index ¶
- func ApplyTrackerStatus(ctx context.Context, t tracker.Tracker, errW io.Writer, ...)
- func IssueSlugForBranch(ctx context.Context, s *store.Store, branchName string) (string, error)
- func MarkMergedFromRef(ctx context.Context, s *store.Store, client *git.Client, b store.BranchRow, ...)
- func ReconcileMergedFromRefs(ctx context.Context, s *store.Store, client *git.Client)
- func ResolveParentBranch(ctx context.Context, s ParentStore, c ParentClient, issueSlug, cfgBase string) (string, error)
- func RunIssueStart(ctx context.Context, deps StartDeps, prompter StartPrompter) error
- type BaseBrancher
- type BranchClient
- type HuhStartPrompter
- func (p *HuhStartPrompter) ConfirmCreateBranch(ctx context.Context, message string) (bool, error)
- func (p *HuhStartPrompter) ConfirmCreateWorktree(ctx context.Context, message string) (bool, error)
- func (p *HuhStartPrompter) NotifyTrackerError(ctx context.Context, message string) error
- func (p *HuhStartPrompter) PickBaseBranch(ctx context.Context, defaultBase string, branches []string) (string, error)
- func (p *HuhStartPrompter) PickIssueFromTracker(ctx context.Context, issues []tracker.Issue, allowedTypes []string) (*issuepkg.Issue, error)
- func (p *HuhStartPrompter) PickIssueFromUser(ctx context.Context, allowedTypes []string) (*issuepkg.Issue, error)
- func (p *HuhStartPrompter) PickTrackerStatus(ctx context.Context, issueID, trackerType string, statuses []string) (string, error)
- func (p *HuhStartPrompter) PickUseTracker(ctx context.Context, trackerType string, trackerFirst bool) (bool, error)
- func (p *HuhStartPrompter) PickUseWorktree(ctx context.Context) (bool, error)
- func (p *HuhStartPrompter) ResolveBranchConflict(ctx context.Context, client BranchClient, b *branch.Branch, ...) (*branch.Branch, error)
- type ParentClient
- type ParentStore
- type PendingReview
- type Prompter
- type StartDeps
- type StartPrompter
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyTrackerStatus ¶
func ApplyTrackerStatus( ctx context.Context, t tracker.Tracker, errW io.Writer, issueID, trackerType string, pick func(ctx context.Context, issueID, trackerType string, statuses []string) (string, error), )
ApplyTrackerStatus fetches tracker statuses, prompts the user to pick one, and applies it. All errors are non-fatal warnings. A nil tracker is a no-op.
func IssueSlugForBranch ¶ added in v0.13.1
IssueSlugForBranch returns the issue slug owning branchName in the store, or "" when the branch is not tracked.
func MarkMergedFromRef ¶ added in v0.12.0
func MarkMergedFromRef(ctx context.Context, s *store.Store, client *git.Client, b store.BranchRow, now time.Time)
MarkMergedFromRef reads branch b's refs/zf/branches/<slug> ref and, when it carries Merged=true, marks the branch and its issue merged in the local store. now is shared across a reconcile pass so a batch of reconciled branches share one timestamp. Errors are non-fatal (best-effort cache sync).
func ReconcileMergedFromRefs ¶ added in v0.12.0
ReconcileMergedFromRefs fetches refs/zf/branches/* (best-effort) and marks any in-progress branch whose ref has Merged=true as merged in the local store.
The branch ref is the cross-machine source of truth: the clone that closes a branch stamps Merged=true on its ref and pushes it (see the close flow's updateClosedStatus). Other clones' local stores lag until reconciled, so any picker that lists in-progress branches straight from the store (close, review sync, review request) would otherwise offer a branch that was already closed elsewhere. Call this before listing in-progress branches for such a picker.
All errors are non-fatal: the fetch is best-effort (offline ⇒ local refs only) and a failed status update just leaves the branch in the list, which is the pre-reconcile behaviour.
func ResolveParentBranch ¶ added in v0.12.0
func ResolveParentBranch(ctx context.Context, s ParentStore, c ParentClient, issueSlug, cfgBase string) (string, error)
ResolveParentBranch computes the merge target for an issue: the configured base (cfgBase, or DefaultBaseBranch when empty), redirected to the parent integration branch when issueSlug has a parent.
The store is checked first for the parent relation; on a cross-machine clone where the store has no record, the refs/zf/branches/<slug> git ref is the fallback (FetchBranchRefs runs best-effort first so a later read sees fresh refs). The parent's branch *name* is resolved from the store, then from the parent's own branch ref. Extracted verbatim from cmd/issue/close.go's resolveDefaultBase so close and commit share one implementation.
func RunIssueStart ¶
func RunIssueStart(ctx context.Context, deps StartDeps, prompter StartPrompter) error
RunIssueStart is the prompter-driven core of the issue-start flow. Called from cmd/issue's startRunE (production, via a HuhStartPrompter) and from cmd/branch's newRunE (also production). Tests call it directly with a scriptedStartPrompter. TrackerFirst is carried inside deps.Flags.
Returns nil on two non-error exits: (1) pickIssue returns (nil, nil) — only possible when a test prompter does so; production prompters always return a non-nil issue or an error — and (2) prompter.ResolveBranchConflict returns (nil, nil) to signal the operator aborted or checked out an existing branch.
Types ¶
type BaseBrancher ¶ added in v0.12.0
type BaseBrancher interface {
LocalBranchNames() ([]string, error)
RemoteBranchNames() ([]string, error)
}
BaseBrancher is the slice of *git.Client that baseBranchCandidates needs: the local and remote-tracking branch listers. Declared as a tiny interface so candidate assembly is unit-testable without a real repository.
type BranchClient ¶
type BranchClient interface {
BranchExists(name string) (bool, error)
Checkout(ctx context.Context, branch string) error
IO() *pkg.IO
}
BranchClient is the subset of *git.Client that ResolveBranchConflict needs. Declared as a small interface so tests can substitute a fake without constructing a full *git.Client.
type HuhStartPrompter ¶
type HuhStartPrompter struct{}
HuhStartPrompter is the production StartPrompter. It opens real huh forms. Constructed once per `issue start` (or `branch new`) invocation.
func NewHuhStartPrompter ¶
func NewHuhStartPrompter() *HuhStartPrompter
NewHuhStartPrompter constructs the production huh-driven StartPrompter.
func (*HuhStartPrompter) ConfirmCreateBranch ¶
func (*HuhStartPrompter) ConfirmCreateWorktree ¶
func (*HuhStartPrompter) NotifyTrackerError ¶
func (p *HuhStartPrompter) NotifyTrackerError(ctx context.Context, message string) error
func (*HuhStartPrompter) PickBaseBranch ¶
func (*HuhStartPrompter) PickIssueFromTracker ¶
func (*HuhStartPrompter) PickIssueFromUser ¶
func (*HuhStartPrompter) PickTrackerStatus ¶
func (*HuhStartPrompter) PickUseTracker ¶
func (*HuhStartPrompter) PickUseWorktree ¶
func (p *HuhStartPrompter) PickUseWorktree(ctx context.Context) (bool, error)
func (*HuhStartPrompter) ResolveBranchConflict ¶
func (p *HuhStartPrompter) ResolveBranchConflict(ctx context.Context, client BranchClient, b *branch.Branch, picked *issuepkg.Issue) (*branch.Branch, error)
ResolveBranchConflict is the production conflict-resolution loop. It is the body of the pre-refactor cmd/issue/conflict.go:resolveBranchConflict lifted verbatim onto the prompter so tests can substitute a scripted result.
type ParentClient ¶ added in v0.12.0
type ParentClient interface {
DefaultBaseBranch() (string, error)
FetchBranchRefs(ctx context.Context) error
ReadBranchRef(ctx context.Context, issueSlug string) (*git.BranchRef, error)
}
ParentClient is the slice of *git.Client that ResolveParentBranch needs.
type ParentStore ¶ added in v0.12.0
type ParentStore interface {
GetParentIssue(ctx context.Context, childSlug string) (string, error)
ListBranches(ctx context.Context, status store.BranchStatus) ([]store.BranchRow, error)
}
ParentStore is the slice of *store.Store that ResolveParentBranch needs.
type PendingReview ¶ added in v0.13.1
type PendingReview struct {
EffectiveRef string // "42@review" or "origin/42@review"
Commits int // commits ahead of the feature branch
Status store.ReviewStatus // approved | changes_requested
}
PendingReview describes reviewer commits on <slug>@review that a reviewer decision (approved / changes_requested) says the developer must incorporate into the feature branch.
func PendingReviewCommits ¶ added in v0.13.1
func PendingReviewCommits(ctx context.Context, client *git.Client, slug, featureBranch string) (*PendingReview, error)
PendingReviewCommits reports reviewer commits awaiting incorporation for slug's featureBranch, or nil when nothing is pending. It reads only local refs — no network — so it is cheap enough for a pre-commit hook and works offline. The guard is armed only by a decided review ref: in_review means the reviewer hasn't decided, and a stale review branch with no ref (e.g. after a close) never trips it.
func PendingReviewForHEAD ¶ added in v0.13.1
func PendingReviewForHEAD(ctx context.Context, client *git.Client, s *store.Store) (*PendingReview, string, error)
PendingReviewForHEAD applies the commit-guard exemptions and returns the pending review for the currently checked-out branch, plus that branch name. It returns (nil, "", nil) whenever the guard must not trip: detached HEAD, an @review branch, a merge in progress (concluding a merge is exactly how incorporation happens), an untracked branch, or nothing pending.
type Prompter ¶ added in v0.11.3
type Prompter interface {
// PickIssueFromUser opens the manual issue-input form (issue ID, subject, type).
PickIssueFromUser(ctx context.Context, allowedTypes []string) (*issuepkg.Issue, error)
// PickIssueFromTracker opens the picker over a pre-fetched issues list.
PickIssueFromTracker(ctx context.Context, issues []tracker.Issue, allowedTypes []string) (*issuepkg.Issue, error)
// NotifyTrackerError shows a one-line error note when the tracker errors
// out or returns no open issues. Returning a non-nil error aborts the flow.
NotifyTrackerError(ctx context.Context, message string) error
}
Prompter resolves the issue-input forms: manual entry, the tracker picker, and the tracker-error note. It is the slice of StartPrompter that getFromUser and getFromTracker drive, kept as its own interface so those helpers can be unit-tested without the rest of the start flow. It lives here in the application layer (not the issue domain package) because every method is a UI-form concern.
type StartDeps ¶
type StartDeps struct {
Client *git.Client
Cfg *config.AppConfig
Tracker tracker.Tracker // nil when cfg.IssueTracker.Type == ""
Flags issue.IssueStartFlags
BaseBranchOverride string // set by PickBaseBranch; skips store re-query in prepareBranch
}
StartDeps bundles the long-lived dependencies the start flow needs. Production code builds it via BuildStartDeps; tests inject directly. Exported because cmd/branch/branch.go's newRunE constructs one too.
func BuildStartDeps ¶
func BuildStartDeps( cmd *cobra.Command, cfg *config.AppConfig, flags issue.IssueStartFlags, ) (StartDeps, error)
BuildStartDeps constructs the production StartDeps from a cobra command. Returns an error if the repo cannot be opened or if a configured tracker (cfg.IssueTracker.Type != "") fails to initialise. When cfg.IssueTracker.Type == "" the returned deps.Tracker is nil and RunIssueStart falls through to the manual issue-input flow.
type StartPrompter ¶
type StartPrompter interface {
// Prompter contributes the three issue-input methods used by
// getFromUser and getFromTracker.
Prompter
// PickUseTracker drives the "fetch from tracker?" toggle. Called only when
// cfg.IssueTracker.Type != "". trackerFirst controls the pre-selected
// option (true for `issue start`, false for `branch new`).
PickUseTracker(ctx context.Context, trackerType string, trackerFirst bool) (use bool, err error)
// PickUseWorktree drives the "worktree vs plain branch?" toggle. Called
// only when cfg.Branch.UseWorktree == nil.
PickUseWorktree(ctx context.Context) (use bool, err error)
// PickBaseBranch presents a picker over all local git branches.
// defaultBase is pre-selected. Called only when --parent was not explicitly
// provided and the repo has more than one local branch.
PickBaseBranch(ctx context.Context, defaultBase string, branches []string) (baseBranch string, err error)
// ConfirmCreateBranch gates client.CreateBranch. message is the full
// human-readable "Create branch %q based on %q?" string.
ConfirmCreateBranch(ctx context.Context, message string) (confirmed bool, err error)
// ConfirmCreateWorktree gates client.CreateWorktree. message is the full
// "Create worktree %q at %q based on %q?" string.
ConfirmCreateWorktree(ctx context.Context, message string) (confirmed bool, err error)
// PickTrackerStatus drives the tracker status-picker form. An empty return
// signals "no selection" — the caller decides whether to treat that as
// skip or abort.
PickTrackerStatus(ctx context.Context, issueID, trackerType string, statuses []string) (string, error)
// ResolveBranchConflict owns the conflict-resolution loop. It checks
// whether b's name already exists locally and, if so, drives the operator
// through a picker (checkout / variant / abort). Returns (b, nil) on the
// clean no-collision path. Returns (nil, nil) to signal "stop here, do
// not create or persist" (operator chose abort or checked out the
// existing branch). Returns (nil, err) on input or git failures.
ResolveBranchConflict(ctx context.Context, client BranchClient, b *branch.Branch, picked *issuepkg.Issue) (*branch.Branch, error)
}
StartPrompter resolves every user-facing decision in the issue-start flow. The production implementation drives huh forms; the test implementation in start_prompter_test.go returns canned values.
Methods correspond to the huh forms in the pre-refactor flow. The order below mirrors the order calls happen in RunIssueStart. Note: PickIssueFromTracker covers a single form that lets the operator pick both the issue and its branch type, so the mapping is interface→form, not 1:1 for every UI element.