package gitsource import ( "fmt" "regexp" "strings" ) var ( githubTreeRe = regexp.MustCompile(`^https://([^/]*github[^/]*)/([^/]+)/([^/]+)/tree/([^/]+)(/.*)?$`) gitlabTreeRe = regexp.MustCompile(`^https://([^/]*gitlab[^/]*)/([^/]+)/([^/]+)/-/tree/([^/]+)(/.*)?$`) ) // NormalizeURL converts pasted GitHub/GitLab web-tree URLs into plain git // clone URLs and returns the implied discovery root ("" for the repo root). // URLs that are already cloneable pass through unchanged. func NormalizeURL(raw string) (url, root string, err error) { s := strings.TrimSpace(raw) if s == "" { return "", "", fmt.Errorf("empty source URL") } if m := githubTreeRe.FindStringSubmatch(s); m != nil { return fmt.Sprintf("https://%s/%s/%s.git", m[1], m[2], m[3]), strings.TrimPrefix(m[5], "/"), nil } if m := gitlabTreeRe.FindStringSubmatch(s); m != nil { return fmt.Sprintf("https://%s/%s/%s.git", m[1], m[2], m[3]), strings.TrimPrefix(m[5], "/"), nil } if strings.HasSuffix(s, ".git") { return s, "", nil } if m := regexp.MustCompile(`^https://([^/]*github[^/]*)/([^/]+)/([^/]+)$`).FindStringSubmatch(s); m != nil { return fmt.Sprintf("https://%s/%s/%s.git", m[1], m[2], m[3]), "", nil } if m := regexp.MustCompile(`^https://([^/]*gitlab[^/]*)/([^/]+)/([^/]+)$`).FindStringSubmatch(s); m != nil { return fmt.Sprintf("https://%s/%s/%s.git", m[1], m[2], m[3]), "", nil } if strings.HasPrefix(s, "file://") { return strings.TrimPrefix(s, "file://"), "", nil } return s, "", nil }