diff --git a/pkg/git/remote_git_resolver.go b/pkg/git/remote_git_resolver.go index af263f840..a36bdda44 100644 --- a/pkg/git/remote_git_resolver.go +++ b/pkg/git/remote_git_resolver.go @@ -2,29 +2,26 @@ package git import ( gogit "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/storage/memory" - corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1" + "regexp" + "strings" ) -const defaultRemote = "origin" - type remoteGitResolver struct{} func (*remoteGitResolver) Resolve(auth transport.AuthMethod, sourceConfig corev1alpha1.SourceConfig) (corev1alpha1.ResolvedSourceConfig, error) { - remote := gogit.NewRemote(memory.NewStorage(), &config.RemoteConfig{ - Name: defaultRemote, - URLs: []string{sourceConfig.Git.URL}, - }) + var resolvedConfig corev1alpha1.ResolvedSourceConfig - refs, err := remote.List(&gogit.ListOptions{ + r, err := gogit.Clone(memory.NewStorage(), nil, &gogit.CloneOptions{ + URL: sourceConfig.Git.URL, Auth: auth, }) + if err != nil { - return corev1alpha1.ResolvedSourceConfig{ + resolvedConfig = corev1alpha1.ResolvedSourceConfig{ Git: &corev1alpha1.ResolvedGitSource{ URL: sourceConfig.Git.URL, Revision: sourceConfig.Git.Revision, @@ -32,32 +29,68 @@ func (*remoteGitResolver) Resolve(auth transport.AuthMethod, sourceConfig corev1 SubPath: sourceConfig.SubPath, InitializeSubmodules: sourceConfig.Git.InitializeSubmodules, }, - }, nil + } } - for _, ref := range refs { + rIter, _ := r.References() + + rIter.ForEach(func(ref *plumbing.Reference) error { if ref.Name().Short() == sourceConfig.Git.Revision { - return corev1alpha1.ResolvedSourceConfig{ + refSourceType := sourceType(ref) + effectiveCommit := "" + + if refSourceType == corev1alpha1.Branch { + effectiveCommit, err = getLogs(r, sourceConfig.SubPath) + } else { + effectiveCommit = ref.Hash().String() + } + + if err != nil { + return nil + } + + resolvedConfig = corev1alpha1.ResolvedSourceConfig{ Git: &corev1alpha1.ResolvedGitSource{ - URL: sourceConfig.Git.URL, - Revision: ref.Hash().String(), - Type: sourceType(ref), - SubPath: sourceConfig.SubPath, - InitializeSubmodules: sourceConfig.Git.InitializeSubmodules, + URL: sourceConfig.Git.URL, + Revision: effectiveCommit, + Type: refSourceType, + SubPath: sourceConfig.SubPath, }, - }, nil + } + } + return nil + }) + + if resolvedConfig.ResolvedSource() == nil { + resolvedConfig = corev1alpha1.ResolvedSourceConfig{ + Git: &corev1alpha1.ResolvedGitSource{ + URL: sourceConfig.Git.URL, + Revision: sourceConfig.Git.Revision, + Type: corev1alpha1.Commit, + SubPath: sourceConfig.SubPath, + }, } } - return corev1alpha1.ResolvedSourceConfig{ - Git: &corev1alpha1.ResolvedGitSource{ - URL: sourceConfig.Git.URL, - Revision: sourceConfig.Git.Revision, - Type: corev1alpha1.Commit, - SubPath: sourceConfig.SubPath, - InitializeSubmodules: sourceConfig.Git.InitializeSubmodules, + return resolvedConfig, err +} + +func getLogs(r *gogit.Repository, subPath string) (string, error) { + logOutput, err := r.Log(&gogit.LogOptions{ + PathFilter: func(s string) bool { + if strings.Contains(s, subPath) { + return true + } else { + return false + } }, - }, nil + }) + + latestCommit, err := logOutput.Next() + regex, _ := regexp.Compile("[a-f0-9]{40}") + effectiveCommit := regex.FindString(latestCommit.String()) + + return effectiveCommit, err } func sourceType(reference *plumbing.Reference) corev1alpha1.GitSourceKind { diff --git a/pkg/git/remote_git_resolver_test.go b/pkg/git/remote_git_resolver_test.go index 2b54fe205..0b7baaa67 100644 --- a/pkg/git/remote_git_resolver_test.go +++ b/pkg/git/remote_git_resolver_test.go @@ -17,11 +17,12 @@ func TestRemoteGitResolver(t *testing.T) { func testRemoteGitResolver(t *testing.T, when spec.G, it spec.S) { const ( - url = "https://github.com/git-fixtures/basic.git" - nonHEADCommit = "a755256fc0a57241b92167eb748b333449a3d7e9" - fixtureHEADMasterCommit = "6ecf0ef2c2dffb796033e5a02219af86ec6584e5" - tag = "commit-tag" - tagCommit = "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc" + url = "https://github.com/git-fixtures/basic.git" + nonHEADCommit = "a755256fc0a57241b92167eb748b333449a3d7e9" + fixtureHEADMasterCommit = "6ecf0ef2c2dffb796033e5a02219af86ec6584e5" + fixtureHEADMasterEffectiveCommit = "918c48b83bd081e863dbe1b80f8998f058cd8294" + tag = "commit-tag" + tagCommit = "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc" ) when("#Resolve", func() { @@ -49,7 +50,7 @@ func testRemoteGitResolver(t *testing.T, when spec.G, it spec.S) { }) }) - when("source is a branch", func() { + when("source is a branch with latest commit", func() { it("returns branch with resolved commit", func() { gitResolver := remoteGitResolver{} @@ -58,7 +59,6 @@ func testRemoteGitResolver(t *testing.T, when spec.G, it spec.S) { URL: url, Revision: "master", }, - SubPath: "/foo/bar", }) require.NoError(t, err) @@ -67,7 +67,30 @@ func testRemoteGitResolver(t *testing.T, when spec.G, it spec.S) { URL: url, Revision: fixtureHEADMasterCommit, Type: corev1alpha1.Branch, - SubPath: "/foo/bar", + }, + }, resolvedGitSource) + }) + }) + + when("source is a branch with older subpath", func() { + it("returns branch with resolved commit", func() { + gitResolver := remoteGitResolver{} + + resolvedGitSource, err := gitResolver.Resolve(anonymousAuth, corev1alpha1.SourceConfig{ + Git: &corev1alpha1.Git{ + URL: url, + Revision: "master", + }, + SubPath: "go/", + }) + require.NoError(t, err) + + assert.Equal(t, corev1alpha1.ResolvedSourceConfig{ + Git: &corev1alpha1.ResolvedGitSource{ + URL: url, + Revision: fixtureHEADMasterEffectiveCommit, + Type: corev1alpha1.Branch, + SubPath: "go/", }, }, resolvedGitSource) })