From 75708eea9844a3ae7cd48ace71d50fe8fbfc91c1 Mon Sep 17 00:00:00 2001 From: "R.A. Lucas" Date: Tue, 2 Mar 2021 10:40:02 -0700 Subject: [PATCH] initial commit on adding usage of git_create_remote_detached --- remote.go | 37 +++++++++++++++++++++++++++++++++--- remote_test.go | 51 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 9 deletions(-) diff --git a/remote.go b/remote.go index 08d8414..e194afa 100644 --- a/remote.go +++ b/remote.go @@ -30,9 +30,9 @@ const ( // RemoteCreateOptions contains options for creating a remote type RemoteCreateOptions struct { - Name string - FetchSpec string - Flags RemoteCreateOptionsFlag + Name string + FetchSpec string + Flags RemoteCreateOptionsFlag } type TransferProgress struct { @@ -173,6 +173,37 @@ type Remote struct { repo *Repository } +type RemoteDetached struct { + r Remote +} + +// NewRemoteDetached returns a detached remote that has no +// reference to a repository. Used to emulate `git ls-remote ` +func NewRemoteDetached(remoteUri string) (*RemoteDetached, error) { + var ptr *C.git_remote + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_remote_create_detached(&ptr, C.CString(remoteUri)) + if ret != 0 { + return nil, MakeGitError(ret) + } + + return &RemoteDetached{r: Remote{ptr: ptr}}, nil +} + +// LsDetached returns a listing of []RemoteHead given an optional reference filter, +// emulating `git ls-remote ...` +func (rd *RemoteDetached) LsDetached(fetchOpts FetchOptions, filterRefs ...string) ([]RemoteHead, error) { + err := rd.r.ConnectFetch(&fetchOpts.RemoteCallbacks, &fetchOpts.ProxyOptions, fetchOpts.Headers) + if err != nil { + return nil, err + } + + return rd.r.Ls(filterRefs...) +} + type CertificateKind uint const ( diff --git a/remote_test.go b/remote_test.go index 22fd292..8eeddd4 100644 --- a/remote_test.go +++ b/remote_test.go @@ -18,6 +18,8 @@ import ( "golang.org/x/crypto/ssh" ) +const TestGitRepoUri = "https://github.com/libgit2/TestGitRepository" + func TestListRemotes(t *testing.T) { t.Parallel() repo := createTestRepo(t) @@ -51,7 +53,7 @@ func TestCertificateCheck(t *testing.T) { repo := createTestRepo(t) defer cleanupTestRepo(t, repo) - remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") + remote, err := repo.Remotes.Create("origin", TestGitRepoUri) checkFatal(t, err) defer remote.Free() @@ -72,7 +74,7 @@ func TestRemoteConnect(t *testing.T) { repo := createTestRepo(t) defer cleanupTestRepo(t, repo) - remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") + remote, err := repo.Remotes.Create("origin", TestGitRepoUri) checkFatal(t, err) defer remote.Free() @@ -95,7 +97,7 @@ func TestRemoteConnectOption(t *testing.T) { option.Name = "origin" option.Flags = RemoteCreateSkipInsteadof - remote, err := repo.Remotes.CreateWithOptions("https://github.com/libgit2/TestGitRepository", option) + remote, err := repo.Remotes.CreateWithOptions(TestGitRepoUri, option) checkFatal(t, err) err = remote.ConnectFetch(nil, nil, nil) @@ -107,7 +109,7 @@ func TestRemoteLs(t *testing.T) { repo := createTestRepo(t) defer cleanupTestRepo(t, repo) - remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") + remote, err := repo.Remotes.Create("origin", TestGitRepoUri) checkFatal(t, err) defer remote.Free() @@ -127,7 +129,7 @@ func TestRemoteLsFiltering(t *testing.T) { repo := createTestRepo(t) defer cleanupTestRepo(t, repo) - remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") + remote, err := repo.Remotes.Create("origin", TestGitRepoUri) checkFatal(t, err) defer remote.Free() @@ -162,7 +164,7 @@ func TestRemotePruneRefs(t *testing.T) { err = config.SetBool("remote.origin.prune", true) checkFatal(t, err) - remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") + remote, err := repo.Remotes.Create("origin", TestGitRepoUri) checkFatal(t, err) defer remote.Free() @@ -493,3 +495,40 @@ func TestRemoteSSH(t *testing.T) { t.Error("Expected remote heads") } } + +func TestNewRemoteDetached(t *testing.T) { + _, err := NewRemoteDetached(TestGitRepoUri) + if err != nil { + t.Fatalf("error %v", err) + } +} + +func TestRemoteDetached_LsDetached(t *testing.T) { + r, _ := NewRemoteDetached(TestGitRepoUri) + + t.Run("NoInput", func(t *testing.T) { + rh, err := r.LsDetached(FetchOptions{}) + if err != nil { + t.Fatalf("error %v", err) + } + + if len(rh) == 0 { + t.Fatalf("Not listing all references") + } + }) + + t.Run("Filters", func(t *testing.T) { + rh, err := r.LsDetached(FetchOptions{}, "HEAD") + if err != nil { + t.Fatalf("error %v", err) + } + + if len(rh) == 0 { + t.Fatalf("Not listing all references") + } + + if rh[0].Name != "HEAD" { + t.Fatalf("Not listing all references") + } + }) +} \ No newline at end of file