Skip to content

Commit

Permalink
config: url, support multiple insteadOf keys in configuration. Fixes g…
Browse files Browse the repository at this point in the history
  • Loading branch information
BryanStenson-okta committed Oct 7, 2023
1 parent 19fe126 commit a29c997
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 19 deletions.
2 changes: 1 addition & 1 deletion config/config_test.go
Expand Up @@ -160,7 +160,7 @@ func (s *ConfigSuite) TestMarshal(c *C) {

cfg.URLs["ssh://git@github.com/"] = &URL{
Name: "ssh://git@github.com/",
InsteadOf: "https://github.com/",
InsteadOf: []string{"https://github.com/"},
}

b, err := cfg.Marshal()
Expand Down
37 changes: 23 additions & 14 deletions config/url.go
Expand Up @@ -17,7 +17,7 @@ type URL struct {
Name string
// Any URL that starts with this value will be rewritten to start, instead, with <base>.
// When more than one insteadOf strings match a given URL, the longest match is used.
InsteadOf string
InsteadOf []string

// raw representation of the subsection, filled by marshal or unmarshal are
// called.
Expand All @@ -26,7 +26,7 @@ type URL struct {

// Validate validates fields of branch
func (b *URL) Validate() error {
if b.InsteadOf == "" {
if len(b.InsteadOf) == 0 {
return errURLEmptyInsteadOf
}

Expand All @@ -41,7 +41,7 @@ func (u *URL) unmarshal(s *format.Subsection) error {
u.raw = s

u.Name = s.Name
u.InsteadOf = u.raw.Option(insteadOfKey)
u.InsteadOf = u.raw.OptionAll(insteadOfKey)
return nil
}

Expand All @@ -51,31 +51,40 @@ func (u *URL) marshal() *format.Subsection {
}

u.raw.Name = u.Name
u.raw.SetOption(insteadOfKey, u.InsteadOf)
u.raw.SetOption(insteadOfKey, u.InsteadOf...)

return u.raw
}

func findLongestInsteadOfMatch(remoteURL string, urls map[string]*URL) *URL {
var longestMatch *URL
for _, u := range urls {
if !strings.HasPrefix(remoteURL, u.InsteadOf) {
continue
}
var longestMatchLength int

// according to spec if there is more than one match, take the logest
if longestMatch == nil || len(longestMatch.InsteadOf) < len(u.InsteadOf) {
longestMatch = u
for _, u := range urls {
for _, currentInsteadOf := range u.InsteadOf {
if !strings.HasPrefix(remoteURL, currentInsteadOf) {
continue
}

lengthCurrentInsteadOf := len(currentInsteadOf)

// according to spec if there is more than one match, take the longest
if longestMatch == nil || longestMatchLength < lengthCurrentInsteadOf {
longestMatch = u
longestMatchLength = lengthCurrentInsteadOf
}
}
}

return longestMatch
}

func (u *URL) ApplyInsteadOf(url string) string {
if !strings.HasPrefix(url, u.InsteadOf) {
return url
for _, j := range u.InsteadOf {
if strings.HasPrefix(url, j) {
return u.Name + url[len(j):]
}
}

return u.Name + url[len(u.InsteadOf):]
return url
}
81 changes: 77 additions & 4 deletions config/url_test.go
Expand Up @@ -11,7 +11,7 @@ var _ = Suite(&URLSuite{})
func (b *URLSuite) TestValidateInsteadOf(c *C) {
goodURL := URL{
Name: "ssh://github.com",
InsteadOf: "http://github.com",
InsteadOf: []string{"http://github.com"},
}
badURL := URL{}
c.Assert(goodURL.Validate(), IsNil)
Expand All @@ -28,7 +28,26 @@ func (b *URLSuite) TestMarshal(c *C) {
cfg := NewConfig()
cfg.URLs["ssh://git@github.com/"] = &URL{
Name: "ssh://git@github.com/",
InsteadOf: "https://github.com/",
InsteadOf: []string{"https://github.com/"},
}

actual, err := cfg.Marshal()
c.Assert(err, IsNil)
c.Assert(string(actual), Equals, string(expected))
}

func (b *URLSuite) TestMarshalMultipleInsteadOf(c *C) {
expected := []byte(`[core]
bare = false
[url "ssh://git@github.com/"]
insteadOf = https://github.com/
insteadOf = https://google.com/
`)

cfg := NewConfig()
cfg.URLs["ssh://git@github.com/"] = &URL{
Name: "ssh://git@github.com/",
InsteadOf: []string{"https://github.com/", "https://google.com/"},
}

actual, err := cfg.Marshal()
Expand All @@ -48,15 +67,69 @@ func (b *URLSuite) TestUnmarshal(c *C) {
c.Assert(err, IsNil)
url := cfg.URLs["ssh://git@github.com/"]
c.Assert(url.Name, Equals, "ssh://git@github.com/")
c.Assert(url.InsteadOf, Equals, "https://github.com/")
c.Assert(url.InsteadOf[0], Equals, "https://github.com/")
}

func (b *URLSuite) TestUnmarshalMultipleInsteadOf(c *C) {
input := []byte(`[core]
bare = false
[url "ssh://git@github.com/"]
insteadOf = https://github.com/
insteadOf = https://google.com/
`)

cfg := NewConfig()
err := cfg.Unmarshal(input)
c.Assert(err, IsNil)
url := cfg.URLs["ssh://git@github.com/"]
c.Assert(url.Name, Equals, "ssh://git@github.com/")

c.Assert(url.ApplyInsteadOf("https://github.com/foobar"), Equals, "ssh://git@github.com/foobar")
c.Assert(url.ApplyInsteadOf("https://google.com/foobar"), Equals, "ssh://git@github.com/foobar")
}

func (b *URLSuite) TestUnmarshalDuplicateUrls(c *C) {
input := []byte(`[core]
bare = false
[url "ssh://git@github.com/"]
insteadOf = https://github.com/
[url "ssh://git@github.com/"]
insteadOf = https://google.com/
`)

cfg := NewConfig()
err := cfg.Unmarshal(input)
c.Assert(err, IsNil)
url := cfg.URLs["ssh://git@github.com/"]
c.Assert(url.Name, Equals, "ssh://git@github.com/")

c.Assert(url.ApplyInsteadOf("https://github.com/foobar"), Equals, "ssh://git@github.com/foobar")
c.Assert(url.ApplyInsteadOf("https://google.com/foobar"), Equals, "ssh://git@github.com/foobar")
}

func (b *URLSuite) TestApplyInsteadOf(c *C) {
urlRule := URL{
Name: "ssh://github.com",
InsteadOf: "http://github.com",
InsteadOf: []string{"http://github.com"},
}

c.Assert(urlRule.ApplyInsteadOf("http://google.com"), Equals, "http://google.com")
c.Assert(urlRule.ApplyInsteadOf("http://github.com/myrepo"), Equals, "ssh://github.com/myrepo")
}

func (b *URLSuite) TestFindLongestInsteadOfMatch(c *C) {
urlRules := map[string]*URL{
"ssh://github.com": &URL{
Name: "ssh://github.com",
InsteadOf: []string{"http://github.com"},
},
"ssh://somethingelse.com": &URL{
Name: "ssh://somethingelse.com",
InsteadOf: []string{"http://github.com/foobar"},
},
}

longestUrl := findLongestInsteadOfMatch("http://github.com/foobar/bingbash.git", urlRules)

c.Assert(longestUrl.Name, Equals, "ssh://somethingelse.com")
}

0 comments on commit a29c997

Please sign in to comment.