merge

package
v0.17.15 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package merge provides functionality for merging stacked pull requests.

Index

Constants

View Source
const (
	// DefaultCITimeout is the default timeout for waiting on CI checks
	DefaultCITimeout = 10 * time.Minute
	// DefaultCIPollInterval is the default interval between CI status checks
	DefaultCIPollInterval = 15 * time.Second
	// CIRegistrationDelay is the delay to allow CI checks to register after push
	CIRegistrationDelay = 5 * time.Second
)

Timing constants for CI waiting

Variables

This section is empty.

Functions

func Action

func Action(ctx *app.Context, opts Options) error

Action performs the merge operation using the plan/execute pattern

func AllBranchesAreLeaves

func AllBranchesAreLeaves(graph *engine.StackGraph, branches []BranchMergeInfo) bool

AllBranchesAreLeaves checks if all branches in the plan have no children in the stack graph.

Why this matters: Only leaf branches (those with no children) can be merged individually without affecting other branches. Merging a non-leaf would orphan its children or require restacking them, making individual merge inappropriate. This check enables offering the "merge individually" option when all selected branches are independent leaves.

Note: Branches not found in the graph (nil node) are treated as non-leaves and cause the function to return false. This is a fail-safe behavior - if we can't verify a branch's structure, we don't allow individual merging.

func AnalyzeMidStackScope

func AnalyzeMidStackScope(eng engine.Engine, plan *Plan, currentScope string) []string

