summaryrefslogtreecommitdiff
path: root/internal/sync/git_operations.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/sync/git_operations.go')
-rw-r--r--internal/sync/git_operations.go117
1 files changed, 117 insertions, 0 deletions
diff --git a/internal/sync/git_operations.go b/internal/sync/git_operations.go
index 7664113..3bd6618 100644
--- a/internal/sync/git_operations.go
+++ b/internal/sync/git_operations.go
@@ -7,6 +7,8 @@ import (
"os/exec"
"regexp"
"strings"
+
+ "codeberg.org/snonux/gitsyncer/internal/config"
)
// checkForMergeConflicts checks if the repository has merge conflicts
@@ -233,3 +235,118 @@ func getAllUniqueBranches(output []byte) []string {
return branches
}
+
+// createSSHBareRepository creates a bare repository on an SSH server
+func createSSHBareRepository(sshHost, repoPath string) error {
+ // Extract user@host and path components
+ parts := strings.Split(sshHost, ":")
+ if len(parts) != 2 {
+ return fmt.Errorf("invalid SSH host format: %s", sshHost)
+ }
+
+ userHost := parts[0]
+ basePath := parts[1]
+
+ // Full path to the repository
+ fullRepoPath := fmt.Sprintf("%s/%s.git", basePath, repoPath)
+
+ fmt.Printf("Creating bare repository at %s:%s\n", userHost, fullRepoPath)
+
+ // Create the repository directory and initialize as bare
+ commands := fmt.Sprintf("mkdir -p %s && cd %s && git init --bare", fullRepoPath, fullRepoPath)
+ cmd := exec.Command("ssh", userHost, commands)
+ output, err := cmd.CombinedOutput()
+
+ if err != nil {
+ return fmt.Errorf("failed to create bare repository: %w\n%s", err, string(output))
+ }
+
+ fmt.Printf("Successfully created bare repository at %s:%s\n", userHost, fullRepoPath)
+ return nil
+}
+
+// pushBranchWithBackupSupport pushes a branch to a remote, creating SSH repos if needed
+func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool, org *config.Organization) error {
+ cmd := exec.Command("git", "push", remoteName, branch, "--tags")
+ output, err := cmd.CombinedOutput()
+
+ if err != nil {
+ outputStr := string(output)
+ // Check if it's because the repository doesn't exist
+ if isRepositoryMissing(outputStr) {
+ // If it's an SSH backup location, try to create the repository
+ if org.BackupLocation && org.IsSSH() {
+ // Get the repository name from the remote URL
+ remoteURL, err := getRemoteURL(remoteName)
+ if err != nil {
+ return fmt.Errorf("failed to get remote URL: %w", err)
+ }
+
+ // Extract repo name from URL
+ repoName := extractRepoName(remoteURL)
+ if repoName == "" {
+ return fmt.Errorf("failed to extract repository name from URL: %s", remoteURL)
+ }
+
+ // Create the bare repository
+ if err := createSSHBareRepository(org.Host, repoName); err != nil {
+ return fmt.Errorf("failed to create SSH repository: %w", err)
+ }
+
+ // Try pushing again
+ cmd = exec.Command("git", "push", remoteName, branch, "--tags")
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("failed to push after creating repository: %w", err)
+ }
+ fmt.Printf(" Successfully pushed to newly created backup repository\n")
+ return nil
+ }
+
+ fmt.Printf(" Note: Remote repository %s does not exist - must be created manually\n", remoteName)
+ fmt.Printf(" Skipping push to %s\n", remoteName)
+ return nil // Not an error, just skip
+ }
+
+ // Check if it's because the branch doesn't exist on the remote
+ if isBranchMissing(outputStr) {
+ 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, "--tags")
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("failed to push to %s: %w", remoteName, err)
+ }
+ return nil
+ }
+
+ return fmt.Errorf("failed to push to %s: %w\n%s", remoteName, err, outputStr)
+ }
+
+ if !remoteHasBranch {
+ fmt.Printf(" Successfully created branch %s on %s\n", branch, remoteName)
+ }
+
+ return nil
+}
+
+// getRemoteURL gets the URL for a given remote
+func getRemoteURL(remoteName string) (string, error) {
+ cmd := exec.Command("git", "remote", "get-url", remoteName)
+ output, err := cmd.Output()
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(string(output)), nil
+}
+
+// extractRepoName extracts the repository name from a git URL
+func extractRepoName(url string) string {
+ // Remove .git suffix if present
+ url = strings.TrimSuffix(url, ".git")
+
+ // Extract the last component of the path
+ parts := strings.Split(url, "/")
+ if len(parts) > 0 {
+ return parts[len(parts)-1]
+ }
+ return ""
+}