diff --git a/config/module/detect.go b/config/module/detect.go index 633bda246..36a34632f 100644 --- a/config/module/detect.go +++ b/config/module/detect.go @@ -20,6 +20,7 @@ var Detectors []Detector func init() { Detectors = []Detector{ + new(GitHubDetector), new(FileDetector), } } diff --git a/config/module/detect_github.go b/config/module/detect_github.go new file mode 100644 index 000000000..e4854cf42 --- /dev/null +++ b/config/module/detect_github.go @@ -0,0 +1,63 @@ +package module + +import ( + "fmt" + "net/url" + "strings" +) + +// GitHubDetector implements Detector to detect GitHub URLs and turn +// them into URLs that the Git Getter can understand. +type GitHubDetector struct{} + +func (d *GitHubDetector) Detect(src, _ string) (string, bool, error) { + if len(src) == 0 { + return "", false, nil + } + + if strings.HasPrefix(src, "github.com/") { + return d.detectHTTP(src) + } else if strings.HasPrefix(src, "git@github.com:") { + return d.detectSSH(src) + } + + return "", false, nil +} + +func (d *GitHubDetector) detectHTTP(src string) (string, bool, error) { + urlStr := fmt.Sprintf("https://%s", src) + url, err := url.Parse(urlStr) + if err != nil { + return "", true, fmt.Errorf("error parsing GitHub URL: %s", err) + } + + if !strings.HasSuffix(url.Path, ".git") { + url.Path += ".git" + } + + return "git::" + url.String(), true, nil +} + +func (d *GitHubDetector) detectSSH(src string) (string, bool, error) { + idx := strings.Index(src, ":") + qidx := strings.Index(src, "?") + if qidx == -1 { + qidx = len(src) + } + + var u url.URL + u.Scheme = "ssh" + u.User = url.User("git") + u.Host = "github.com" + u.Path = src[idx+1:qidx] + if qidx < len(src) { + q, err := url.ParseQuery(src[qidx+1:]) + if err != nil { + return "", true, fmt.Errorf("error parsing GitHub SSH URL: %s", err) + } + + u.RawQuery = q.Encode() + } + + return "git::"+u.String(), true, nil +} diff --git a/config/module/detect_github_test.go b/config/module/detect_github_test.go new file mode 100644 index 000000000..37fac84c8 --- /dev/null +++ b/config/module/detect_github_test.go @@ -0,0 +1,47 @@ +package module + +import ( + "testing" +) + +func TestGitHubDetector(t *testing.T) { + cases := []struct { + Input string + Output string + }{ + // HTTP + {"github.com/hashicorp/foo", "git::https://github.com/hashicorp/foo.git"}, + {"github.com/hashicorp/foo.git", "git::https://github.com/hashicorp/foo.git"}, + { + "github.com/hashicorp/foo?foo=bar", + "git::https://github.com/hashicorp/foo.git?foo=bar", + }, + { + "github.com/hashicorp/foo.git?foo=bar", + "git::https://github.com/hashicorp/foo.git?foo=bar", + }, + + // SSH + {"git@github.com:hashicorp/foo.git", "git::ssh://git@github.com/hashicorp/foo.git"}, + { + "git@github.com:hashicorp/foo.git?foo=bar", + "git::ssh://git@github.com/hashicorp/foo.git?foo=bar", + }, + } + + pwd := "/pwd" + f := new(GitHubDetector) + for i, tc := range cases { + output, ok, err := f.Detect(tc.Input, pwd) + if err != nil { + t.Fatalf("err: %s", err) + } + if !ok { + t.Fatal("not ok") + } + + if output != tc.Output { + t.Fatalf("%d: bad: %#v", i, output) + } + } +}