From 67697bba2ba926954508a05628a838457b25fa0e Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Fri, 24 Sep 2021 12:32:18 -0400 Subject: Attempt to find the correct default git branch (#1217) Signed-off-by: Dave Henderson --- data/datasource_git.go | 52 +++++++++++++++++++++++++++++++++++++++++++++ data/datasource_git_test.go | 14 +++++++++--- 2 files changed, 63 insertions(+), 3 deletions(-) (limited to 'data') diff --git a/data/datasource_git.go b/data/datasource_git.go index 6c2491de..bd1811b4 100644 --- a/data/datasource_git.go +++ b/data/datasource_git.go @@ -14,12 +14,14 @@ import ( "github.com/hairyhenderson/gomplate/v3/base64" "github.com/hairyhenderson/gomplate/v3/env" + "github.com/rs/zerolog" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/memfs" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "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/plumbing/transport/http" "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/go-git/go-git/v5/storage/memory" @@ -141,6 +143,7 @@ func cloneURL(u *url.URL) *url.URL { return out } +// refFromURL - extract the ref from the URL fragment if present func (g gitsource) refFromURL(u *url.URL) plumbing.ReferenceName { switch { case strings.HasPrefix(u.Fragment, "refs/"): @@ -152,6 +155,44 @@ func (g gitsource) refFromURL(u *url.URL) plumbing.ReferenceName { } } +// refFromRemoteHead - extract the ref from the remote HEAD, to work around +// hard-coded 'master' default branch in go-git. +// Should be unnecessary once https://github.com/go-git/go-git/issues/249 is +// fixed. +func (g gitsource) refFromRemoteHead(ctx context.Context, u *url.URL, auth transport.AuthMethod) (plumbing.ReferenceName, error) { + e, err := transport.NewEndpoint(u.String()) + if err != nil { + return "", err + } + + cli, err := client.NewClient(e) + if err != nil { + return "", err + } + + s, err := cli.NewUploadPackSession(e, auth) + if err != nil { + return "", err + } + + info, err := s.AdvertisedReferencesContext(ctx) + if err != nil { + return "", err + } + + refs, err := info.AllReferences() + if err != nil { + return "", err + } + + headRef, ok := refs["HEAD"] + if !ok { + return "", fmt.Errorf("no HEAD ref found") + } + + return headRef.Target(), nil +} + // clone a repo for later reading through http(s), git, or ssh. u must be the URL to the repo // itself, and must have any file path stripped func (g gitsource) clone(ctx context.Context, repoURL *url.URL, depth int) (billy.Filesystem, *git.Repository, error) { @@ -175,6 +216,17 @@ func (g gitsource) clone(ctx context.Context, repoURL *url.URL, depth int) (bill u.Fragment = "" u.RawQuery = "" + // attempt to get the ref from the remote so we don't default to master + if ref == "" { + ref, err = g.refFromRemoteHead(ctx, u, auth) + if err != nil { + zerolog.Ctx(ctx).Warn(). + Stringer("repoURL", u). + Err(err). + Msg("failed to get ref from remote, using default") + } + } + opts := &git.CloneOptions{ URL: u.String(), Auth: auth, diff --git a/data/datasource_git_test.go b/data/datasource_git_test.go index f48393c3..33771410 100644 --- a/data/datasource_git_test.go +++ b/data/datasource_git_test.go @@ -229,10 +229,18 @@ func setupGitRepo(t *testing.T) billy.Filesystem { r, err := git.Init(s, repo) assert.NilError(t, err) + // default to main + h := plumbing.NewSymbolicReference(plumbing.HEAD, plumbing.ReferenceName("refs/heads/main")) + err = s.SetReference(h) + assert.NilError(t, err) + // config needs to be created after setting up a "normal" fs repo // this is possibly a bug in git-go? c, err := r.Config() assert.NilError(t, err) + + c.Init.DefaultBranch = "main" + s.SetConfig(c) assert.NilError(t, err) @@ -331,12 +339,12 @@ func TestOpenFileRepo(t *testing.T) { b, _ := ioutil.ReadAll(f) assert.Equal(t, "hello world", string(b)) - _, repo, err := g.clone(ctx, mustParseURL("git+file:///repo#master"), 0) + _, repo, err := g.clone(ctx, mustParseURL("git+file:///repo#main"), 0) assert.NilError(t, err) - ref, err := repo.Reference(plumbing.NewBranchReferenceName("master"), true) + ref, err := repo.Reference(plumbing.NewBranchReferenceName("main"), true) assert.NilError(t, err) - assert.Equal(t, "refs/heads/master", ref.Name().String()) + assert.Equal(t, "refs/heads/main", ref.Name().String()) _, repo, err = g.clone(ctx, mustParseURL("git+file:///repo#refs/tags/v1"), 0) assert.NilError(t, err) -- cgit v1.2.3