diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-11 18:39:16 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-11 18:39:16 +0200 |
| commit | 0011f18e8494a4e57dc277b826d56c0a1df041ce (patch) | |
| tree | 7ffc0ad73b95c32b201adabbaf8baccbdbf6b04f /internal/cli/sync_handlers.go | |
| parent | 8e3b69cdface52a755ee64003832557e8b15e23b (diff) | |
refactor(internal): extract sync and summary helpers
Diffstat (limited to 'internal/cli/sync_handlers.go')
| -rw-r--r-- | internal/cli/sync_handlers.go | 298 |
1 files changed, 116 insertions, 182 deletions
diff --git a/internal/cli/sync_handlers.go b/internal/cli/sync_handlers.go index 538e18c..8fb3a93 100644 --- a/internal/cli/sync_handlers.go +++ b/internal/cli/sync_handlers.go @@ -187,32 +187,7 @@ func HandleSyncAll(cfg *config.Config, flags *Flags) int { fmt.Print(summary) } - // Generate script for abandoned branches - if scriptPath, err := syncer.GenerateDeleteScript(); err != nil { - fmt.Printf("\n⚠️ Failed to generate script: %v\n", err) - } else if scriptPath != "" { - fmt.Printf("\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n📋 ABANDONED BRANCH MANAGEMENT SCRIPT\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n") - fmt.Printf("Generated script: %s\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("Usage:\n") - fmt.Printf(" bash %s --review # Review diffs before deletion\n", scriptPath) - fmt.Printf(" bash %s --review-full # Review full diffs\n", scriptPath) - fmt.Printf(" bash %s --dry-run # Preview what will be deleted\n", scriptPath) - fmt.Printf(" bash %s # Delete branches (with confirmation)\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("💡 Recommended workflow:\n") - fmt.Printf(" 1. Review branches: bash %s --review\n", scriptPath) - fmt.Printf(" 2. Dry-run delete: bash %s --dry-run\n", scriptPath) - fmt.Printf(" 3. Delete branches: bash %s\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("⚠️ WARNING: Review carefully before deleting branches!\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n") - } + printDeleteScript(syncer) return 0 } @@ -457,6 +432,105 @@ func printFullSyncSeparator() { fmt.Println(strings.Repeat("=", 70) + "\n") } +type syncExecution struct { + syncer *sync.Syncer + descCache map[string]string + throttleManager *state.Manager + throttleState *state.State +} + +func newSyncExecution(cfg *config.Config, flags *Flags) *syncExecution { + execution := &syncExecution{ + descCache: loadDescriptionCache(flags.WorkDir), + syncer: sync.New(cfg, flags.WorkDir), + } + execution.syncer.SetBackupEnabled(flags.Backup) + + if flags.Throttle { + manager, st, err := loadThrottleState(flags.WorkDir) + if err != nil { + fmt.Printf("Warning: Failed to load throttle state: %v\n", err) + } + execution.throttleManager = manager + execution.throttleState = st + } + + return execution +} + +func (e *syncExecution) maybeThrottle(repoName string, flags *Flags) bool { + if !flags.Throttle { + return false + } + + decision := evaluateThrottle(repoName, e.throttleState, flags.DryRun) + if decision.Message != "" { + fmt.Println(decision.Message) + } + if decision.SetNextAllowed && e.throttleManager != nil && !flags.DryRun { + e.throttleState.SetNextRepoSyncAllowed(repoName, decision.NextAllowed) + if err := e.throttleManager.Save(e.throttleState); err != nil { + fmt.Printf("Warning: Failed to save throttle state: %v\n", err) + } + } + + return decision.Skip +} + +func (e *syncExecution) markSynced(repoName string, flags *Flags) { + if !flags.Throttle || e.throttleManager == nil { + return + } + + updateRepoSyncState(repoName, e.throttleState) + if err := e.throttleManager.Save(e.throttleState); err != nil { + fmt.Printf("Warning: Failed to save throttle state: %v\n", err) + } +} + +func (e *syncExecution) finishDiscoveredSync(successCount int, flags *Flags) { + if err := saveDescriptionCache(flags.WorkDir, e.descCache); err != nil { + fmt.Printf("Warning: Failed to save descriptions cache: %v\n", err) + } + + fmt.Printf("\n=== Summary ===\n") + fmt.Printf("Successfully synced: %d repositories\n", successCount) + + if summary := e.syncer.GenerateAbandonedBranchSummary(); summary != "" { + fmt.Print(summary) + } + + printDeleteScript(e.syncer) +} + +func printDeleteScript(syncer *sync.Syncer) { + if scriptPath, err := syncer.GenerateDeleteScript(); err != nil { + fmt.Printf("\n⚠️ Failed to generate script: %v\n", err) + } else if scriptPath != "" { + fmt.Printf("\n") + fmt.Print(strings.Repeat("=", 70)) + fmt.Printf("\n📋 ABANDONED BRANCH MANAGEMENT SCRIPT\n") + fmt.Print(strings.Repeat("=", 70)) + fmt.Printf("\n") + fmt.Printf("Generated script: %s\n", scriptPath) + fmt.Printf("\n") + fmt.Printf("Usage:\n") + fmt.Printf(" bash %s --review # Review diffs before deletion\n", scriptPath) + fmt.Printf(" bash %s --review-full # Review full diffs\n", scriptPath) + fmt.Printf(" bash %s --dry-run # Preview what will be deleted\n", scriptPath) + fmt.Printf(" bash %s # Delete branches (with confirmation)\n", scriptPath) + fmt.Printf("\n") + fmt.Printf("💡 Recommended workflow:\n") + fmt.Printf(" 1. Review branches: bash %s --review\n", scriptPath) + fmt.Printf(" 2. Dry-run delete: bash %s --dry-run\n", scriptPath) + fmt.Printf(" 3. Delete branches: bash %s\n", scriptPath) + fmt.Printf("\n") + fmt.Printf("⚠️ WARNING: Review carefully before deleting branches!\n") + fmt.Print(strings.Repeat("=", 70)) + fmt.Printf("\n") + } +} + func syncCodebergRepos(cfg *config.Config, flags *Flags, repos []codeberg.Repository, repoNames []string) int { // Initialize GitHub client if needed var githubClient github.Client @@ -470,24 +544,9 @@ func syncCodebergRepos(cfg *config.Config, flags *Flags, repos []codeberg.Reposi fmt.Printf("\nStarting sync of %d repositories...\n", len(repoNames)) - // Load descriptions cache - descCache := loadDescriptionCache(flags.WorkDir) - - syncer := sync.New(cfg, flags.WorkDir) - syncer.SetBackupEnabled(flags.Backup) + execution := newSyncExecution(cfg, flags) successCount := 0 - var throttleManager *state.Manager - var throttleState *state.State - if flags.Throttle { - manager, st, err := loadThrottleState(flags.WorkDir) - if err != nil { - fmt.Printf("Warning: Failed to load throttle state: %v\n", err) - } - throttleManager = manager - throttleState = st - } - // Create map for descriptions repoMap := make(map[string]codeberg.Repository) for _, repo := range repos { @@ -497,20 +556,8 @@ func syncCodebergRepos(cfg *config.Config, flags *Flags, repos []codeberg.Reposi for i, repoName := range repoNames { fmt.Printf("\n[%d/%d] Syncing %s...\n", i+1, len(repoNames), repoName) - if flags.Throttle { - decision := evaluateThrottle(repoName, throttleState, flags.DryRun) - if decision.Message != "" { - fmt.Println(decision.Message) - } - if decision.SetNextAllowed && throttleManager != nil && !flags.DryRun { - throttleState.SetNextRepoSyncAllowed(repoName, decision.NextAllowed) - if err := throttleManager.Save(throttleState); err != nil { - fmt.Printf("Warning: Failed to save throttle state: %v\n", err) - } - } - if decision.Skip { - continue - } + if execution.maybeThrottle(repoName, flags) { + continue } // Create GitHub repo if needed @@ -528,66 +575,23 @@ func syncCodebergRepos(cfg *config.Config, flags *Flags, repos []codeberg.Reposi } } - if err := syncer.SyncRepository(repoName); err != nil { + if err := execution.syncer.SyncRepository(repoName); err != nil { fmt.Printf("ERROR: Failed to sync %s: %v\n", repoName, err) fmt.Printf("Stopping sync due to error.\n") return 1 } - if flags.Throttle && throttleManager != nil { - updateRepoSyncState(repoName, throttleState) - if err := throttleManager.Save(throttleState); err != nil { - fmt.Printf("Warning: Failed to save throttle state: %v\n", err) - } - } + execution.markSynced(repoName, flags) successCount++ // After syncing, sync descriptions according to precedence if cbRepo, ok := repoMap[repoName]; ok { - syncRepoDescriptions(cfg, flags.DryRun, repoName, cbRepo.Description, "", descCache) + syncRepoDescriptions(cfg, flags.DryRun, repoName, cbRepo.Description, "", execution.descCache) } else { - syncRepoDescriptions(cfg, flags.DryRun, repoName, "", "", descCache) + syncRepoDescriptions(cfg, flags.DryRun, repoName, "", "", execution.descCache) } } - // Save descriptions cache - if err := saveDescriptionCache(flags.WorkDir, descCache); err != nil { - fmt.Printf("Warning: Failed to save descriptions cache: %v\n", err) - } - - fmt.Printf("\n=== Summary ===\n") - fmt.Printf("Successfully synced: %d repositories\n", successCount) - - // Print abandoned branches summary - if summary := syncer.GenerateAbandonedBranchSummary(); summary != "" { - fmt.Print(summary) - } - - // Generate script for abandoned branches - if scriptPath, err := syncer.GenerateDeleteScript(); err != nil { - fmt.Printf("\n⚠️ Failed to generate script: %v\n", err) - } else if scriptPath != "" { - fmt.Printf("\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n📋 ABANDONED BRANCH MANAGEMENT SCRIPT\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n") - fmt.Printf("Generated script: %s\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("Usage:\n") - fmt.Printf(" bash %s --review # Review diffs before deletion\n", scriptPath) - fmt.Printf(" bash %s --review-full # Review full diffs\n", scriptPath) - fmt.Printf(" bash %s --dry-run # Preview what will be deleted\n", scriptPath) - fmt.Printf(" bash %s # Delete branches (with confirmation)\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("💡 Recommended workflow:\n") - fmt.Printf(" 1. Review branches: bash %s --review\n", scriptPath) - fmt.Printf(" 2. Dry-run delete: bash %s --dry-run\n", scriptPath) - fmt.Printf(" 3. Delete branches: bash %s\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("⚠️ WARNING: Review carefully before deleting branches!\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n") - } + execution.finishDiscoveredSync(successCount, flags) if !flags.SyncGitHubPublic { return 0 @@ -611,24 +615,9 @@ func syncGitHubRepos(cfg *config.Config, flags *Flags, repos []github.Repository fmt.Printf("\nStarting sync of %d repositories...\n", len(repoNames)) - // Load descriptions cache - descCache := loadDescriptionCache(flags.WorkDir) - - syncer := sync.New(cfg, flags.WorkDir) - syncer.SetBackupEnabled(flags.Backup) + execution := newSyncExecution(cfg, flags) successCount := 0 - var throttleManager *state.Manager - var throttleState *state.State - if flags.Throttle { - manager, st, err := loadThrottleState(flags.WorkDir) - if err != nil { - fmt.Printf("Warning: Failed to load throttle state: %v\n", err) - } - throttleManager = manager - throttleState = st - } - // Create map for descriptions repoMap := make(map[string]github.Repository) for _, repo := range repos { @@ -638,20 +627,8 @@ func syncGitHubRepos(cfg *config.Config, flags *Flags, repos []github.Repository for i, repoName := range repoNames { fmt.Printf("\n[%d/%d] Syncing %s...\n", i+1, len(repoNames), repoName) - if flags.Throttle { - decision := evaluateThrottle(repoName, throttleState, flags.DryRun) - if decision.Message != "" { - fmt.Println(decision.Message) - } - if decision.SetNextAllowed && throttleManager != nil && !flags.DryRun { - throttleState.SetNextRepoSyncAllowed(repoName, decision.NextAllowed) - if err := throttleManager.Save(throttleState); err != nil { - fmt.Printf("Warning: Failed to save throttle state: %v\n", err) - } - } - if decision.Skip { - continue - } + if execution.maybeThrottle(repoName, flags) { + continue } // Create Codeberg repo if needed @@ -669,66 +646,23 @@ func syncGitHubRepos(cfg *config.Config, flags *Flags, repos []github.Repository } } - if err := syncer.SyncRepository(repoName); err != nil { + if err := execution.syncer.SyncRepository(repoName); err != nil { fmt.Printf("ERROR: Failed to sync %s: %v\n", repoName, err) fmt.Printf("Stopping sync due to error.\n") return 1 } - if flags.Throttle && throttleManager != nil { - updateRepoSyncState(repoName, throttleState) - if err := throttleManager.Save(throttleState); err != nil { - fmt.Printf("Warning: Failed to save throttle state: %v\n", err) - } - } + execution.markSynced(repoName, flags) successCount++ // After syncing, sync descriptions according to precedence if ghRepo, ok := repoMap[repoName]; ok { - syncRepoDescriptions(cfg, flags.DryRun, repoName, "", ghRepo.Description, descCache) + syncRepoDescriptions(cfg, flags.DryRun, repoName, "", ghRepo.Description, execution.descCache) } else { - syncRepoDescriptions(cfg, flags.DryRun, repoName, "", "", descCache) + syncRepoDescriptions(cfg, flags.DryRun, repoName, "", "", execution.descCache) } } - // Save descriptions cache - if err := saveDescriptionCache(flags.WorkDir, descCache); err != nil { - fmt.Printf("Warning: Failed to save descriptions cache: %v\n", err) - } - - fmt.Printf("\n=== Summary ===\n") - fmt.Printf("Successfully synced: %d repositories\n", successCount) - - // Print abandoned branches summary - if summary := syncer.GenerateAbandonedBranchSummary(); summary != "" { - fmt.Print(summary) - } - - // Generate script for abandoned branches - if scriptPath, err := syncer.GenerateDeleteScript(); err != nil { - fmt.Printf("\n⚠️ Failed to generate script: %v\n", err) - } else if scriptPath != "" { - fmt.Printf("\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n📋 ABANDONED BRANCH MANAGEMENT SCRIPT\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n") - fmt.Printf("Generated script: %s\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("Usage:\n") - fmt.Printf(" bash %s --review # Review diffs before deletion\n", scriptPath) - fmt.Printf(" bash %s --review-full # Review full diffs\n", scriptPath) - fmt.Printf(" bash %s --dry-run # Preview what will be deleted\n", scriptPath) - fmt.Printf(" bash %s # Delete branches (with confirmation)\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("💡 Recommended workflow:\n") - fmt.Printf(" 1. Review branches: bash %s --review\n", scriptPath) - fmt.Printf(" 2. Dry-run delete: bash %s --dry-run\n", scriptPath) - fmt.Printf(" 3. Delete branches: bash %s\n", scriptPath) - fmt.Printf("\n") - fmt.Printf("⚠️ WARNING: Review carefully before deleting branches!\n") - fmt.Print(strings.Repeat("=", 70)) - fmt.Printf("\n") - } + execution.finishDiscoveredSync(successCount, flags) return 0 } |
