diff --git a/README.md b/README.md index f5abbbc69..96bc24c5d 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ is built-in by default: file URLs. * GitHub URLs, such as "github.com/mitchellh/vagrant" are automatically changed to Git protocol over HTTP. + * GitLab URLs, such as "gitlab.com/inkscape/inkscape" are automatically + changed to Git protocol over HTTP. * BitBucket URLs, such as "bitbucket.org/mitchellh/vagrant" are automatically changed to a Git or mercurial protocol using the BitBucket API. diff --git a/detect.go b/detect.go index 5bb750c9f..f134f7705 100644 --- a/detect.go +++ b/detect.go @@ -23,6 +23,7 @@ var Detectors []Detector func init() { Detectors = []Detector{ new(GitHubDetector), + new(GitLabDetector), new(GitDetector), new(BitBucketDetector), new(S3Detector), diff --git a/detect_gitlab.go b/detect_gitlab.go new file mode 100644 index 000000000..9d1e8d83c --- /dev/null +++ b/detect_gitlab.go @@ -0,0 +1,47 @@ +package getter + +import ( + "fmt" + "net/url" + "strings" +) + +// GitLabDetector implements Detector to detect GitLab URLs and turn +// them into URLs that the Git Getter can understand. +type GitLabDetector struct{} + +func (d *GitLabDetector) Detect(src, _ string) (string, bool, error) { + if len(src) == 0 { + return "", false, nil + } + + if strings.HasPrefix(src, "gitlab.com/") { + return d.detectHTTP(src) + } + + return "", false, nil +} + +func (d *GitLabDetector) detectHTTP(src string) (string, bool, error) { + parts := strings.Split(src, "/") + if len(parts) < 3 { + return "", false, fmt.Errorf( + "GitLab URLs should be gitlab.com/username/repo") + } + + urlStr := fmt.Sprintf("https://%s", strings.Join(parts[:3], "/")) + repoUrl, err := url.Parse(urlStr) + if err != nil { + return "", true, fmt.Errorf("error parsing GitLab URL: %s", err) + } + + if !strings.HasSuffix(repoUrl.Path, ".git") { + repoUrl.Path += ".git" + } + + if len(parts) > 3 { + repoUrl.Path += "//" + strings.Join(parts[3:], "/") + } + + return "git::" + repoUrl.String(), true, nil +} diff --git a/detect_gitlab_test.go b/detect_gitlab_test.go new file mode 100644 index 000000000..f1f85af3c --- /dev/null +++ b/detect_gitlab_test.go @@ -0,0 +1,44 @@ +package getter + +import ( + "testing" +) + +func TestGitLabDetector(t *testing.T) { + cases := []struct { + Input string + Output string + }{ + // HTTP + {"gitlab.com/hashicorp/foo", "git::https://gitlab.com/hashicorp/foo.git"}, + {"gitlab.com/hashicorp/foo.git", "git::https://gitlab.com/hashicorp/foo.git"}, + { + "gitlab.com/hashicorp/foo/bar", + "git::https://gitlab.com/hashicorp/foo.git//bar", + }, + { + "gitlab.com/hashicorp/foo?foo=bar", + "git::https://gitlab.com/hashicorp/foo.git?foo=bar", + }, + { + "gitlab.com/hashicorp/foo.git?foo=bar", + "git::https://gitlab.com/hashicorp/foo.git?foo=bar", + }, + } + + pwd := "/pwd" + f := new(GitLabDetector) + 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) + } + } +}