AnalyzeMidStackScope checks if user is mid-stack in a scope and returns any upstack branches that are in the same scope (won't be merged).

func AnyPRHasChecks

func AnyPRHasChecks(branches []BranchMergeInfo) bool

AnyPRHasChecks returns true if any of the given branches have CI checks configured

func CreateMergePlan

func CreateMergePlan(ctx context.Context, eng mergePlanEngine, splog output.Output, githubClient github.Client, opts CreatePlanOptions) (*Plan, *PlanValidation, error)

CreateMergePlan analyzes the current state and builds a merge plan. This is a convenience wrapper that calls CollectMergeBranches + BuildMergePlan.

func Execute

func Execute(ctx *app.Context, eng mergeExecuteEngine, opts ExecuteOptions) error

Execute executes a validated merge plan step by step

func ExecuteInWorktree

func ExecuteInWorktree(ctx *app.Context, eng mergeExecuteEngine, opts ExecuteOptions, scope string, targetBranch string) (err error)

ExecuteInWorktree executes the merge plan in a temporary worktree

func FormatMergePlan

func FormatMergePlan(plan *Plan, validation *PlanValidation) string

FormatMergePlan returns a human-readable representation of a merge plan

func FormatStackLabel

func FormatStackLabel(stack MultiStackInfo) string

FormatStackLabel creates a display label for a stack

func FormatValidationError

func FormatValidationError(errors, warnings []string) error

FormatValidationError creates a detailed error message including validation errors and warnings.

func FormatValidationSection

func FormatValidationSection(result *strings.Builder, validation *PlanValidation)

FormatValidationSection writes validation errors, warnings, and info to the builder. Used by all plan format functions to avoid duplication.

func GenerateMultiStackBranchName

func GenerateMultiStackBranchName() string

GenerateMultiStackBranchName creates a unique branch name for the multi-stack PR

func GetAvailableScopes

func GetAvailableScopes(eng engine.Engine) []string

GetAvailableScopes returns all unique non-empty scopes in the repository

func GetMergeMethod

func GetMergeMethod(ctx *app.Context, githubClient github.Client) (github.MergeMethod, error)

GetMergeMethod returns the merge method to use for PR merges. If not configured, it prompts the user to select one and saves it to config.

func HandlePostMerge

func HandlePostMerge(ctx *app.Context, handler InteractiveHandler) error

HandlePostMerge handles the post-merge follow-up workflow.

func IsSingleBranchLeafMerge

func IsSingleBranchLeafMerge(plan *Plan, graph *engine.StackGraph) bool

IsSingleBranchLeafMerge returns true if this is a simple merge of a single leaf branch (no children, no upstack work needed).

Why this matters: Single leaf branches with no upstack work represent the simplest merge case. We can offer a streamlined confirmation UX (just "Proceed?") instead of showing the full plan, since there are no complex steps or dependencies to review.

func RunWizard

func RunWizard(ctx *app.Context, handler InteractiveHandler, opts WizardOptions) error

RunWizard executes the interactive merge wizard. It guides the user through selecting what to merge, the strategy, and then executes the merge.

Types

type BranchMergeInfo

type BranchMergeInfo struct {
	BranchName    string
	PRNumber      int
	PRURL         string
	IsDraft       bool
	ChecksStatus  ChecksStatus
	MatchesRemote bool
}

BranchMergeInfo contains info about a branch to be merged

func (BranchMergeInfo) HasChecks

func (b BranchMergeInfo) HasChecks() bool

HasChecks returns true if the branch has CI checks configured

type CIWaiter

type CIWaiter struct {
	// contains filtered or unexported fields
}

CIWaiter handles waiting for CI checks to pass on GitHub PRs. It extracts the common CI polling logic used by both consolidation and step execution.

func NewCIWaiter

func NewCIWaiter(opts CIWaiterOptions) *CIWaiter

NewCIWaiter creates a new CIWaiter with the given options

func (*CIWaiter) SetProgressHandler

func (w *CIWaiter) SetProgressHandler(handler EventHandler, stepIndex int)

SetProgressHandler sets the handler and step index for progress reporting

func (*CIWaiter) WaitAndMerge

func (w *CIWaiter) WaitAndMerge(ctx context.Context, branchName string, pr *github.PullRequestInfo, expectChecks bool, mergeOpts github.MergePROptions) error

WaitAndMerge waits for CI checks to pass and then merges the PR. This is used for consolidation PRs that should be auto-merged.

func (*CIWaiter) WaitForChecks

func (w *CIWaiter) WaitForChecks(ctx context.Context, branchName string, prNumber int, expectChecks bool) (*WaitResult, error)

WaitForChecks waits for CI checks to pass on a branch. Returns an error if checks fail, timeout, or context is canceled.

type CIWaiterOptions

type CIWaiterOptions struct {
	Client       github.Client
	Output       output.Output
	Timeout      time.Duration // Default: 10 minutes
	PollInterval time.Duration // Default: 15 seconds
}

CIWaiterOptions configures a CIWaiter

type ChecksStatus

type ChecksStatus string

ChecksStatus represents the CI check status for a PR

const (
	// ChecksPassing indicates all checks passed
	ChecksPassing ChecksStatus = "PASSING"
	// ChecksFailing indicates at least one check failed
	ChecksFailing ChecksStatus = "FAILING"
	// ChecksPending indicates checks are still running
	ChecksPending ChecksStatus = "PENDING"
	// ChecksNone indicates no checks are configured
	ChecksNone ChecksStatus = "NONE"
)

type CollectedBranches

type CollectedBranches struct {
	BranchesToMerge []BranchMergeInfo
	UpstackBranches []string
	CurrentBranch   string
	Validation      *PlanValidation
}

CollectedBranches holds the intermediate result of branch collection. This allows the wizard to collect branches once, then build plans with different strategies.

func CollectMergeBranches

func CollectMergeBranches(ctx context.Context, eng mergePlanEngine, splog output.Output, githubClient github.Client, opts CreatePlanOptions) (*CollectedBranches, error)

CollectMergeBranches gathers branches, metadata, CI status, and validation without building strategy-specific steps. This is the expensive part that calls GitHub APIs and should only run once per wizard session.

type ConsolidateMergeExecutor

type ConsolidateMergeExecutor struct {
	// contains filtered or unexported fields
}

ConsolidateMergeExecutor handles stack consolidation merging

func NewConsolidateMergeExecutor

func NewConsolidateMergeExecutor(plan *Plan, engine mergeExecuteEngine, ctx *app.Context) *ConsolidateMergeExecutor

NewConsolidateMergeExecutor creates a new consolidation executor

func (*ConsolidateMergeExecutor) Execute

Execute performs stack consolidation merging

func (*ConsolidateMergeExecutor) SetProgressHandler

func (c *ConsolidateMergeExecutor) SetProgressHandler(handler EventHandler, stepIndex int)

SetProgressHandler sets the progress handler and step index for reporting

type ConsolidationResult

type ConsolidationResult struct {
	BranchName string
	PRNumber   int
	PRURL      string
}

ConsolidationResult contains information about a completed consolidation

type CreatePlanOptions

type CreatePlanOptions struct {
	Strategy     Strategy
	Force        bool
	Scope        string
	TargetBranch string // Optional branch to merge from (instead of current)
	Wait         bool   // Whether to wait for CI/merge (applies to consolidate strategy)
}

CreatePlanOptions contains options for creating a merge plan

type Event

type Event struct {
	Phase     Phase
	Type      EventType
	StepIndex int
	Step      *PlanStep
	Message   string
	Error     error

	// Waiting-specific fields
	Elapsed time.Duration
	Timeout time.Duration
	Checks  []github.CheckDetail

	// Estimate fields
	EstimatedDuration time.Duration
}

Event represents a merge progress event

type EventHandler

type EventHandler interface {
	// Start is called when the merge plan is ready to execute.
	// The plan contains all steps that will be executed.
	Start(plan *Plan)

	// EmitEvent sends a progress event to the handler.
	// Called for each step transition (started, completed, failed, waiting).
	// May be called concurrently from multiple goroutines.
	EmitEvent(event Event)

	// Complete is called when the merge operation is finished.
	// Result contains success status and any consolidation result.
	Complete(result *Result)

	// Cleanup ensures terminal state is restored.
	// Should be called via defer after creating the handler.
	// No-op for non-TTY handlers.
	Cleanup()
}

EventHandler is the interface for reporting merge progress using events. This is the recommended interface for new handler implementations.

Lifecycle:

  1. Start() is called once when the merge plan is ready
  2. EmitEvent() is called for each step (started, completed, failed, waiting)
  3. Complete() is called once when the operation finishes
  4. Cleanup() should be called via defer to restore terminal state

Thread safety: All methods may be called from different goroutines. Implementations should handle synchronization internally.

type EventType

type EventType string

EventType represents the type of merge event

const (
	EventStarted   EventType = "started"
	EventProgress  EventType = "progress"
	EventCompleted EventType = "completed"
	EventFailed    EventType = "failed"
	EventWaiting   EventType = "waiting"
	EventSkipped   EventType = "skipped"
)

Event type constants

type ExecuteOptions

type ExecuteOptions struct {
	Plan                    *Plan
	Strategy                Strategy
	Force                   bool
	Wait                    bool                       // Whether to wait for CI/merge (applies to consolidate)
	Handler                 EventHandler               // Optional progress handler
	UndoStackDepth          int                        // Maximum undo stack depth (from config)
	ConsolidationResultFunc func(*ConsolidationResult) // Callback for consolidation results
	MergeMethod             github.MergeMethod         // Optional: override merge method (empty = auto-detect/prompt)
}

ExecuteOptions contains options for executing a merge plan

type IndividualMergeStatus

type IndividualMergeStatus struct {
	CanMerge       bool            // True if all PRs can be merged individually
	MergeableState map[string]bool // Per-branch mergeable state (true = mergeable)
	BlockingReason string          // Reason why individual merge is blocked (if any)
}

IndividualMergeStatus contains the result of checking if individual merge is possible

func CanMergeIndividually

func CanMergeIndividually(ctx context.Context, gitRunner git.Runner, githubClient github.Client, graph *engine.StackGraph, branches []BranchMergeInfo) (*IndividualMergeStatus, error)

CanMergeIndividually checks if all PRs can be merged individually by verifying: 1. All branches are leaf branches (no children) 2. All PRs have GitHub mergeable state = MERGEABLE (no conflicts with trunk)

Returns the status including per-branch mergeable states for display purposes. Returns error if GitHub API call fails; check CanMerge field and BlockingReason for results.

type InteractiveHandler

type InteractiveHandler interface {
	EventHandler

	// IsInteractive returns true if this handler supports interactive prompts.
	// Non-interactive handlers (e.g., SimpleMergeEventHandler) return false,
	// and their prompt methods will return errors.
	// Check this before calling prompt methods to provide better error messages.
	IsInteractive() bool

	// PromptMergeType asks user what to merge (this/scope/stacks).
	// Called at the start of the wizard when no merge target is pre-selected.
	// canMergeThisBranch indicates if "This branch" is a valid option (false on trunk or empty worktree).
	// Returns ErrCanceled if user cancels.
	PromptMergeType(canMergeThisBranch bool, availableScopes []string, availableStacks []MultiStackInfo) (MergeType, error)

	// PromptScope asks user to select a scope from available options.
	// Called when user selects MergeTypeScope.
	// Returns ErrCanceled if user cancels.
	PromptScope(availableScopes []string) (string, error)

	// PromptStacks asks user to select stacks (multi-select with ordering).
	// Returns selected stack root names in priority order.
	// Called when user selects MergeTypeStacks.
	// Returns ErrCanceled if user cancels.
	PromptStacks(availableStacks []MultiStackInfo) ([]string, error)

	// PromptStrategy asks user to select merge strategy.
	// plan provides context (branch count, etc.) for display.
	// recommended is the suggested default based on stack size.
	// Returns ErrCanceled if user cancels.
	PromptStrategy(plan *Plan, recommended Strategy) (StrategyChoice, error)

	// PromptConfirm asks user to confirm an action.
	// Returns ErrCanceled if user cancels.
	PromptConfirm(message string, defaultYes bool) (bool, error)

	// ShowPlan displays the merge plan for review.
	// This is informational - no return value needed.
	// Called before prompting for strategy selection.
	ShowPlan(plan *Plan, validation *PlanValidation)

	// ShowMidStackWarning displays a warning when user is mid-stack in a scope.
	// Called when branches above the current branch share the same scope.
	ShowMidStackWarning(scope string, upstackBranchesInScope []string)

	// PromptPostMerge asks user what to do after merge completes.
	// Called after successful merge execution.
	// Returns ErrCanceled if user cancels (treated as "done").
	PromptPostMerge(hasUncommittedChanges bool, trunkName string) (PostMergeAction, error)

	// PromptSimpleMergeConfirm shows a simplified confirmation for single-branch merges.
	// This provides a cleaner UX than ShowPlan + PromptConfirm for simple cases.
	// Returns true to proceed, false to cancel.
	PromptSimpleMergeConfirm(branch BranchMergeInfo, baseBranch string) (bool, error)
}

InteractiveHandler extends EventHandler with interactive prompt capabilities. This allows the action layer to request user input without depending on specific UI implementations (TUI, CLI, etc.).

Implementations should handle TUI lifecycle (pause/resume) internally when showing prompts to avoid conflicts with progress display.

Error handling: Prompt methods should return sterrors.ErrCanceled when the user cancels (e.g., Ctrl+C, Escape). Other errors indicate actual failures.

type LocalCISearchResult

type LocalCISearchResult struct {
	WorkingStacks []MultiStackInfo     // Stacks that pass CI together
	FailedStacks  []MultiStackExcluded // Stacks that failed CI
}

LocalCISearchResult contains the result of binary search for working stacks

func FindLargestWorkingSet

func FindLargestWorkingSet(
	ctx context.Context,
	validator *LocalCIValidator,
	executor *MultiStackWorktreeExecutor,
	worktreeEng engine.Engine,
	worktreePath string,
	stacks []MultiStackInfo,
) (*LocalCISearchResult, error)

FindLargestWorkingSet finds the maximum subset of stacks that pass CI. It uses a greedy approach: try adding stacks one by one, keeping those that pass.

type LocalCIValidator

type LocalCIValidator struct {
	Command string
	Timeout time.Duration
	// contains filtered or unexported fields
}

LocalCIValidator runs local CI validation on merged code

func NewLocalCIValidator

func NewLocalCIValidator(cfg config.Configurer, out output.Output) *LocalCIValidator

NewLocalCIValidator creates a new local CI validator from config. Uses the unified ci.command config, with fallback to combine.ciCommand for backwards compatibility.

func (*LocalCIValidator) IsConfigured

func (v *LocalCIValidator) IsConfigured() bool

IsConfigured returns true if a CI command is configured

func (*LocalCIValidator) Validate

func (v *LocalCIValidator) Validate(ctx context.Context, workdir string) error

Validate runs the CI command in the specified directory

type MergeType

type MergeType string

MergeType represents what the user wants to merge

const (
	MergeTypeThis   MergeType = "this"   // Merge current branch and its stack
	MergeTypeScope  MergeType = "scope"  // Merge all branches in a scope
	MergeTypeStacks MergeType = "stacks" // Merge selected stacks
)

MergeType constants

type MultiStackExcluded

type MultiStackExcluded struct {
	Stack  MultiStackInfo
	Reason string // "conflict" | "ci_failure"
}

MultiStackExcluded represents a stack that was not included in the merge

type MultiStackInfo

type MultiStackInfo struct {
	RootBranch  string   // Stack root branch name (direct child of trunk)
	AllBranches []string // All branches in the stack (root to tip, in order)
	PRCount     int      // Number of PRs in this stack
	Scope       string   // Stack scope if any
}

MultiStackInfo represents a stack that can be merged in multi-stack mode

func DiscoverStacks

func DiscoverStacks(eng engine.BranchReader) ([]MultiStackInfo, error)

DiscoverStacks returns all independent stacks rooted at trunk. Each stack is represented by its root branch (direct child of trunk) and includes all branches in the stack in topological order.

func DiscoverStacksWithSort

func DiscoverStacksWithSort(eng engine.BranchReader, strategy engine.SortStrategy) ([]MultiStackInfo, error)

DiscoverStacksWithSort is like DiscoverStacks but allows specifying the sort strategy. Use SortStrategySmart to match the ordering of `stackit log`.

func FilterStacks

func FilterStacks(stacks []MultiStackInfo, selectedRoots []string) []MultiStackInfo

FilterStacks filters stacks based on selected root branch names. If selectedRoots is empty, returns all stacks. The returned stacks maintain the order of selectedRoots (priority order).

type MultiStackOptions

type MultiStackOptions struct {
	SelectedStacks []string // Stack roots selected by user (skips picker if provided)
	SkipLocalCI    bool     // Skip local CI validation
	Wait           bool     // Wait for CI and auto-merge
}

MultiStackOptions contains options specific to multi-stack merge

type MultiStackPRCreator

type MultiStackPRCreator struct {
	// contains filtered or unexported fields
}

MultiStackPRCreator handles creating the multi-stack PR

func NewMultiStackPRCreator

func NewMultiStackPRCreator(ctx *app.Context, worktreeEng engine.Engine, worktreePath string) *MultiStackPRCreator

NewMultiStackPRCreator creates a new PR creator for multi-stack merge

func (*MultiStackPRCreator) BuildStackMetadata

func (p *MultiStackPRCreator) BuildStackMetadata(included []MultiStackInfo) pr.StackMetadata

BuildStackMetadata builds stack trailer metadata for the included multi-stack branches.

func (*MultiStackPRCreator) CreateAndPushBranch

func (p *MultiStackPRCreator) CreateAndPushBranch(ctx context.Context, branchName string) error

CreateAndPushBranch creates a named branch at the current HEAD and pushes it

func (*MultiStackPRCreator) CreatePR

func (p *MultiStackPRCreator) CreatePR(ctx context.Context, branchName string, included []MultiStackInfo, excluded []MultiStackExcluded) (*github.PullRequestInfo, error)

CreatePR creates the multi-stack pull request

func (*MultiStackPRCreator) EnableAutoMerge

func (p *MultiStackPRCreator) EnableAutoMerge(ctx context.Context, pr *github.PullRequestInfo, commitBody string) error

EnableAutoMerge enables GitHub auto-merge for a multi-stack PR.

func (*MultiStackPRCreator) WaitAndMerge

func (p *MultiStackPRCreator) WaitAndMerge(ctx context.Context, branchName string, pr *github.PullRequestInfo, commitBody string) error

WaitAndMerge waits for CI to pass and auto-merges the PR

type MultiStackResult

type MultiStackResult struct {
	IncludedStacks []MultiStackInfo     // Stacks that were successfully included
	ExcludedStacks []MultiStackExcluded // Stacks that were excluded with reasons
	PRNumber       int                  // Created PR number
	PRURL          string               // Created PR URL
	BranchName     string               // Consolidation branch name
}

MultiStackResult contains the result of a multi-stack merge operation

func ExecuteMultiStack

func ExecuteMultiStack(ctx *app.Context, opts MultiStackOptions) (*MultiStackResult, error)

ExecuteMultiStack performs the multi-stack merge operation. It merges multiple independent stacks into a single consolidated branch, handling conflicts by skipping entire stacks that conflict.

type MultiStackWorktreeExecutor

type MultiStackWorktreeExecutor struct {
	// contains filtered or unexported fields
}

MultiStackWorktreeExecutor handles merging stacks in a worktree

func NewMultiStackWorktreeExecutor

func NewMultiStackWorktreeExecutor(eng engine.Engine, out output.Output) *MultiStackWorktreeExecutor

NewMultiStackWorktreeExecutor creates a new worktree executor for multi-stack merge

func (*MultiStackWorktreeExecutor) ExecuteInWorktree

ExecuteInWorktree creates a worktree at trunk and attempts to merge all stacks. It first tries a global octopus merge (all branches from all stacks in one commit). If that fails due to conflicts, it falls back to per-stack merging to identify which stacks conflict.

func (*MultiStackWorktreeExecutor) ResetToTrunk

func (w *MultiStackWorktreeExecutor) ResetToTrunk(ctx context.Context, eng engine.Engine) error

ResetToTrunk resets the worktree to trunk, discarding all merges. This is used by binary search to try different combinations.

type MultiStackWorktreeResult

type MultiStackWorktreeResult struct {
	MergedStacks   []MultiStackInfo     // Stacks that were successfully merged
	ConflictStacks []MultiStackExcluded // Stacks that conflicted
	WorktreePath   string               // Path to the worktree
	WorktreeEngine engine.Engine        // Engine for the worktree
	Cleanup        func()               // Function to clean up the worktree
}

MultiStackWorktreeResult contains the result of merging stacks in a worktree

type NullEventHandler

type NullEventHandler struct{}

NullEventHandler is a no-op EventHandler for testing or when output is not needed

func (*NullEventHandler) Cleanup

func (h *NullEventHandler) Cleanup()

Cleanup implements EventHandler.

func (*NullEventHandler) Complete

func (h *NullEventHandler) Complete(_ *Result)

Complete implements EventHandler.

func (*NullEventHandler) EmitEvent

func (h *NullEventHandler) EmitEvent(_ Event)

EmitEvent implements EventHandler.

func (*NullEventHandler) Start

func (h *NullEventHandler) Start(_ *Plan)

Start implements EventHandler.

type Options

type Options struct {
	DryRun         bool
	Confirm        bool
	Strategy       Strategy
	Force          bool
	Wait           bool // Whether to wait for CI/merge (applies to consolidate)
	Scope          string
	TargetBranch   string
	Plan           *Plan // Optional pre-calculated plan
	UndoStackDepth int   // Maximum undo stack depth (from config)
	Handler        EventHandler
	MergeMethod    github.MergeMethod // Optional: override merge method (empty = auto-detect/prompt)
}

Options contains options for the merge command

type PRCleaner

type PRCleaner struct {
	// contains filtered or unexported fields
}

PRCleaner handles post-merge cleanup of individual PRs

func NewPRCleaner

func NewPRCleaner(ctx *app.Context, eng prCleanupEngine, config PRCleanupConfig) *PRCleaner

NewPRCleaner creates a new PR cleaner

func (*PRCleaner) CleanupBranches

func (c *PRCleaner) CleanupBranches(ctx context.Context, branchNames []string) PRCleanupResult

CleanupBranches closes PRs for the given branch names and updates their bodies with a footer

func (*PRCleaner) LogResult

func (c *PRCleaner) LogResult(result PRCleanupResult)

LogResult logs the cleanup result to output

type PRCleanupConfig

type PRCleanupConfig struct {
	// Source identifies the cleanup source for footer text
	Source PRCleanupSource

	// ConsolidationPRNumber is the PR number of the consolidation PR
	ConsolidationPRNumber int

	// UserName is the username to include in the footer (optional)
	UserName string
}

PRCleanupConfig configures the post-merge PR cleanup behavior

type PRCleanupResult

type PRCleanupResult struct {
	ClosedPRs  []int // PR numbers that were closed
	FailedPRs  []int // PR numbers that failed to close
	SkippedPRs []int // PR numbers that were already closed
}

PRCleanupResult contains the results of PR cleanup

func (PRCleanupResult) ClosedCount

func (r PRCleanupResult) ClosedCount() int

ClosedCount returns the number of PRs that were closed

func (PRCleanupResult) FailedCount

func (r PRCleanupResult) FailedCount() int

FailedCount returns the number of PRs that failed to close

func (PRCleanupResult) SkippedCount

func (r PRCleanupResult) SkippedCount() int

SkippedCount returns the number of PRs that were skipped (already closed)

type PRCleanupSource

type PRCleanupSource string

PRCleanupSource identifies how a consolidation happened (for footer text)

const (
	// CleanupSourceConsolidate is used when consolidating a single stack
	CleanupSourceConsolidate PRCleanupSource = "consolidation"
	// CleanupSourceMultiStack is used when consolidating multiple stacks
	CleanupSourceMultiStack PRCleanupSource = "multi-stack consolidation"
)

type PRContentGenerator

type PRContentGenerator struct {
	// contains filtered or unexported fields
}

PRContentGenerator handles PR title and body generation for merge PRs.

func NewPRContentGenerator

func NewPRContentGenerator(engine interface {
	GetBranch(name string) engine.Branch
	GetScope(branch engine.Branch) engine.Scope
	GetStackDescription(branch engine.Branch) *git.StackDescription
	Trunk() engine.Branch
}) *PRContentGenerator

NewPRContentGenerator creates a new PR content generator.

func (*PRContentGenerator) GenerateConsolidationPR

func (g *PRContentGenerator) GenerateConsolidationPR(branches []BranchMergeInfo) pr.Content

GenerateConsolidationPR generates PR content for stack consolidation.

func (*PRContentGenerator) GenerateMultiStackPR

func (g *PRContentGenerator) GenerateMultiStackPR(included []MultiStackInfo, excluded []MultiStackExcluded) pr.Content

GenerateMultiStackPR generates PR content for multi-stack merges.

type Phase

type Phase string

Phase represents a phase in the merge process

const (
	PhasePlan     Phase = "plan"
	PhaseMerge    Phase = "merge"
	PhaseRestack  Phase = "restack"
	PhaseCleanup  Phase = "cleanup"
	PhaseWaiting  Phase = "waiting"
	PhaseComplete Phase = "complete"
)

Phase constants

type Plan

type Plan struct {
	Strategy        Strategy
	CurrentBranch   string
	BranchesToMerge []BranchMergeInfo // Branches that will be merged (bottom to top)
	UpstackBranches []string          // Branches above current that will be restacked
	Steps           []PlanStep        // Ordered steps to execute
	Warnings        []string          // Non-blocking warnings
	Infos           []string          // Informational messages
	CreatedAt       time.Time
}

Plan is the complete plan for a merge operation

func BuildMergePlan

func BuildMergePlan(collected *CollectedBranches, strategy Strategy, wait bool) *Plan

BuildMergePlan builds a Plan with strategy-specific steps from collected branch data. This is the cheap part that only does in-memory computation.

type PlanStep

type PlanStep struct {
	StepType     StepType
	BranchName   string
	PRNumber     int
	Description  string        // Human-readable description for display
	WaitTimeout  time.Duration // Timeout for waiting steps (e.g., CI checks)
	ExpectChecks bool          // Whether we expect CI checks to be present
}

PlanStep represents a single step in the merge plan

type PlanValidation

type PlanValidation struct {
	Valid    bool
	Errors   []string // Blocking errors
	Warnings []string // Non-blocking warnings
	Infos    []string // Informational messages
}

PlanValidation contains validation results

type PostMergeAction

type PostMergeAction string

PostMergeAction represents a follow-up action after merge

const (
	PostMergeSyncTrunk PostMergeAction = "sync-trunk" // Switch to trunk and sync
	PostMergeDone      PostMergeAction = "done"       // No follow-up action
)

PostMergeAction constants

type PostMergeActionRequired

type PostMergeActionRequired struct {
	Action PostMergeAction
}

PostMergeActionRequired is returned when post-merge action is needed

func (*PostMergeActionRequired) Error

func (e *PostMergeActionRequired) Error() string

type Result

type Result struct {
	Success             bool
	ConsolidationResult *ConsolidationResult
	Error               error
}

Result contains the final result of a merge operation

type StepType

type StepType string

StepType represents the type of step in a merge plan

const (
	// StepMergePR represents merging a PR
	StepMergePR StepType = "MERGE_PR"
	// StepRestack represents restacking a branch onto its parent
	StepRestack StepType = "RESTACK"
	// StepDeleteBranch represents deleting a local branch
	StepDeleteBranch StepType = "DELETE_BRANCH"
	// StepUpdatePRBase represents updating a PR's base branch
	StepUpdatePRBase StepType = "UPDATE_PR_BASE"
	// StepPullTrunk represents pulling the trunk branch
	StepPullTrunk StepType = "PULL_TRUNK"
	// StepWaitCI represents waiting for CI checks to complete
	StepWaitCI StepType = "WAIT_CI"
	// StepConsolidate represents consolidating the entire stack into a single PR
	StepConsolidate StepType = "CONSOLIDATE"
)

type Strategy

type Strategy string

Strategy defines how PRs in the stack should be merged

const (
	// StrategyBottomUp merges PRs from the bottom of the stack up to the current branch
	StrategyBottomUp Strategy = "bottom-up"
	// StrategyShip creates a single PR containing all stack commits for atomic merging
	StrategyShip Strategy = "ship"
)

func DetermineRecommendedStrategy

func DetermineRecommendedStrategy(branchCount int) Strategy

DetermineRecommendedStrategy returns the recommended strategy based on stack size. - 1-2 branches: bottom-up (merge one at a time) - 3+ branches: ship (atomic merge)

type StrategyChoice

type StrategyChoice struct {
	Strategy Strategy
	Wait     bool // Whether to wait for CI (consolidate strategy only)
}

StrategyChoice contains the user's strategy selection and related options

type WaitResult

type WaitResult struct {
	Passed      bool
	MaxDuration time.Duration // Maximum duration of any check (for estimating future runs)
}

WaitResult contains the result of waiting for CI

type WizardOptions

type WizardOptions struct {
	DryRun       bool     // If true, show plan but don't execute
	Force        bool     // Skip validation checks
	Scope        string   // Pre-selected scope (empty = prompt or use current branch)
	TargetBranch string   // Pre-selected target branch (empty = current branch)
	Strategy     Strategy // Pre-selected strategy (empty = prompt)
	Wait         bool     // Pre-selected wait option (for consolidate)
}

WizardOptions configures the interactive merge wizard

Jump to

Keyboard shortcuts

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