Skip to content
This repository has been archived by the owner on Sep 11, 2020. It is now read-only.

Commit

Permalink
fix wildcard handling in RefSpec matching
Browse files Browse the repository at this point in the history
1) The guard logic here was inverted, resulting in an always-false
   branch, which meant that the suffix after the wildcard was
   incorrectly ignored.
2) Wildcards were treated as 1-or-more matches, but git treats them as
   0-or-more. This change aligns go-git with git, but represents a bit
   of a breaking change for go-git.
  • Loading branch information
novas0x2a committed Jun 4, 2019
1 parent 37b8072 commit 3db5510
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 11 deletions.
6 changes: 3 additions & 3 deletions config/refspec.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ func (s RefSpec) matchGlob(n plumbing.ReferenceName) bool {

var prefix, suffix string
prefix = src[0:wildcard]
if len(src) < wildcard {
suffix = src[wildcard+1 : len(suffix)]
if len(src) > wildcard+1 {
suffix = src[wildcard+1:]
}

return len(name) > len(prefix)+len(suffix) &&
return len(name) >= len(prefix)+len(suffix) &&
strings.HasPrefix(name, prefix) &&
strings.HasSuffix(name, suffix)
}
Expand Down
81 changes: 73 additions & 8 deletions config/refspec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,38 @@ func (s *RefSpecSuite) TestRefSpecMatch(c *C) {
}

func (s *RefSpecSuite) TestRefSpecMatchGlob(c *C) {
spec := RefSpec("refs/heads/*:refs/remotes/origin/*")
c.Assert(spec.Match(plumbing.ReferenceName("refs/tag/foo")), Equals, false)
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/foo")), Equals, true)
tests := map[string]map[string]bool{
"refs/heads/*:refs/remotes/origin/*": {
"refs/tag/foo": false,
"refs/heads/foo": true,
},
"refs/heads/*bc:refs/remotes/origin/*bc": {
"refs/heads/abc": true,
"refs/heads/bc": true,
"refs/heads/abx": false,
},
"refs/heads/a*c:refs/remotes/origin/a*c": {
"refs/heads/abc": true,
"refs/heads/ac": true,
"refs/heads/abx": false,
},
"refs/heads/ab*:refs/remotes/origin/ab*": {
"refs/heads/abc": true,
"refs/heads/ab": true,
"refs/heads/xbc": false,
},
}

for specStr, data := range tests {
spec := RefSpec(specStr)
for ref, matches := range data {
c.Assert(spec.Match(plumbing.ReferenceName(ref)),
Equals,
matches,
Commentf("while matching spec %q against ref %q", specStr, ref),
)
}
}
}

func (s *RefSpecSuite) TestRefSpecDst(c *C) {
Expand All @@ -107,14 +136,50 @@ func (s *RefSpecSuite) TestRefSpecDst(c *C) {
spec.Dst(plumbing.ReferenceName("refs/heads/master")).String(), Equals,
"refs/remotes/origin/master",
)

spec = RefSpec("refs/heads/*bc:refs/remotes/origin/*bc")
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/abc")), Equals, true)
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/bc")), Equals, true)
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/abx")), Equals, false)

spec = RefSpec("refs/heads/a*c:refs/remotes/origin/a*c")
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/abc")), Equals, true)
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/ac")), Equals, true)
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/abx")), Equals, false)

spec = RefSpec("refs/heads/ab*:refs/remotes/origin/ab*")
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/abc")), Equals, true)
c.Assert(spec.Match(plumbing.ReferenceName("refs/heads/xbc")), Equals, false)
}

func (s *RefSpecSuite) TestRefSpecDstBlob(c *C) {
spec := RefSpec("refs/heads/*:refs/remotes/origin/*")
c.Assert(
spec.Dst(plumbing.ReferenceName("refs/heads/foo")).String(), Equals,
"refs/remotes/origin/foo",
)
ref := "refs/heads/abc"
tests := map[string]string{
"refs/heads/*:refs/remotes/origin/*": "refs/remotes/origin/abc",
"refs/heads/*bc:refs/remotes/origin/*": "refs/remotes/origin/a",
"refs/heads/*bc:refs/remotes/origin/*bc": "refs/remotes/origin/abc",
"refs/heads/a*c:refs/remotes/origin/*": "refs/remotes/origin/b",
"refs/heads/a*c:refs/remotes/origin/a*c": "refs/remotes/origin/abc",
"refs/heads/ab*:refs/remotes/origin/*": "refs/remotes/origin/c",
"refs/heads/ab*:refs/remotes/origin/ab*": "refs/remotes/origin/abc",
"refs/heads/*abc:refs/remotes/origin/*abc": "refs/remotes/origin/abc",
"refs/heads/abc*:refs/remotes/origin/abc*": "refs/remotes/origin/abc",
// for these two cases, git specifically logs:
// error: * Ignoring funny ref 'refs/remotes/origin/' locally
// and ignores the ref; go-git does not currently do this validation,
// but probably should.
// "refs/heads/*abc:refs/remotes/origin/*": "",
// "refs/heads/abc*:refs/remotes/origin/*": "",
}

for specStr, dst := range tests {
spec := RefSpec(specStr)
c.Assert(spec.Dst(plumbing.ReferenceName(ref)).String(),
Equals,
dst,
Commentf("while getting dst from spec %q with ref %q", specStr, ref),
)
}
}
func (s *RefSpecSuite) TestMatchAny(c *C) {
specs := []RefSpec{
Expand Down

0 comments on commit 3db5510

Please sign in to comment.