Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git: Allow supplying a custom transport when performing various operations #379

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions options.go
Expand Up @@ -37,6 +37,9 @@ var (
type CloneOptions struct {
// The (possibly remote) repository URL to clone from.
URL string
// Specify the transport to use. If nil, a default transport will
// be selected based on the URL's protocol.
Transport transport.Transport
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
// Name of the remote to be added, by default `origin`.
Expand Down Expand Up @@ -97,6 +100,9 @@ type PullOptions struct {
SingleBranch bool
// Limit fetching to the specified number of commits.
Depth int
// Specify the transport to use. If nil, a default transport will
// be selected based on the URL's protocol.
Transport transport.Transport
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
// RecurseSubmodules controls if new commits of all populated submodules
Expand Down Expand Up @@ -151,6 +157,9 @@ type FetchOptions struct {
// Depth limit fetching to the specified number of commits from the tip of
// each remote branch history.
Depth int
// Specify the transport to use. If nil, a default transport will
// be selected based on the URL's protocol.
Transport transport.Transport
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
// Progress is where the human readable information sent by the server is
Expand Down Expand Up @@ -195,6 +204,9 @@ type PushOptions struct {
// RefSpecs specify what destination ref to update with what source
// object. A refspec with empty src can be used to delete a reference.
RefSpecs []config.RefSpec
// Specify the transport to use. If nil, a default transport will
// be selected based on the URL's protocol.
Transport transport.Transport
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
// Progress is where the human readable information sent by the server is
Expand Down Expand Up @@ -247,6 +259,9 @@ type SubmoduleUpdateOptions struct {
// the current repository but also in any nested submodules inside those
// submodules (and so on). Until the SubmoduleRescursivity is reached.
RecurseSubmodules SubmoduleRescursivity
// Specify the transport to use. If nil, a default transport will
// be selected based on the URL's protocol.
Transport transport.Transport
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
}
Expand Down Expand Up @@ -569,6 +584,9 @@ func (o *CreateTagOptions) loadConfigTagger(r *Repository) error {

// ListOptions describes how a remote list should be performed.
type ListOptions struct {
// Specify the transport to use. If nil, a default transport will
// be selected based on the URL's protocol.
Transport transport.Transport
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
// InsecureSkipTLS skips ssl verify if protocal is https
Expand Down
26 changes: 14 additions & 12 deletions remote.go
Expand Up @@ -103,7 +103,7 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
return fmt.Errorf("remote names don't match: %s != %s", o.RemoteName, r.c.Name)
}

s, err := newSendPackSession(r.c.URLs[0], o.Auth, o.InsecureSkipTLS, o.CABundle)
s, err := newSendPackSession(r.c.URLs[0], o.Transport, o.Auth, o.InsecureSkipTLS, o.CABundle)
if err != nil {
return err
}
Expand Down Expand Up @@ -314,7 +314,7 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
o.RefSpecs = r.c.Fetch
}

s, err := newUploadPackSession(r.c.URLs[0], o.Auth, o.InsecureSkipTLS, o.CABundle)
s, err := newUploadPackSession(r.c.URLs[0], o.Transport, o.Auth, o.InsecureSkipTLS, o.CABundle)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -411,38 +411,40 @@ func depthChanged(before []plumbing.Hash, s storage.Storer) (bool, error) {
return false, nil
}

func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool, cabundle []byte) (transport.UploadPackSession, error) {
c, ep, err := newClient(url, auth, insecure, cabundle)
func newUploadPackSession(url string, trans transport.Transport, auth transport.AuthMethod, insecure bool, cabundle []byte) (transport.UploadPackSession, error) {
c, ep, err := newClient(url, trans, auth, insecure, cabundle)
if err != nil {
return nil, err
}

return c.NewUploadPackSession(ep, auth)
}

func newSendPackSession(url string, auth transport.AuthMethod, insecure bool, cabundle []byte) (transport.ReceivePackSession, error) {
c, ep, err := newClient(url, auth, insecure, cabundle)
func newSendPackSession(url string, trans transport.Transport, auth transport.AuthMethod, insecure bool, cabundle []byte) (transport.ReceivePackSession, error) {
c, ep, err := newClient(url, trans, auth, insecure, cabundle)
if err != nil {
return nil, err
}

return c.NewReceivePackSession(ep, auth)
}

func newClient(url string, auth transport.AuthMethod, insecure bool, cabundle []byte) (transport.Transport, *transport.Endpoint, error) {
func newClient(url string, trans transport.Transport, auth transport.AuthMethod, insecure bool, cabundle []byte) (transport.Transport, *transport.Endpoint, error) {
ep, err := transport.NewEndpoint(url)
if err != nil {
return nil, nil, err
}
ep.InsecureSkipTLS = insecure
ep.CaBundle = cabundle

c, err := client.NewClient(ep)
if err != nil {
return nil, nil, err
if trans == nil {
trans, err = client.NewClient(ep)
if err != nil {
return nil, nil, err
}
}

return c, ep, err
return trans, ep, err
}

func (r *Remote) fetchPack(ctx context.Context, o *FetchOptions, s transport.UploadPackSession,
Expand Down Expand Up @@ -1091,7 +1093,7 @@ func (r *Remote) List(o *ListOptions) (rfs []*plumbing.Reference, err error) {
}

func (r *Remote) list(ctx context.Context, o *ListOptions) (rfs []*plumbing.Reference, err error) {
s, err := newUploadPackSession(r.c.URLs[0], o.Auth, o.InsecureSkipTLS, o.CABundle)
s, err := newUploadPackSession(r.c.URLs[0], o.Transport, o.Auth, o.InsecureSkipTLS, o.CABundle)
if err != nil {
return nil, err
}
Expand Down
83 changes: 83 additions & 0 deletions remote_test.go
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
"github.com/go-git/go-git/v5/plumbing/storer"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/client"
"github.com/go-git/go-git/v5/storage"
"github.com/go-git/go-git/v5/storage/filesystem"
"github.com/go-git/go-git/v5/storage/memory"
Expand Down Expand Up @@ -336,6 +338,47 @@ func (s *RemoteSuite) TestFetchWithPackfileWriter(c *C) {
c.Assert(mock.PackfileWriterCalled, Equals, true)
}

type mockTransport struct {
transport.Transport
NewUploadPackSessionCalled bool
NewReceivePackSessionCalled bool
}

func newMockTransport(url string) *mockTransport {
ep, _ := transport.NewEndpoint(url)
t, _ := client.NewClient(ep)
return &mockTransport{Transport: t}
}

func (t *mockTransport) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) {
t.NewUploadPackSessionCalled = true
return t.Transport.NewUploadPackSession(ep, auth)
}

func (t *mockTransport) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) {
t.NewReceivePackSessionCalled = true
return t.Transport.NewReceivePackSession(ep, auth)
}

func (s *RemoteSuite) TestFetchWithTransport(c *C) {
url := s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())
mock := newMockTransport(url)

r := NewRemote(memory.NewStorage(), &config.RemoteConfig{
URLs: []string{url},
})

err := r.Fetch(&FetchOptions{
RefSpecs: []config.RefSpec{
config.RefSpec("+refs/heads/master:refs/remotes/origin/master"),
},
Transport: mock,
})

c.Assert(err, IsNil)
c.Assert(mock.NewUploadPackSessionCalled, Equals, true)
}

func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDate(c *C) {
url := s.GetBasicLocalRepositoryURL()
s.doTestFetchNoErrAlreadyUpToDate(c, url)
Expand Down Expand Up @@ -562,6 +605,32 @@ func (s *RemoteSuite) TestPushContextCanceled(c *C) {
c.Assert(runtime.NumGoroutine(), Equals, numGoroutines)
}

func (s *RemoteSuite) TestPushWithTransport(c *C) {
url, clean := s.TemporalDir()
defer clean()

_, err := PlainInit(url, true)
c.Assert(err, IsNil)

fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit()
sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault())

mock := newMockTransport(url)

r := NewRemote(sto, &config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{url},
})

err = r.Push(&PushOptions{
RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"},
Transport: mock,
})

c.Assert(err, IsNil)
c.Assert(mock.NewReceivePackSessionCalled, Equals, true)
}

func (s *RemoteSuite) TestPushTags(c *C) {
url, clean := s.TemporalDir()
defer clean()
Expand Down Expand Up @@ -1007,6 +1076,20 @@ func (s *RemoteSuite) TestListTimeout(c *C) {
c.Assert(err, NotNil)
}

func (s *RemoteSuite) TestListWithTransport(c *C) {
repo := fixtures.Basic().One()
remote := NewRemote(memory.NewStorage(), &config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{repo.URL},
})

mock := newMockTransport(repo.URL)

_, err := remote.List(&ListOptions{Transport: mock})
c.Assert(err, IsNil)
c.Assert(mock.NewUploadPackSessionCalled, Equals, true)
}

func (s *RemoteSuite) TestUpdateShallows(c *C) {
hashes := []plumbing.Hash{
plumbing.NewHash("0000000000000000000000000000000000000001"),
Expand Down
1 change: 1 addition & 0 deletions repository.go
Expand Up @@ -824,6 +824,7 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
ref, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
RefSpecs: c.Fetch,
Depth: o.Depth,
Transport: o.Transport,
Auth: o.Auth,
Progress: o.Progress,
Tags: o.Tags,
Expand Down
52 changes: 52 additions & 0 deletions repository_test.go
Expand Up @@ -189,6 +189,19 @@ func (s *RepositorySuite) TestCloneContext(c *C) {
c.Assert(err, Equals, context.Canceled)
}

func (s *RepositorySuite) TestCloneWithTransport(c *C) {
url := s.GetBasicLocalRepositoryURL()
mock := newMockTransport(url)

_, err := Clone(memory.NewStorage(), nil, &CloneOptions{
URL: url,
Transport: mock,
})

c.Assert(err, IsNil)
c.Assert(mock.NewUploadPackSessionCalled, Equals, true)
}

func (s *RepositorySuite) TestCloneWithTags(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
Expand Down Expand Up @@ -882,6 +895,21 @@ func (s *RepositorySuite) TestFetchContext(c *C) {
c.Assert(r.FetchContext(ctx, &FetchOptions{}), NotNil)
}

func (s *RepositorySuite) TestFetchWithTransport(c *C) {
url := s.GetBasicLocalRepositoryURL()
mock := newMockTransport(url)

r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{url},
})
c.Assert(err, IsNil)

c.Assert(r.Fetch(&FetchOptions{Transport: mock}), IsNil)
c.Assert(mock.NewUploadPackSessionCalled, Equals, true)
}

func (s *RepositorySuite) TestCloneWithProgress(c *C) {
fs := memfs.New()

Expand Down Expand Up @@ -1226,6 +1254,30 @@ func (s *RepositorySuite) TestPushContext(c *C) {
c.Assert(err, NotNil)
}

func (s *RepositorySuite) TestPushWithTransport(c *C) {
url, clean := s.TemporalDir()
defer clean()

_, err := PlainInit(url, true)
c.Assert(err, IsNil)

_, err = s.Repository.CreateRemote(&config.RemoteConfig{
Name: "test2",
URLs: []string{url},
})
c.Assert(err, IsNil)

mock := newMockTransport(url)

err = s.Repository.Push(&PushOptions{
RemoteName: "test2",
Transport: mock,
})

c.Assert(err, IsNil)
c.Assert(mock.NewReceivePackSessionCalled, Equals, true)
}

// installPreReceiveHook installs a pre-receive hook in the .git
// directory at path which prints message m before exiting
// successfully.
Expand Down
10 changes: 7 additions & 3 deletions submodule.go
Expand Up @@ -243,7 +243,10 @@ func (s *Submodule) fetchAndCheckout(
ctx context.Context, r *Repository, o *SubmoduleUpdateOptions, hash plumbing.Hash,
) error {
if !o.NoFetch {
err := r.FetchContext(ctx, &FetchOptions{Auth: o.Auth})
err := r.FetchContext(ctx, &FetchOptions{
Transport: o.Transport,
Auth: o.Auth,
})
if err != nil && err != NoErrAlreadyUpToDate {
return err
}
Expand All @@ -263,8 +266,9 @@ func (s *Submodule) fetchAndCheckout(
refSpec := config.RefSpec("+" + hash.String() + ":" + hash.String())

err := r.FetchContext(ctx, &FetchOptions{
Auth: o.Auth,
RefSpecs: []config.RefSpec{refSpec},
Transport: o.Transport,
Auth: o.Auth,
RefSpecs: []config.RefSpec{refSpec},
})
if err != nil && err != NoErrAlreadyUpToDate && err != ErrExactSHA1NotSupported {
return err
Expand Down
19 changes: 19 additions & 0 deletions submodule_test.go
Expand Up @@ -91,6 +91,25 @@ func (s *SubmoduleSuite) TestUpdate(c *C) {
c.Assert(status.IsClean(), Equals, true)
}

func (s *SubmoduleSuite) TestUpdateWithTransport(c *C) {
if testing.Short() {
c.Skip("skipping test in short mode.")
}

sm, err := s.Worktree.Submodule("basic")
c.Assert(err, IsNil)

mock := newMockTransport(sm.Config().URL)

err = sm.Update(&SubmoduleUpdateOptions{
Init: true,
Transport: mock,
})

c.Assert(err, IsNil)
c.Assert(mock.NewUploadPackSessionCalled, Equals, true)
}

func (s *SubmoduleSuite) TestRepositoryWithoutInit(c *C) {
sm, err := s.Worktree.Submodule("basic")
c.Assert(err, IsNil)
Expand Down
1 change: 1 addition & 0 deletions worktree.go
Expand Up @@ -74,6 +74,7 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
fetchHead, err := remote.fetch(ctx, &FetchOptions{
RemoteName: o.RemoteName,
Depth: o.Depth,
Transport: o.Transport,
Auth: o.Auth,
Progress: o.Progress,
Force: o.Force,
Expand Down