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

@ -7,7 +7,37 @@ import (
)
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", "")
if err := r.Clone(context.Background()); err != nil {
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 {
t.Fatal(err)
}
urls := []string{
"ssh://git@gitlab.xxx.com:1234/foo/bar.git",
"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)
}
}
t.Cleanup(func() {
os.RemoveAll("/tmp/test_repo")
})
}

@ -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