fix `kratos new -r` not support scp styled git url.issue https://gith… (#2295)

* fix `kratos new -r` not support scp styled git url.issue https://github.com/go-kratos/kratos/issues/2294

* fix lint

* fix lint

* remove tail space and add  test case

Co-authored-by: czyt <czyt@w.cn>
Co-authored-by: czyt <x-gopher@qq.com>
pull/2312/head
虫子樱桃 2 years ago committed by GitHub
parent 890bc21ac1
commit 20c2425c18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      cmd/kratos/internal/base/repo.go
  2. 50
      cmd/kratos/internal/base/repo_test.go
  3. 58
      cmd/kratos/internal/base/vcs_url.go
  4. 55
      cmd/kratos/internal/base/vcs_url_test.go

@ -3,13 +3,15 @@ package base
import ( import (
"context" "context"
"fmt" "fmt"
stdurl "net/url" "net"
"os" "os"
"os/exec" "os/exec"
"path" "path"
"strings" "strings"
) )
var unExpandVarPath = []string{"~", ".", ".."}
// Repo is git repository manager. // Repo is git repository manager.
type Repo struct { type Repo struct {
url string url string
@ -18,27 +20,21 @@ type Repo struct {
} }
func repoDir(url string) string { func repoDir(url string) string {
if !strings.Contains(url, "//") { vcsURL, err := ParseVCSUrl(url)
url = "//" + url if err != nil {
} return url
if strings.HasPrefix(url, "//git@") {
url = "ssh:" + url
} else if strings.HasPrefix(url, "//") {
url = "https:" + url
} }
u, err := stdurl.Parse(url) // check host contains port
if err == nil { host, _, err := net.SplitHostPort(vcsURL.Host)
url = fmt.Sprintf("%s://%s%s", u.Scheme, u.Hostname(), u.Path) if err != nil {
host = vcsURL.Host
} }
var start int for _, p := range unExpandVarPath {
start = strings.Index(url, "//") host = strings.TrimLeft(host, p)
if start == -1 {
start = strings.Index(url, ":") + 1
} else {
start += 2
} }
end := strings.LastIndex(url, "/") dir := path.Base(path.Dir(vcsURL.Path))
return url[start:end] url = fmt.Sprintf("%s/%s", host, dir)
return url
} }
// NewRepo new a repository manager. // NewRepo new a repository manager.

@ -7,7 +7,37 @@ import (
) )
func TestRepo(t *testing.T) { func TestRepo(t *testing.T) {
os.RemoveAll("/tmp/test_repo") urls := []string{
// ssh://[user@]host.xz[:port]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
// http[s]://host.xz[:port]/path/to/repo.git/
"https://github.com:7875/go-kratos/kratos.git",
// ftp[s]://host.xz[:port]/path/to/repo.git/
"ftps://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
// ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/~[user]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:/~[user]/path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
///path/to/repo.git/
"//github.com/go-kratos/kratos.git",
// file:///path/to/repo.git/
"file://./github.com/go-kratos/kratos.git",
}
for _, url := range urls {
dir := repoDir(url)
if dir != "github.com/go-kratos" && dir != "/go-kratos" {
t.Fatal(url, "repoDir test failed", dir)
}
}
}
func TestRepoClone(t *testing.T) {
r := NewRepo("https://github.com/go-kratos/service-layout.git", "") r := NewRepo("https://github.com/go-kratos/service-layout.git", "")
if err := r.Clone(context.Background()); err != nil { if err := r.Clone(context.Background()); err != nil {
t.Fatal(err) t.Fatal(err)
@ -15,19 +45,7 @@ func TestRepo(t *testing.T) {
if err := r.CopyTo(context.Background(), "/tmp/test_repo", "github.com/go-kratos/kratos-layout", nil); err != nil { if err := r.CopyTo(context.Background(), "/tmp/test_repo", "github.com/go-kratos/kratos-layout", nil); err != nil {
t.Fatal(err) t.Fatal(err)
} }
urls := []string{ t.Cleanup(func() {
"ssh://git@gitlab.xxx.com:1234/foo/bar.git", os.RemoveAll("/tmp/test_repo")
"ssh://gitlab.xxx.com:1234/foo/bar.git", })
"//git@gitlab.xxx.com:1234/foo/bar.git",
"git@gitlab.xxx.com:1234/foo/bar.git",
"gitlab.xxx.com:1234/foo/bar.git",
"gitlab.xxx.com/foo/bar.git",
"gitlab.xxx.com/foo/bar",
}
for _, url := range urls {
dir := repoDir(url)
if dir != "gitlab.xxx.com/foo" {
t.Fatal("repoDir test failed", dir)
}
}
} }

@ -0,0 +1,58 @@
package base
import (
"errors"
"net/url"
"regexp"
"strings"
)
var (
scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
scheme = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"}
)
// ParseVCSUrl ref https://github.com/golang/go/blob/master/src/cmd/go/internal/vcs/vcs.go
// see https://go-review.googlesource.com/c/go/+/12226/
// git url define https://git-scm.com/docs/git-clone#_git_urls
func ParseVCSUrl(repo string) (*url.URL, error) {
var (
repoURL *url.URL
err error
)
if m := scpSyntaxRe.FindStringSubmatch(repo); m != nil {
// Match SCP-like syntax and convert it to a URL.
// Eg, "git@github.com:user/repo" becomes
// "ssh://git@github.com/user/repo".
repoURL = &url.URL{
Scheme: "ssh",
User: url.User(m[1]),
Host: m[2],
Path: m[3],
}
} else {
if !strings.Contains(repo, "//") {
repo = "//" + repo
}
if strings.HasPrefix(repo, "//git@") {
repo = "ssh:" + repo
} else if strings.HasPrefix(repo, "//") {
repo = "https:" + repo
}
repoURL, err = url.Parse(repo)
if err != nil {
return nil, err
}
}
// Iterate over insecure schemes too, because this function simply
// reports the state of the repo. If we can't see insecure schemes then
// we can't report the actual repo URL.
for _, s := range scheme {
if repoURL.Scheme == s {
return repoURL, nil
}
}
return nil, errors.New("unable to parse repo url")
}

@ -0,0 +1,55 @@
package base
import (
"net"
"strings"
"testing"
)
func TestParseVCSUrl(t *testing.T) {
repos := []string{
// ssh://[user@]host.xz[:port]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
// http[s]://host.xz[:port]/path/to/repo.git/
"https://github.com:7875/go-kratos/kratos.git",
// ftp[s]://host.xz[:port]/path/to/repo.git/
"ftps://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
// ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/~[user]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:/~[user]/path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
///path/to/repo.git/
"~/go-kratos/kratos.git",
// file:///path/to/repo.git/
"file://~/go-kratos/kratos.git",
}
for _, repo := range repos {
url, err := ParseVCSUrl(repo)
if err != nil {
t.Fatal(repo, err)
}
urlPath := strings.TrimLeft(url.Path, "/")
if urlPath != "go-kratos/kratos.git" {
t.Fatal(repo, "parse url failed", urlPath)
}
}
}
func TestParseSsh(t *testing.T) {
repo := "ssh://git@github.com:7875/go-kratos/kratos.git"
url, err := ParseVCSUrl(repo)
if err != nil {
t.Fatal(err)
}
host, _, err := net.SplitHostPort(url.Host)
if err != nil {
host = url.Host
}
t.Log(host, url.Path)
}
Loading…
Cancel
Save