summaryrefslogtreecommitdiff
path: root/internal/sync
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-06-23 17:58:12 +0300
committerPaul Buetow <paul@buetow.org>2025-06-23 17:58:12 +0300
commit26ed54e854ca7b26d04108752233e96212bb362a (patch)
tree71352f6de885700e555f1a00023bc2ae7ffa4fa1 /internal/sync
parent8706e6a82819c0c16a0c157283de2f14af2664c3 (diff)
Add support for multiple repository configuration and sync
- Add optional 'repositories' array to configuration file - Add --list-repos flag to list configured repositories - Add --sync-all flag to sync all configured repositories at once - Show progress when syncing multiple repositories - Gracefully handle missing remote repositories with warnings - Improve error handling to continue syncing other repos on failure - Add comprehensive integration tests for all functionality - Add test for multiple repository sync feature Example usage: gitsyncer --sync-all # Sync all configured repos gitsyncer --list-repos # List configured repos gitsyncer --sync repo-name # Sync specific repo (still works) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'internal/sync')
-rw-r--r--internal/sync/sync.go71
1 files changed, 65 insertions, 6 deletions
diff --git a/internal/sync/sync.go b/internal/sync/sync.go
index 4fe1b13..e35dad7 100644
--- a/internal/sync/sync.go
+++ b/internal/sync/sync.go
@@ -69,6 +69,24 @@ func (s *Syncer) SyncRepository(repoName string) error {
return fmt.Errorf("failed to add remote %s: %w", s.getRemoteName(org), err)
}
}
+ } else {
+ // Repository exists, ensure all remotes are configured
+ fmt.Printf("Using existing repository at %s\n", repoPath)
+
+ // Check and add any missing remotes
+ for i := range s.config.Organizations {
+ org := &s.config.Organizations[i]
+ remoteName := s.getRemoteName(org)
+
+ // Check if remote exists
+ cmd := exec.Command("git", "-C", repoPath, "remote", "get-url", remoteName)
+ if err := cmd.Run(); err != nil {
+ // Remote doesn't exist, add it
+ if err := s.addRemote(repoPath, org); err != nil {
+ return fmt.Errorf("failed to add remote %s: %w", remoteName, err)
+ }
+ }
+ }
}
// Change to repository directory
@@ -155,10 +173,43 @@ func (s *Syncer) addRemote(repoPath string, org *config.Organization) error {
// fetchAll fetches from all remotes
func (s *Syncer) fetchAll() error {
- cmd := exec.Command("git", "fetch", "--all", "--prune")
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- return cmd.Run()
+ // First, check which remotes actually exist
+ cmd := exec.Command("git", "remote", "-v")
+ output, err := cmd.Output()
+ if err != nil {
+ return fmt.Errorf("failed to list remotes: %w", err)
+ }
+
+ // Try to fetch from each remote individually to handle missing repos
+ remotes := make(map[string]bool)
+ lines := strings.Split(string(output), "\n")
+ for _, line := range lines {
+ if line == "" {
+ continue
+ }
+ parts := strings.Fields(line)
+ if len(parts) >= 1 {
+ remotes[parts[0]] = true
+ }
+ }
+
+ // Fetch from each remote
+ for remote := range remotes {
+ fmt.Printf("Fetching %s\n", remote)
+ cmd := exec.Command("git", "fetch", remote, "--prune")
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ // Check if it's because the repository doesn't exist
+ if strings.Contains(string(output), "does not appear to be a git repository") ||
+ strings.Contains(string(output), "Could not read from remote repository") {
+ fmt.Printf(" Warning: Remote repository %s does not exist yet\n", remote)
+ continue
+ }
+ return fmt.Errorf("failed to fetch from %s: %w\n%s", remote, err, string(output))
+ }
+ }
+
+ return nil
}
// getAllBranches gets all unique branches from all remotes
@@ -242,8 +293,16 @@ func (s *Syncer) syncBranch(branch string, remotes map[string]*config.Organizati
output, err := cmd.CombinedOutput()
if err != nil {
+ outputStr := string(output)
+ // Check if it's because the repository doesn't exist
+ if strings.Contains(outputStr, "does not appear to be a git repository") ||
+ strings.Contains(outputStr, "Could not read from remote repository") {
+ fmt.Printf(" Note: Remote repository %s does not exist - creating it first would be needed\n", remoteName)
+ fmt.Printf(" Skipping push to %s (repository must be created manually)\n", remoteName)
+ continue
+ }
// Check if it's because the branch doesn't exist on the remote
- if strings.Contains(string(output), "error: src refspec") {
+ if strings.Contains(outputStr, "error: src refspec") {
fmt.Printf(" Creating new branch on %s\n", remoteName)
// Try again with -u flag to set upstream
cmd = exec.Command("git", "push", "-u", remoteName, branch)
@@ -251,7 +310,7 @@ func (s *Syncer) syncBranch(branch string, remotes map[string]*config.Organizati
return fmt.Errorf("failed to push to %s: %w", remoteName, err)
}
} else {
- return fmt.Errorf("failed to push to %s: %w\n%s", remoteName, err, string(output))
+ return fmt.Errorf("failed to push to %s: %w\n%s", remoteName, err, outputStr)
}
}
}