Files
2026-06-23 05:02:15 +08:00

50 lines
1.4 KiB
Go

package git
import (
"fmt"
"os/exec"
"regexp"
"strings"
)
// Remote holds the parsed coordinates of a git remote.
type Remote struct {
Host string
Owner string
Repo string
}
var (
httpsRE = regexp.MustCompile(`^https?://(?:[^@]+@)?([^/:]+)(?::\d+)?/([^/]+)/([^/]+?)(?:\.git)?/?$`)
sshRE = regexp.MustCompile(`^(?:ssh://)?(?:[^@]+@)?([^/:]+)[:/]([^/]+)/([^/]+?)(?:\.git)?/?$`)
)
// ParseRemoteURL parses a git remote URL into its Host, Owner, and Repo parts.
// Supports https, ssh (git@host:owner/repo), and ssh:// forms.
func ParseRemoteURL(url string) (*Remote, error) {
trimmed := strings.TrimSpace(url)
if trimmed == "" {
return nil, fmt.Errorf("empty remote URL")
}
if m := httpsRE.FindStringSubmatch(trimmed); m != nil {
return &Remote{Host: m[1], Owner: m[2], Repo: m[3]}, nil
}
if m := sshRE.FindStringSubmatch(trimmed); m != nil {
return &Remote{Host: m[1], Owner: m[2], Repo: m[3]}, nil
}
return nil, fmt.Errorf("unrecognized remote URL format: %q", trimmed)
}
// DetectRepo resolves the origin remote URL for the given workspace root
// and parses it into a Remote.
func DetectRepo(workspaceRoot string) (*Remote, error) {
out, err := exec.Command("git", "-C", workspaceRoot, "remote", "get-url", "origin").Output()
if err != nil {
return nil, fmt.Errorf("git remote get-url origin: %w", err)
}
return ParseRemoteURL(strings.TrimSpace(string(out)))
}