fix: Git ssh-scp syntax (#69)

* fix(deps): proper git ssh scheme

* feat(deps): git scp style

Adds support for the git ssh-scp style (`git@github.com:user/repo.git`),
which is an alternative form for ssh (note no ssh://).

* fix(deps): githubSlug also matching gitSSH

* test(deps): other hosts than github
This commit is contained in:
Tom 2020-01-29 16:58:25 +01:00 committed by GitHub
parent 7b8a7836a4
commit 8f14d63f95
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 55 deletions

View file

@ -64,7 +64,7 @@ func TestParseDependency(t *testing.T) {
},
{
name: "SSH",
path: "git+ssh://git@github.com:jsonnet-bundler/jsonnet-bundler.git",
path: "git+ssh://git@github.com/jsonnet-bundler/jsonnet-bundler.git",
want: &deps.Dependency{
Source: deps.Source{
GitSource: &deps.Git{

View file

@ -87,7 +87,7 @@ func (gs *Git) LegacyName() string {
}
var gitProtoFmts = map[string]string{
GitSchemeSSH: GitSchemeSSH + "%s:%s/%s.git",
GitSchemeSSH: GitSchemeSSH + "%s/%s/%s.git",
GitSchemeHTTPS: GitSchemeHTTPS + "%s/%s/%s",
}
@ -100,20 +100,18 @@ func (gs *Git) Remote() string {
// regular expressions for matching package uris
const (
gitSSHExp = `git\+ssh://git@(?P<host>[^:]+):(?P<user>[^/]+)/(?P<repo>[^/]+).git`
gitSSHExp = `ssh://git@(?P<host>.+)/(?P<user>.+)/(?P<repo>.+).git`
gitSCPExp = `^git@(?P<host>.+):(?P<user>.+)/(?P<repo>.+).git`
githubSlugExp = `github.com/(?P<user>[-_a-zA-Z0-9]+)/(?P<repo>[-_a-zA-Z0-9]+)`
)
var (
gitSSHRegex = regexp.MustCompile(gitSSHExp)
gitSSHWithVersionRegex = regexp.MustCompile(gitSSHExp + `@(?P<version>.*)`)
gitSSHWithPathRegex = regexp.MustCompile(gitSSHExp + `/(?P<subdir>.*)`)
gitSSHWithPathAndVersionRegex = regexp.MustCompile(gitSSHExp + `/(?P<subdir>.*)@(?P<version>.*)`)
githubSlugRegex = regexp.MustCompile(githubSlugExp)
githubSlugWithVersionRegex = regexp.MustCompile(githubSlugExp + `@(?P<version>.*)`)
githubSlugWithPathRegex = regexp.MustCompile(githubSlugExp + `/(?P<subdir>.*)`)
githubSlugWithPathAndVersionRegex = regexp.MustCompile(githubSlugExp + `/(?P<subdir>.*)@(?P<version>.*)`)
VersionRegex = `@(?P<version>.*)`
PathRegex = `/(?P<subdir>.*)`
PathAndVersionRegex = `/(?P<subdir>.*)@(?P<version>.*)`
)
func parseGit(uri string) *Dependency {
@ -125,10 +123,16 @@ func parseGit(uri string) *Dependency {
var version string
switch {
case githubSlugRegex.MatchString(uri):
gs, version = parseGitHub(uri)
case gitSSHRegex.MatchString(uri):
gs, version = parseGitSSH(uri)
case reMatch(gitSSHExp, uri):
gs, version = match(uri, gitSSHExp)
gs.Scheme = GitSchemeSSH
case reMatch(gitSCPExp, uri):
gs, version = match(uri, gitSCPExp)
gs.Scheme = GitSchemeSSH
case reMatch(githubSlugExp, uri):
gs, version = match(uri, githubSlugExp)
gs.Scheme = GitSchemeHTTPS
gs.Host = "github.com"
default:
return nil
}
@ -144,33 +148,16 @@ func parseGit(uri string) *Dependency {
return &d
}
func parseGitSSH(p string) (gs *Git, version string) {
gs, version = match(p, []*regexp.Regexp{
gitSSHWithPathAndVersionRegex,
gitSSHWithPathRegex,
gitSSHWithVersionRegex,
gitSSHRegex,
})
gs.Scheme = GitSchemeSSH
return gs, version
}
func parseGitHub(p string) (gs *Git, version string) {
gs, version = match(p, []*regexp.Regexp{
githubSlugWithPathAndVersionRegex,
githubSlugWithPathRegex,
githubSlugWithVersionRegex,
githubSlugRegex,
})
gs.Scheme = GitSchemeHTTPS
gs.Host = "github.com"
return gs, version
}
func match(p string, exps []*regexp.Regexp) (gs *Git, version string) {
func match(p string, exp string) (gs *Git, version string) {
gs = &Git{}
exps := []*regexp.Regexp{
regexp.MustCompile(exp + PathAndVersionRegex),
regexp.MustCompile(exp + PathRegex),
regexp.MustCompile(exp + VersionRegex),
regexp.MustCompile(exp),
}
for _, e := range exps {
if !e.MatchString(p) {
continue
@ -190,6 +177,10 @@ func match(p string, exps []*regexp.Regexp) (gs *Git, version string) {
return gs, ""
}
func reMatch(exp string, str string) bool {
return regexp.MustCompile(exp).MatchString(str)
}
func reSubMatchMap(r *regexp.Regexp, str string) map[string]string {
match := r.FindStringSubmatch(str)
subMatchMap := make(map[string]string)

View file

@ -17,9 +17,23 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseGit(t *testing.T) {
sshWant := func(host string) *Dependency {
return &Dependency{
Version: "v1",
Source: Source{GitSource: &Git{
Scheme: GitSchemeSSH,
Host: host,
User: "user",
Repo: "repo",
Subdir: "/foobar",
}},
}
}
tests := []struct {
name string
uri string
@ -27,7 +41,7 @@ func TestParseGit(t *testing.T) {
wantRemote string
}{
{
name: "GitHub",
name: "github-slug",
uri: "github.com/ksonnet/ksonnet-lib/ksonnet.beta.3",
want: &Dependency{
Version: "master",
@ -42,26 +56,28 @@ func TestParseGit(t *testing.T) {
wantRemote: "https://github.com/ksonnet/ksonnet-lib",
},
{
name: "SSH",
uri: "git+ssh://git@my.host:user/repo.git/foobar@v1",
want: &Dependency{
Version: "v1",
Source: Source{GitSource: &Git{
Scheme: GitSchemeSSH,
Host: "my.host",
User: "user",
Repo: "repo",
Subdir: "/foobar",
}},
name: "ssh.ssh",
uri: "ssh://git@example.com/user/repo.git/foobar@v1",
want: sshWant("example.com"),
wantRemote: "ssh://git@example.com/user/repo.git",
},
wantRemote: "ssh://git@my.host:user/repo.git",
{
name: "ssh.scp",
uri: "git@my.host:user/repo.git/foobar@v1",
want: sshWant("my.host"),
wantRemote: "ssh://git@my.host/user/repo.git", // want ssh format here
},
}
for _, c := range tests {
t.Run(c.name, func(t *testing.T) {
got := Parse("", c.uri)
require.NotNilf(t, got, "parsed dependency is nil. Most likely, no regex matched the format.")
assert.Equal(t, c.want, got)
require.NotNil(t, got.Source)
require.NotNil(t, got.Source.GitSource)
assert.Equal(t, c.wantRemote, got.Source.GitSource.Remote())
})
}