gogit: check if revision changed before cloning in checkout branch (#694)

* Check if revision has changed in gogit CheckoutBranch

Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
This commit is contained in:
Somtochiama 2022-05-04 09:37:07 +01:00 committed by Paulo Gomes
parent 6a793a55f6
commit 8a3df9da42
No known key found for this signature in database
GPG Key ID: 9995233870E99BEE
2 changed files with 50 additions and 3 deletions

View File

@ -26,8 +26,10 @@ import (
"github.com/Masterminds/semver/v3"
extgogit "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/object"
"github.com/go-git/go-git/v5/storage/memory"
"github.com/fluxcd/pkg/gitutil"
"github.com/fluxcd/pkg/version"
@ -50,13 +52,14 @@ func CheckoutStrategyForOptions(_ context.Context, opts git.CheckoutOptions) git
if branch == "" {
branch = git.DefaultBranch
}
return &CheckoutBranch{Branch: branch, RecurseSubmodules: opts.RecurseSubmodules}
return &CheckoutBranch{Branch: branch, RecurseSubmodules: opts.RecurseSubmodules, LastRevision: opts.LastRevision}
}
}
type CheckoutBranch struct {
Branch string
RecurseSubmodules bool
LastRevision string
}
func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
@ -64,7 +67,31 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g
if err != nil {
return nil, fmt.Errorf("failed to construct auth method with options: %w", err)
}
ref := plumbing.NewBranchReferenceName(c.Branch)
// check if previous revision has changed before attempting to clone
if c.LastRevision != "" {
config := &config.RemoteConfig{
Name: git.DefaultOrigin,
URLs: []string{url},
}
rem := extgogit.NewRemote(memory.NewStorage(), config)
refs, err := rem.List(&extgogit.ListOptions{
Auth: authMethod,
})
if err != nil {
return nil, fmt.Errorf("unable to list remote for '%s': %w", url, err)
}
currentRevision := filterRefs(refs, ref)
if currentRevision != "" && currentRevision == c.LastRevision {
return nil, git.NoChangesError{
Message: "no changes since last reconcilation",
ObservedRevision: currentRevision,
}
}
}
repo, err := extgogit.PlainCloneContext(ctx, path, false, &extgogit.CloneOptions{
URL: url,
Auth: authMethod,
@ -333,3 +360,13 @@ func recurseSubmodules(recurse bool) extgogit.SubmoduleRescursivity {
}
return extgogit.NoRecurseSubmodules
}
func filterRefs(refs []*plumbing.Reference, currentRef plumbing.ReferenceName) string {
for _, ref := range refs {
if ref.Name().String() == currentRef.String() {
return fmt.Sprintf("%s/%s", currentRef.Short(), ref.Hash().String())
}
}
return ""
}

View File

@ -72,6 +72,7 @@ func TestCheckoutBranch_Checkout(t *testing.T) {
filesCreated map[string]string
expectedCommit string
expectedErr string
lastRevision string
}{
{
name: "Default branch",
@ -80,10 +81,18 @@ func TestCheckoutBranch_Checkout(t *testing.T) {
expectedCommit: firstCommit.String(),
},
{
name: "Other branch",
name: "skip clone if LastRevision hasn't changed",
branch: "master",
filesCreated: map[string]string{"branch": "init"},
expectedErr: fmt.Sprintf("no changes since last reconcilation: observed revision 'master/%s'", firstCommit.String()),
lastRevision: fmt.Sprintf("master/%s", firstCommit.String()),
},
{
name: "Other branch - revision has changed",
branch: "test",
filesCreated: map[string]string{"branch": "second"},
expectedCommit: secondCommit.String(),
lastRevision: fmt.Sprintf("master/%s", firstCommit.String()),
},
{
name: "Non existing branch",
@ -97,7 +106,8 @@ func TestCheckoutBranch_Checkout(t *testing.T) {
g := NewWithT(t)
branch := CheckoutBranch{
Branch: tt.branch,
Branch: tt.branch,
LastRevision: tt.lastRevision,
}
tmpDir := t.TempDir()