Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions pkg/mirror/git_url.go → pkg/giturl/git_url.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package mirror
package giturl

import (
"fmt"
Expand All @@ -23,8 +23,8 @@ var (
localURLRgx = regexp.MustCompile(`^file:///(?P<path>([\w\-\.]+\/)*)(?P<repo>[\w\-\.]+(\.git)?)$`)
)

// GitURL represents parsed git url
type GitURL struct {
// URL represents parsed git url
type URL struct {
Scheme string // value will be either 'scp', 'ssh', 'https' or 'local'
User string // might be empty for http and local urls
Host string // host or host:port
Expand All @@ -40,40 +40,40 @@ func NormaliseURL(rawURL string) string {
return nURL
}

// ParseGitURL parses a raw url into a GitURL structure.
// Parse parses a raw url into a GitURL structure.
// valid git urls are...
// - user@host.xz:path/to/repo.git
// - ssh://user@host.xz[:port]/path/to/repo.git
// - https://host.xz[:port]/path/to/repo.git
func ParseGitURL(rawURL string) (*GitURL, error) {
gURL := &GitURL{}
func Parse(rawURL string) (*URL, error) {
gURL := &URL{}

rawURL = NormaliseURL(rawURL)

var sections []string

switch {
case isSCPURL(rawURL):
case IsSCPURL(rawURL):
sections = scpURLRgx.FindStringSubmatch(rawURL)
gURL.Scheme = "scp"
gURL.User = sections[scpURLRgx.SubexpIndex("user")]
gURL.Host = sections[scpURLRgx.SubexpIndex("host")]
gURL.Path = sections[scpURLRgx.SubexpIndex("path")]
gURL.Repo = sections[scpURLRgx.SubexpIndex("repo")]
case isSSHURL(rawURL):
case IsSSHURL(rawURL):
sections = sshURLRgx.FindStringSubmatch(rawURL)
gURL.Scheme = "ssh"
gURL.User = sections[sshURLRgx.SubexpIndex("user")]
gURL.Host = sections[sshURLRgx.SubexpIndex("host")]
gURL.Path = sections[sshURLRgx.SubexpIndex("path")]
gURL.Repo = sections[sshURLRgx.SubexpIndex("repo")]
case isHTTPSURL(rawURL):
case IsHTTPSURL(rawURL):
sections = httpsURLRgx.FindStringSubmatch(rawURL)
gURL.Scheme = "https"
gURL.Host = sections[httpsURLRgx.SubexpIndex("host")]
gURL.Path = sections[httpsURLRgx.SubexpIndex("path")]
gURL.Repo = sections[httpsURLRgx.SubexpIndex("repo")]
case isLocalURL(rawURL):
case IsLocalURL(rawURL):
sections = localURLRgx.FindStringSubmatch(rawURL)
gURL.Scheme = "local"
gURL.Path = sections[localURLRgx.SubexpIndex("path")]
Expand Down Expand Up @@ -101,42 +101,42 @@ func ParseGitURL(rawURL string) (*GitURL, error) {
// SameURL returns whether or not the two parsed git URLs are equivalent.
// git URLs can be represented in multiple schemes so if host, path and repo name
// of URLs are same then those URLs are for the same remote repository
func SameURL(lURL, rURL *GitURL) bool {
func SameURL(lURL, rURL *URL) bool {
return lURL.Host == rURL.Host &&
lURL.Path == rURL.Path &&
lURL.Repo == rURL.Repo
}

// SameRawURL returns whether or not the two remote URL strings are equivalent
func SameRawURL(lRepo, rRepo string) (bool, error) {
lURL, err := ParseGitURL(lRepo)
lURL, err := Parse(lRepo)
if err != nil {
return false, err
}
rURL, err := ParseGitURL(rRepo)
rURL, err := Parse(rRepo)
if err != nil {
return false, err
}

return SameURL(lURL, rURL), nil
}

// isSCPURL returns true if supplied URL is scp-like syntax
func isSCPURL(rawURL string) bool {
// IsSCPURL returns true if supplied URL is scp-like syntax
func IsSCPURL(rawURL string) bool {
return scpURLRgx.MatchString(rawURL)
}

// isSSHURL returns true if supplied URL is SSH URL
func isSSHURL(rawURL string) bool {
// IsSSHURL returns true if supplied URL is SSH URL
func IsSSHURL(rawURL string) bool {
return sshURLRgx.MatchString(rawURL)
}

// isHTTPSURL returns true if supplied URL is HTTPS URL
func isHTTPSURL(rawURL string) bool {
// IsHTTPSURL returns true if supplied URL is HTTPS URL
func IsHTTPSURL(rawURL string) bool {
return httpsURLRgx.MatchString(rawURL)
}

// isLocalURL returns true if supplied URL is HTTPS URL
func isLocalURL(rawURL string) bool {
// IsLocalURL returns true if supplied URL is HTTPS URL
func IsLocalURL(rawURL string) bool {
return localURLRgx.MatchString(rawURL)
}
30 changes: 15 additions & 15 deletions pkg/mirror/git_url_test.go → pkg/giturl/git_url_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package mirror
package giturl

import (
"testing"
Expand All @@ -11,60 +11,60 @@ func TestParseGitURL(t *testing.T) {
tests := []struct {
name string
rawURL string
want *GitURL
want *URL
wantErr bool
}{
{"1",
"user@host.xz:path/to/repo.git",
&GitURL{Scheme: "scp", User: "user", Host: "host.xz", Path: "path/to", Repo: "repo.git"},
&URL{Scheme: "scp", User: "user", Host: "host.xz", Path: "path/to", Repo: "repo.git"},
false,
},
{"2",
"git@github.com:org/repo",
&GitURL{Scheme: "scp", User: "git", Host: "github.com", Path: "org", Repo: "repo"},
&URL{Scheme: "scp", User: "git", Host: "github.com", Path: "org", Repo: "repo"},
false},
{"3",
"ssh://user@host.xz:123/path/to/repo.git",
&GitURL{Scheme: "ssh", User: "user", Host: "host.xz:123", Path: "path/to", Repo: "repo.git"},
&URL{Scheme: "ssh", User: "user", Host: "host.xz:123", Path: "path/to", Repo: "repo.git"},
false},
{"4",
"ssh://git@github.com/org/repo",
&GitURL{Scheme: "ssh", User: "git", Host: "github.com", Path: "org", Repo: "repo"},
&URL{Scheme: "ssh", User: "git", Host: "github.com", Path: "org", Repo: "repo"},
false},
{"5",
"https://host.xz:345/path/to/repo.git",
&GitURL{Scheme: "https", Host: "host.xz:345", Path: "path/to", Repo: "repo.git"},
&URL{Scheme: "https", Host: "host.xz:345", Path: "path/to", Repo: "repo.git"},
false},
{"6",
"https://github.com/org/repo",
&GitURL{Scheme: "https", Host: "github.com", Path: "org", Repo: "repo"},
&URL{Scheme: "https", Host: "github.com", Path: "org", Repo: "repo"},
false},
{"7",
"https://host.xz:123/path/to/repo.git",
&GitURL{Scheme: "https", Host: "host.xz:123", Path: "path/to", Repo: "repo.git"},
&URL{Scheme: "https", Host: "host.xz:123", Path: "path/to", Repo: "repo.git"},
false},
{
"valid-special-char-scp",
"user.name-with_@host-with_x.xz:123:path-with_.x/to/prr.test_test-repo0.git",
&GitURL{Scheme: "scp", User: "user.name-with_", Host: "host-with_x.xz:123", Path: "path-with_.x/to", Repo: "prr.test_test-repo0.git"},
&URL{Scheme: "scp", User: "user.name-with_", Host: "host-with_x.xz:123", Path: "path-with_.x/to", Repo: "prr.test_test-repo0.git"},
false,
},
{
"valid-special-char-ssh",
"ssh://user.name-with_@host-with_x.xz:123/path-with_.x/to/prr.test_test-repo1.git",
&GitURL{Scheme: "ssh", User: "user.name-with_", Host: "host-with_x.xz:123", Path: "path-with_.x/to", Repo: "prr.test_test-repo1.git"},
&URL{Scheme: "ssh", User: "user.name-with_", Host: "host-with_x.xz:123", Path: "path-with_.x/to", Repo: "prr.test_test-repo1.git"},
false,
},
{
"valid-special-char-https",
"https://host-with_x.xz:123/path-with_.x/to/prr.test_test-repo2.git",
&GitURL{Scheme: "https", Host: "host-with_x.xz:123", Path: "path-with_.x/to", Repo: "prr.test_test-repo2.git"},
&URL{Scheme: "https", Host: "host-with_x.xz:123", Path: "path-with_.x/to", Repo: "prr.test_test-repo2.git"},
false,
},
{
"valid-special-char-local",
"file:///path-with_.x/to/prr.test_test-repo3.git",
&GitURL{Scheme: "local", Path: "path-with_.x/to", Repo: "prr.test_test-repo3.git"},
&URL{Scheme: "local", Path: "path-with_.x/to", Repo: "prr.test_test-repo3.git"},
false,
},

Expand Down Expand Up @@ -97,12 +97,12 @@ func TestParseGitURL(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseGitURL(tt.rawURL)
got, err := Parse(tt.rawURL)
if (err != nil) != tt.wantErr {
t.Errorf("ParseGitURL() error = %v, wantErr %v", err, tt.wantErr)
return
}
if diff := cmp.Diff(tt.want, got, cmpopts.EquateComparable(GitURL{})); diff != "" {
if diff := cmp.Diff(tt.want, got, cmpopts.EquateComparable(URL{})); diff != "" {
t.Errorf("ParseGitURL() mismatch (-want +got):\n%s", diff)
}
})
Expand Down
1 change: 0 additions & 1 deletion pkg/mirror/git-mirror-e2e-1393286165/upstream1
Submodule upstream1 deleted from d489b7
6 changes: 4 additions & 2 deletions pkg/mirror/repo_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"log/slog"
"time"

"github.com/utilitywarehouse/git-mirror/pkg/giturl"
)

var (
Expand Down Expand Up @@ -97,13 +99,13 @@ func (rp *RepoPool) StartLoop() {

// Repository will return Repository object based on given remote URL
func (rp *RepoPool) Repository(remote string) (*Repository, error) {
gitURL, err := ParseGitURL(remote)
gitURL, err := giturl.Parse(remote)
if err != nil {
return nil, err
}

for _, repo := range rp.repos {
if SameURL(repo.gitURL, gitURL) {
if giturl.SameURL(repo.gitURL, gitURL) {
return repo, nil
}
}
Expand Down
12 changes: 7 additions & 5 deletions pkg/mirror/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"strings"
"sync"
"time"

"github.com/utilitywarehouse/git-mirror/pkg/giturl"
)

const (
Expand Down Expand Up @@ -47,7 +49,7 @@ const (
// The implementation borrows heavily from https://github.com/kubernetes/git-sync.
// A Repository is safe for concurrent use by multiple goroutines.
type Repository struct {
gitURL *GitURL // parsed remote git URL
gitURL *giturl.URL // parsed remote git URL
remote string // remote repo to mirror
root string // absolute path to the root where repo directory createdabsolute path to the root where repo directory created
dir string // absolute path to the repo directory
Expand All @@ -66,9 +68,9 @@ type Repository struct {
// NewRepository creates new repository from the given config.
// Remote repo will not be mirrored until either Mirror() or StartLoop() is called.
func NewRepository(repoConf RepositoryConfig, envs []string, log *slog.Logger) (*Repository, error) {
remoteURL := NormaliseURL(repoConf.Remote)
remoteURL := giturl.NormaliseURL(repoConf.Remote)

gURL, err := ParseGitURL(remoteURL)
gURL, err := giturl.Parse(remoteURL)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -506,7 +508,7 @@ func (r *Repository) init(ctx context.Context) error {
// and parse output to get default branch name
func (r *Repository) getRemoteDefaultBranch(ctx context.Context) (string, error) {
envs := []string{}
if isSCPURL(r.remote) || isSSHURL(r.remote) {
if giturl.IsSCPURL(r.remote) || giturl.IsSSHURL(r.remote) {
envs = append(envs, r.auth.gitSSHCommand())
}

Expand Down Expand Up @@ -598,7 +600,7 @@ func (r *Repository) fetch(ctx context.Context) ([]string, error) {
args := []string{"fetch", "origin", "--prune", "--no-progress", "--porcelain", "--no-auto-gc"}

envs := []string{}
if isSCPURL(r.remote) || isSSHURL(r.remote) {
if giturl.IsSCPURL(r.remote) || giturl.IsSSHURL(r.remote) {
envs = append(envs, r.auth.gitSSHCommand())
}

Expand Down
7 changes: 4 additions & 3 deletions pkg/mirror/repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/utilitywarehouse/git-mirror/pkg/giturl"
)

func TestNewRepo(t *testing.T) {
Expand All @@ -33,7 +34,7 @@ func TestNewRepo(t *testing.T) {
gc: "always",
},
&Repository{
gitURL: &GitURL{Scheme: "scp", User: "user", Host: "host.xz", Path: "path/to", Repo: "repo.git"},
gitURL: &giturl.URL{Scheme: "scp", User: "user", Host: "host.xz", Path: "path/to", Repo: "repo.git"},
remote: "user@host.xz:path/to/repo.git",
root: "/tmp",
dir: "/tmp/repo.git",
Expand Down Expand Up @@ -110,7 +111,7 @@ func TestNewRepo(t *testing.T) {
t.Errorf("NewRepository() error = %v, wantErr %v", err, tt.wantErr)
return
}
if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreFields(Repository{}, "log", "lock", "stop", "stopped"), cmp.AllowUnexported(Repository{}, GitURL{})); diff != "" {
if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreFields(Repository{}, "log", "lock", "stop", "stopped"), cmp.AllowUnexported(Repository{}, giturl.URL{})); diff != "" {
t.Errorf("NewRepository() mismatch (-want +got):\n%s", diff)
}
})
Expand All @@ -119,7 +120,7 @@ func TestNewRepo(t *testing.T) {

func TestRepo_AddWorktreeLink(t *testing.T) {
r := &Repository{
gitURL: &GitURL{Scheme: "scp", User: "user", Host: "host.xz", Path: "path/to", Repo: "repo.git"},
gitURL: &giturl.URL{Scheme: "scp", User: "user", Host: "host.xz", Path: "path/to", Repo: "repo.git"},
root: "/tmp/root",
interval: 10 * time.Second,
auth: nil,
Expand Down