Function bodies 244 total
mocks.MockClient.WorktreeAdd method · go · L1235-L1250 (16 LOC)pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreeAdd(repoPath string, wtPath string, branch string, base string, newBranch bool) error {
ret := _m.Called(repoPath, wtPath, branch, base, newBranch)
if len(ret) == 0 {
panic("no return value specified for WorktreeAdd")
}
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, string, bool) error); ok {
r0 = rf(repoPath, wtPath, branch, base, newBranch)
} else {
r0 = ret.Error(0)
}
return r0
}mocks.MockClient_WorktreeAdd_Call.Run method · go · L1267-L1272 (6 LOC)pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreeAdd_Call) Run(run func(repoPath string, wtPath string, branch string, base string, newBranch bool)) *MockClient_WorktreeAdd_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(string), args[2].(string), args[3].(string), args[4].(bool))
})
return _c
}mocks.MockClient.WorktreeList method · go · L1285-L1312 (28 LOC)pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreeList(repoPath string) ([]gitops.WorktreeInfo, error) {
ret := _m.Called(repoPath)
if len(ret) == 0 {
panic("no return value specified for WorktreeList")
}
var r0 []gitops.WorktreeInfo
var r1 error
if rf, ok := ret.Get(0).(func(string) ([]gitops.WorktreeInfo, error)); ok {
return rf(repoPath)
}
if rf, ok := ret.Get(0).(func(string) []gitops.WorktreeInfo); ok {
r0 = rf(repoPath)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]gitops.WorktreeInfo)
}
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(repoPath)
} else {
r1 = ret.Error(1)
}
return r0, r1
}mocks.MockClient_WorktreeList_Call.Run method · go · L1325-L1330 (6 LOC)pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreeList_Call) Run(run func(repoPath string)) *MockClient_WorktreeList_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}mocks.MockClient.WorktreePrune method · go · L1343-L1358 (16 LOC)pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreePrune(repoPath string) error {
ret := _m.Called(repoPath)
if len(ret) == 0 {
panic("no return value specified for WorktreePrune")
}
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(repoPath)
} else {
r0 = ret.Error(0)
}
return r0
}mocks.MockClient_WorktreePrune_Call.Run method · go · L1371-L1376 (6 LOC)pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreePrune_Call) Run(run func(repoPath string)) *MockClient_WorktreePrune_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}mocks.MockClient.WorktreeRemove method · go · L1389-L1404 (16 LOC)pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreeRemove(repoPath string, wtPath string, force bool) error {
ret := _m.Called(repoPath, wtPath, force)
if len(ret) == 0 {
panic("no return value specified for WorktreeRemove")
}
var r0 error
if rf, ok := ret.Get(0).(func(string, string, bool) error); ok {
r0 = rf(repoPath, wtPath, force)
} else {
r0 = ret.Error(0)
}
return r0
}All rows scored by the Repobility analyzer (https://repobility.com)
mocks.MockClient_WorktreeRemove_Call.Run method · go · L1419-L1424 (6 LOC)pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreeRemove_Call) Run(run func(repoPath string, wtPath string, force bool)) *MockClient_WorktreeRemove_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(string), args[2].(bool))
})
return _c
}mocks.MockClient.WorktreesDir method · go · L1437-L1462 (26 LOC)pkg/gitops/mocks/mock_Client.go
func (_m *MockClient) WorktreesDir(repoPath string) (string, error) {
ret := _m.Called(repoPath)
if len(ret) == 0 {
panic("no return value specified for WorktreesDir")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
return rf(repoPath)
}
if rf, ok := ret.Get(0).(func(string) string); ok {
r0 = rf(repoPath)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(repoPath)
} else {
r1 = ret.Error(1)
}
return r0, r1
}mocks.MockClient_WorktreesDir_Call.Run method · go · L1475-L1480 (6 LOC)pkg/gitops/mocks/mock_Client.go
func (_c *MockClient_WorktreesDir_Call) Run(run func(repoPath string)) *MockClient_WorktreesDir_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}mocks.NewMockClient function · go · L1494-L1504 (11 LOC)pkg/gitops/mocks/mock_Client.go
func NewMockClient(t interface {
mock.TestingT
Cleanup(func())
}) *MockClient {
mock := &MockClient{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}iterm.ScriptCreateWorktreeWindow function · go · L15-L44 (30 LOC)pkg/iterm/applescript.go
func ScriptCreateWorktreeWindow(wtPath, sessionName string, noClaude bool) string {
// Escape single quotes in paths for AppleScript
safePath := escapeAppleScript(wtPath)
safeName := escapeAppleScript(sessionName)
claudeCmd := fmt.Sprintf("cd '%s' && claude", safePath)
if noClaude {
claudeCmd = fmt.Sprintf("cd '%s'", safePath)
}
return fmt.Sprintf(`tell application "iTerm2"
set newWindow to (create window with default profile)
tell newWindow
tell current session of current tab
set name to "%s:claude"
write text "%s"
set claudeID to unique ID
end tell
tell current session of current tab
set shellSession to (split horizontally with default profile)
end tell
tell shellSession
set name to "%s:shell"
write text "cd '%s'"
set shellID to unique ID
end tell
end tell
return claudeID & "\t" & shellID
end tell`, safeName, claudeCmd, safeName, safePath)
}iterm.ScriptSessionExists function · go · L47-L61 (15 LOC)pkg/iterm/applescript.go
func ScriptSessionExists(sessionID string) string {
safe := escapeAppleScript(sessionID)
return fmt.Sprintf(`tell application "iTerm2"
repeat with w in windows
repeat with t in tabs of w
repeat with s in sessions of t
if unique ID of s is "%s" then
return "true"
end if
end repeat
end repeat
end repeat
return "false"
end tell`, safe)
}iterm.ScriptFocusWindow function · go · L64-L81 (18 LOC)pkg/iterm/applescript.go
func ScriptFocusWindow(sessionID string) string {
safe := escapeAppleScript(sessionID)
return fmt.Sprintf(`tell application "iTerm2"
repeat with w in windows
repeat with t in tabs of w
repeat with s in sessions of t
if unique ID of s is "%s" then
select t
tell w to select
activate
return true
end if
end repeat
end repeat
end repeat
return false
end tell`, safe)
}iterm.ScriptCloseWindow function · go · L84-L99 (16 LOC)pkg/iterm/applescript.go
func ScriptCloseWindow(sessionID string) string {
safe := escapeAppleScript(sessionID)
return fmt.Sprintf(`tell application "iTerm2"
repeat with w in windows
repeat with t in tabs of w
repeat with s in sessions of t
if unique ID of s is "%s" then
close w
return true
end if
end repeat
end repeat
end repeat
return false
end tell`, safe)
}Repobility · open methodology · https://repobility.com/research/
iterm.RealClient.IsRunning method · go · L34-L40 (7 LOC)pkg/iterm/iterm.go
func (c *RealClient) IsRunning() bool {
out, err := exec.Command("osascript", "-e", ScriptIsRunning()).Output()
if err != nil {
return false
}
return strings.TrimSpace(string(out)) == "true"
}iterm.RealClient.EnsureRunning method · go · L42-L61 (20 LOC)pkg/iterm/iterm.go
func (c *RealClient) EnsureRunning() error {
if c.IsRunning() {
return nil
}
if err := exec.Command("open", "-a", "iTerm").Start(); err != nil {
return fmt.Errorf("failed to launch iTerm2: %w", err)
}
// Wait up to 10 seconds
for i := 0; i < 20; i++ {
if c.IsRunning() {
time.Sleep(1 * time.Second) // extra settle time
return nil
}
time.Sleep(500 * time.Millisecond)
}
return fmt.Errorf("timed out waiting for iTerm2 to start")
}iterm.RealClient.CreateWorktreeWindow method · go · L63-L83 (21 LOC)pkg/iterm/iterm.go
func (c *RealClient) CreateWorktreeWindow(path, name string, noClaude bool) (*SessionIDs, error) {
if err := c.EnsureRunning(); err != nil {
return nil, err
}
script := ScriptCreateWorktreeWindow(path, name, noClaude)
out, err := exec.Command("osascript", "-e", script).Output()
if err != nil {
return nil, fmt.Errorf("failed to create iTerm2 window: %w", err)
}
parts := strings.SplitN(strings.TrimSpace(string(out)), "\t", 2)
if len(parts) != 2 {
return nil, fmt.Errorf("unexpected osascript output: %s", string(out))
}
return &SessionIDs{
ClaudeSessionID: parts[0],
ShellSessionID: parts[1],
}, nil
}iterm.RealClient.SessionExists method · go · L85-L94 (10 LOC)pkg/iterm/iterm.go
func (c *RealClient) SessionExists(sessionID string) bool {
if sessionID == "" {
return false
}
out, err := exec.Command("osascript", "-e", ScriptSessionExists(sessionID)).Output()
if err != nil {
return false
}
return strings.TrimSpace(string(out)) == "true"
}iterm.RealClient.FocusWindow method · go · L96-L102 (7 LOC)pkg/iterm/iterm.go
func (c *RealClient) FocusWindow(sessionID string) error {
if sessionID == "" {
return fmt.Errorf("empty session ID")
}
_, err := exec.Command("osascript", "-e", ScriptFocusWindow(sessionID)).Output()
return err
}iterm.RealClient.CloseWindow method · go · L104-L110 (7 LOC)pkg/iterm/iterm.go
func (c *RealClient) CloseWindow(sessionID string) error {
if sessionID == "" {
return fmt.Errorf("empty session ID")
}
_, err := exec.Command("osascript", "-e", ScriptCloseWindow(sessionID)).Output()
return err
}mocks.MockClient.CloseWindow method · go · L24-L39 (16 LOC)pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) CloseWindow(sessionID string) error {
ret := _m.Called(sessionID)
if len(ret) == 0 {
panic("no return value specified for CloseWindow")
}
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(sessionID)
} else {
r0 = ret.Error(0)
}
return r0
}mocks.MockClient_CloseWindow_Call.Run method · go · L52-L57 (6 LOC)pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_CloseWindow_Call) Run(run func(sessionID string)) *MockClient_CloseWindow_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}Powered by Repobility — scan your code at https://repobility.com
mocks.MockClient.CreateWorktreeWindow method · go · L70-L97 (28 LOC)pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) CreateWorktreeWindow(path string, name string, noClaude bool) (*iterm.SessionIDs, error) {
ret := _m.Called(path, name, noClaude)
if len(ret) == 0 {
panic("no return value specified for CreateWorktreeWindow")
}
var r0 *iterm.SessionIDs
var r1 error
if rf, ok := ret.Get(0).(func(string, string, bool) (*iterm.SessionIDs, error)); ok {
return rf(path, name, noClaude)
}
if rf, ok := ret.Get(0).(func(string, string, bool) *iterm.SessionIDs); ok {
r0 = rf(path, name, noClaude)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*iterm.SessionIDs)
}
}
if rf, ok := ret.Get(1).(func(string, string, bool) error); ok {
r1 = rf(path, name, noClaude)
} else {
r1 = ret.Error(1)
}
return r0, r1
}mocks.MockClient_CreateWorktreeWindow_Call.Run method · go · L112-L117 (6 LOC)pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_CreateWorktreeWindow_Call) Run(run func(path string, name string, noClaude bool)) *MockClient_CreateWorktreeWindow_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(string), args[2].(bool))
})
return _c
}mocks.MockClient.EnsureRunning method · go · L130-L145 (16 LOC)pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) EnsureRunning() error {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for EnsureRunning")
}
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}mocks.MockClient_EnsureRunning_Call.Run method · go · L157-L162 (6 LOC)pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_EnsureRunning_Call) Run(run func()) *MockClient_EnsureRunning_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}mocks.MockClient.FocusWindow method · go · L175-L190 (16 LOC)pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) FocusWindow(sessionID string) error {
ret := _m.Called(sessionID)
if len(ret) == 0 {
panic("no return value specified for FocusWindow")
}
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(sessionID)
} else {
r0 = ret.Error(0)
}
return r0
}mocks.MockClient_FocusWindow_Call.Run method · go · L203-L208 (6 LOC)pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_FocusWindow_Call) Run(run func(sessionID string)) *MockClient_FocusWindow_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}mocks.MockClient.IsRunning method · go · L221-L236 (16 LOC)pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) IsRunning() bool {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for IsRunning")
}
var r0 bool
if rf, ok := ret.Get(0).(func() bool); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(bool)
}
return r0
}mocks.MockClient_IsRunning_Call.Run method · go · L248-L253 (6 LOC)pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_IsRunning_Call) Run(run func()) *MockClient_IsRunning_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}Repobility — same analyzer, your code, free for public repos · /scan/
mocks.MockClient.SessionExists method · go · L266-L281 (16 LOC)pkg/iterm/mocks/mock_Client.go
func (_m *MockClient) SessionExists(sessionID string) bool {
ret := _m.Called(sessionID)
if len(ret) == 0 {
panic("no return value specified for SessionExists")
}
var r0 bool
if rf, ok := ret.Get(0).(func(string) bool); ok {
r0 = rf(sessionID)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}mocks.MockClient_SessionExists_Call.Run method · go · L294-L299 (6 LOC)pkg/iterm/mocks/mock_Client.go
func (_c *MockClient_SessionExists_Call) Run(run func(sessionID string)) *MockClient_SessionExists_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}mocks.NewMockClient function · go · L313-L323 (11 LOC)pkg/iterm/mocks/mock_Client.go
func NewMockClient(t interface {
mock.TestingT
Cleanup(func())
}) *MockClient {
mock := &MockClient{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}lifecycle.NewManager function · go · L28-L36 (9 LOC)pkg/lifecycle/lifecycle.go
func NewManager(git gitops.Client, it iterm.Client, sm *state.Manager, trust *claude.TrustManager, log ops.Logger) *Manager {
return &Manager{
git: git,
iterm: it,
state: sm,
trust: trust,
log: log,
}
}lifecycle.Manager.Create method · go · L59-L185 (127 LOC)pkg/lifecycle/lifecycle.go
func (m *Manager) Create(opts CreateOptions) (*CreateResult, error) {
repoName, err := m.git.RepoName(opts.RepoPath)
if err != nil {
return nil, err
}
wtDir, err := m.git.WorktreesDir(opts.RepoPath)
if err != nil {
return nil, err
}
dirname := gitops.BranchToDirname(opts.Branch)
wtPath := filepath.Join(wtDir, dirname)
m.log.Info("Creating worktree for branch '%s' in repo '%s'", opts.Branch, repoName)
m.log.Verbose("Worktrees dir: %s", wtDir)
m.log.Verbose("Worktree path: %s", wtPath)
m.log.Verbose("Base branch: %s", opts.BaseBranch)
// If worktree already exists, delegate to open
if isDirectory(wtPath) {
m.log.Info("Worktree already exists, opening iTerm2 window")
openResult, err := m.Open(OpenOptions{
RepoPath: opts.RepoPath,
WtPath: wtPath,
Branch: opts.Branch,
NoClaude: opts.NoClaude,
DryRun: opts.DryRun,
})
if err != nil {
return nil, err
}
return &CreateResult{
WtPath: openResult.WtPath,
Branch: openResult.Branclifecycle.Manager.Open method · go · L205-L266 (62 LOC)pkg/lifecycle/lifecycle.go
func (m *Manager) Open(opts OpenOptions) (*OpenResult, error) {
repoName, err := m.git.RepoName(opts.RepoPath)
if err != nil {
return nil, err
}
dirname := filepath.Base(opts.WtPath)
// Check if window already exists
ws, err := m.state.GetWorktree(opts.WtPath)
if err != nil {
return nil, err
}
if ws != nil && ws.ClaudeSessionID != "" {
if m.iterm.IsRunning() && m.iterm.SessionExists(ws.ClaudeSessionID) {
m.log.Info("iTerm2 window already open, focusing it")
if err := m.iterm.FocusWindow(ws.ClaudeSessionID); err != nil {
return nil, err
}
return &OpenResult{WtPath: opts.WtPath, Branch: opts.Branch, SessionID: ws.ClaudeSessionID, Focused: true}, nil
}
}
if opts.DryRun {
m.log.Info("Would open iTerm2 window for %s", opts.WtPath)
return &OpenResult{WtPath: opts.WtPath, Branch: opts.Branch}, nil
}
// Pre-approve Claude Code trust
m.trustProject(opts.WtPath)
sessionName := fmt.Sprintf("wt:%s:%s", repoName, dirname)
m.log.Info("Opening iTerm2 wlifecycle.Manager.Delete method · go · L280-L350 (71 LOC)pkg/lifecycle/lifecycle.go
func (m *Manager) Delete(opts DeleteOptions) error {
dirname := filepath.Base(opts.WtPath)
// Close iTerm2 window if it exists
ws, _ := m.state.GetWorktree(opts.WtPath)
if ws != nil && ws.ClaudeSessionID != "" {
if opts.DryRun {
m.log.Info("Would close iTerm2 window")
} else if m.iterm.IsRunning() && m.iterm.SessionExists(ws.ClaudeSessionID) {
if err := m.iterm.CloseWindow(ws.ClaudeSessionID); err != nil {
m.log.Warning("Failed to close iTerm2 window: %v", err)
} else {
m.log.Success("Closed iTerm2 window")
time.Sleep(500 * time.Millisecond)
}
}
}
// Remove worktree
if opts.DryRun {
m.log.Info("Would remove git worktree: %s", opts.WtPath)
} else {
m.log.Info("Removing git worktree")
if err := m.git.WorktreeRemove(opts.RepoPath, opts.WtPath, opts.Force); err != nil {
return err
}
m.log.Success("Removed git worktree")
}
// Delete branch if requested
if opts.DeleteBranch {
branchName := opts.Branch
if ws != nil && ws.Branch != "lifecycle.Manager.trustProject method · go · L353-L363 (11 LOC)pkg/lifecycle/lifecycle.go
func (m *Manager) trustProject(wtPath string) {
if m.trust == nil {
return
}
added, err := m.trust.TrustProject(wtPath)
if err != nil {
m.log.Warning("Failed to set Claude trust: %v", err)
} else if added {
m.log.Verbose("Claude trust set for %s", wtPath)
}
}All rows scored by the Repobility analyzer (https://repobility.com)
ops.Delete function · go · L13-L36 (24 LOC)pkg/ops/delete.go
func Delete(git gitops.Client, log Logger, opts DeleteOptions, safetyCheck SafetyCheckFunc, cleanup CleanupFunc) error {
dirname := filepath.Base(opts.WtPath)
log.Info("Deleting worktree '%s'", dirname)
// Safety checks (skip with --force)
if !opts.Force && safetyCheck != nil {
safe, err := safetyCheck(opts.WtPath)
if err != nil {
return err
}
if !safe {
return fmt.Errorf("delete aborted")
}
}
if cleanup != nil {
if err := cleanup(opts.WtPath, opts.Branch); err != nil {
return err
}
}
return nil
}ops.DeleteAll function · go · L41-L101 (61 LOC)pkg/ops/delete.go
func DeleteAll(git gitops.Client, log Logger, opts DeleteOptions, safetyCheck SafetyCheckFunc, cleanup CleanupFunc) (int, error) {
worktrees, err := git.WorktreeList(opts.RepoPath)
if err != nil {
return 0, err
}
// Filter out main repo
var toDelete []gitops.WorktreeInfo
for _, wt := range worktrees {
if wt.Path != opts.RepoPath {
toDelete = append(toDelete, wt)
}
}
if len(toDelete) == 0 {
log.Info("No worktrees to delete")
return 0, nil
}
log.Info("Found %d worktrees to delete", len(toDelete))
deleted := 0
for _, wt := range toDelete {
dirname := filepath.Base(wt.Path)
if !isDirectory(wt.Path) {
continue
}
// Safety checks
if !opts.Force && safetyCheck != nil {
safe, err := safetyCheck(wt.Path)
if err != nil {
log.Warning("Safety check failed for '%s': %v (skipping)", dirname, err)
continue
}
if !safe {
log.Info("Skipping '%s'", dirname)
continue
}
}
// Cleanup (iTerm, worktree remove, branch delete, stateops.Discover function · go · L8-L83 (76 LOC)pkg/ops/discover.go
func Discover(git gitops.Client, log Logger, opts DiscoverOptions, stateCheck StateChecker, stateAdopt StateAdopter) (*DiscoverResult, error) {
repoName, err := git.RepoName(opts.RepoPath)
if err != nil {
return nil, err
}
wtDir, err := git.WorktreesDir(opts.RepoPath)
if err != nil {
return nil, err
}
worktrees, err := git.WorktreeList(opts.RepoPath)
if err != nil {
return nil, err
}
result := &DiscoverResult{RepoName: repoName}
// Find worktrees not in state
for _, wt := range worktrees {
if wt.Path == opts.RepoPath {
continue
}
managed, err := stateCheck(wt.Path)
if err != nil {
log.Verbose("Could not check state for '%s': %v", wt.Path, err)
continue
}
if managed {
continue
}
result.Unmanaged = append(result.Unmanaged, UnmanagedWorktree{
Path: wt.Path,
Branch: wt.Branch,
Source: classifySource(wt.Path, wtDir),
})
}
if len(result.Unmanaged) == 0 {
log.Success("No unmanaged worktrees found")
return result, nil
}
ops.Merge function · go · L15-L45 (31 LOC)pkg/ops/merge.go
func Merge(git gitops.Client, log Logger, opts MergeOptions, cleanup CleanupFunc, prCreate PRCreateFunc) (*MergeResult, error) {
result := &MergeResult{Branch: opts.Branch}
dirname := filepath.Base(opts.WtPath)
// Safety check: dirty worktree
if !opts.Force {
dirty, err := git.IsWorktreeDirty(opts.WtPath)
if err != nil {
log.Warning("Could not check worktree status: %v", err)
}
if dirty {
return result, fmt.Errorf("worktree '%s' has uncommitted changes (use --force to skip)", dirname)
}
}
// Check if there are commits to merge
hasCommits, err := git.HasUnpushedCommits(opts.WtPath, opts.BaseBranch)
if err != nil {
log.Verbose("Could not check for commits: %v", err)
}
if !hasCommits {
log.Info("No commits to merge for '%s'", opts.Branch)
result.Success = true
return result, nil
}
if opts.CreatePR {
return mergePR(git, log, opts, result, prCreate)
}
return mergeLocal(git, log, opts, result, cleanup)
}ops.mergeLocal function · go · L48-L134 (87 LOC)pkg/ops/merge.go
func mergeLocal(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
// Check if a merge is already in progress in main repo
mergeInProgress, err := git.IsMergeInProgress(opts.RepoPath)
if err != nil {
log.Verbose("Could not check merge status: %v", err)
}
if mergeInProgress {
return mergeLocalContinue(git, log, opts, result, cleanup)
}
// Check if a rebase is in progress in the worktree (rebase-then-ff flow)
rebaseInProgress, err := git.IsRebaseInProgress(opts.WtPath)
if err != nil {
log.Verbose("Could not check rebase status: %v", err)
}
if rebaseInProgress {
return mergeLocalContinueRebase(git, log, opts, result, cleanup)
}
// Verify main repo is on the base branch
currentBranch, err := git.CurrentBranch(opts.RepoPath)
if err != nil {
return result, err
}
if currentBranch != opts.BaseBranch {
return result, fmt.Errorf("main repo is on '%s', expected '%s' — switch to '%s' first", currentBranops.mergeLocalContinue function · go · L137-L158 (22 LOC)pkg/ops/merge.go
func mergeLocalContinue(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
log.Info("Merge in progress — continuing merge of '%s' into '%s'", opts.Branch, opts.BaseBranch)
hasConflicts, err := git.HasConflicts(opts.RepoPath)
if err != nil {
log.Verbose("Could not check conflict status: %v", err)
}
if hasConflicts {
return result, fmt.Errorf("main repo has unresolved conflicts — resolve all conflicts and stage files, then run merge again")
}
if opts.DryRun {
log.Info("Would run: git merge --continue")
} else {
if err := git.MergeContinue(opts.RepoPath); err != nil {
return result, fmt.Errorf("merge --continue failed: %w", err)
}
log.Success("Merge continued — '%s' merged into '%s'", opts.Branch, opts.BaseBranch)
}
return mergeLocalFinish(git, log, opts, result, cleanup)
}ops.mergeLocalContinueRebase function · go · L161-L191 (31 LOC)pkg/ops/merge.go
func mergeLocalContinueRebase(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
dirname := filepath.Base(opts.WtPath)
log.Info("Rebase in progress — continuing merge of '%s' into '%s'", opts.Branch, opts.BaseBranch)
hasConflicts, err := git.HasConflicts(opts.WtPath)
if err != nil {
log.Verbose("Could not check conflict status: %v", err)
}
if hasConflicts {
return result, fmt.Errorf("worktree has unresolved conflicts — resolve all conflicts and stage files, then run merge '%s' again (or 'git -C %s rebase --abort' to cancel)", dirname, opts.WtPath)
}
if opts.DryRun {
log.Info("Would run: git rebase --continue")
log.Info("Would fast-forward merge '%s' into '%s'", opts.Branch, opts.BaseBranch)
} else {
if err := git.RebaseContinue(opts.WtPath); err != nil {
return result, fmt.Errorf("rebase --continue failed: %w", err)
}
log.Success("Rebase continued — '%s' rebased onto '%s'", opts.Branch, opts.Baops.mergeLocalFinish function · go · L194-L225 (32 LOC)pkg/ops/merge.go
func mergeLocalFinish(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, cleanup CleanupFunc) (*MergeResult, error) {
// Push base branch if remote exists
hasRemote, err := git.HasRemote(opts.RepoPath)
if err != nil {
log.Verbose("Could not check for remote: %v", err)
}
if hasRemote {
if opts.DryRun {
log.Info("Would push '%s'", opts.BaseBranch)
} else {
log.Info("Pushing '%s'", opts.BaseBranch)
if err := git.Push(opts.RepoPath, opts.BaseBranch, false); err != nil {
log.Warning("Push failed: %v (merge succeeded locally)", err)
} else {
log.Success("Pushed '%s'", opts.BaseBranch)
}
}
}
// Cleanup unless --no-cleanup
if !opts.NoCleanup && cleanup != nil {
log.Info("Cleaning up worktree")
if err := cleanup(opts.WtPath, opts.Branch); err != nil {
log.Warning("Cleanup failed: %v (merge succeeded)", err)
}
}
result.Success = true
log.Success("Merge complete")
return result, nil
}Repobility · open methodology · https://repobility.com/research/
ops.mergePR function · go · L228-L282 (55 LOC)pkg/ops/merge.go
func mergePR(git gitops.Client, log Logger, opts MergeOptions, result *MergeResult, prCreate PRCreateFunc) (*MergeResult, error) {
if opts.Strategy == "rebase" {
log.Warning("--rebase is ignored for PR mode (merge strategy is configured on GitHub)")
}
log.Info("Creating PR for '%s' → '%s'", opts.Branch, opts.BaseBranch)
// Push branch
if opts.DryRun {
log.Info("Would push branch '%s'", opts.Branch)
} else {
log.Info("Pushing branch '%s'", opts.Branch)
if err := git.Push(opts.WtPath, opts.Branch, true); err != nil {
return result, fmt.Errorf("push failed: %w", err)
}
log.Success("Pushed '%s'", opts.Branch)
}
// Build gh pr create args
args := []string{"pr", "create", "--base", opts.BaseBranch, "--head", opts.Branch}
if opts.PRTitle != "" {
args = append(args, "--title", opts.PRTitle)
}
if opts.PRBody != "" {
args = append(args, "--body", opts.PRBody)
}
if opts.PRTitle == "" && opts.PRBody == "" {
args = append(args, "--fill")
}
if opts.PRDraft {
mocks.MockCleanupFunc.Execute method · go · L21-L36 (16 LOC)pkg/ops/mocks/mock_CleanupFunc.go
func (_m *MockCleanupFunc) Execute(wtPath string, branch string) error {
ret := _m.Called(wtPath, branch)
if len(ret) == 0 {
panic("no return value specified for Execute")
}
var r0 error
if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(wtPath, branch)
} else {
r0 = ret.Error(0)
}
return r0
}mocks.MockCleanupFunc_Execute_Call.Run method · go · L50-L55 (6 LOC)pkg/ops/mocks/mock_CleanupFunc.go
func (_c *MockCleanupFunc_Execute_Call) Run(run func(wtPath string, branch string)) *MockCleanupFunc_Execute_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(string))
})
return _c
}