package git import ( "net/url" "os/exec" "regexp" "strings" "github.com/cli/cli/internal/run" ) var remoteRE = regexp.MustCompile(`(.+)\s+(.+)\s+\((push|fetch)\)`) // RemoteSet is a slice of git remotes type RemoteSet []*Remote // Remote is a parsed git remote type Remote struct { Name string FetchURL *url.URL PushURL *url.URL } func (r *Remote) String() string { return r.Name } // Remotes gets the git remotes set for the current repo func Remotes() (RemoteSet, error) { list, err := listRemotes() if err != nil { return nil, err } return parseRemotes(list), nil } func parseRemotes(gitRemotes []string) (remotes RemoteSet) { for _, r := range gitRemotes { match := remoteRE.FindStringSubmatch(r) if match == nil { continue } name := strings.TrimSpace(match[1]) urlStr := strings.TrimSpace(match[2]) urlType := strings.TrimSpace(match[3]) var rem *Remote if len(remotes) > 0 { rem = remotes[len(remotes)-1] if name != rem.Name { rem = nil } } if rem == nil { rem = &Remote{Name: name} remotes = append(remotes, rem) } u, err := ParseURL(urlStr) if err != nil { continue } switch urlType { case "fetch": rem.FetchURL = u case "push": rem.PushURL = u } } return } // AddRemote adds a new git remote and auto-fetches objects from it func AddRemote(name, u string) (*Remote, error) { addCmd := exec.Command("git", "remote", "add", "-f", name, u) err := run.PrepareCmd(addCmd).Run() if err != nil { return nil, err } urlParsed, err := url.Parse(u) if err != nil { return nil, err } return &Remote{ Name: name, FetchURL: urlParsed, PushURL: urlParsed, }, nil }