Skip to content

Commit

Permalink
Implements no-op before CheckoutTag in gogit
Browse files Browse the repository at this point in the history
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
  • Loading branch information
somtochiama authored and Paulo Gomes committed May 9, 2022
1 parent a5749e6 commit 07c44d9
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 12 deletions.
51 changes: 40 additions & 11 deletions pkg/git/gogit/checkout.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"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/plumbing/transport"
"github.com/go-git/go-git/v5/storage/memory"

"github.com/fluxcd/pkg/gitutil"
Expand All @@ -46,7 +47,7 @@ func CheckoutStrategyForOptions(_ context.Context, opts git.CheckoutOptions) git
case opts.SemVer != "":
return &CheckoutSemVer{SemVer: opts.SemVer, RecurseSubmodules: opts.RecurseSubmodules}
case opts.Tag != "":
return &CheckoutTag{Tag: opts.Tag, RecurseSubmodules: opts.RecurseSubmodules}
return &CheckoutTag{Tag: opts.Tag, RecurseSubmodules: opts.RecurseSubmodules, LastRevision: opts.LastRevision}
default:
branch := opts.Branch
if branch == "" {
Expand All @@ -71,19 +72,11 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g
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,
})
currentRevision, err := getLastRevision(url, ref, opts, authMethod)
if err != nil {
return nil, fmt.Errorf("unable to list remote for '%s': %w", url, err)
return nil, err
}

currentRevision := filterRefs(refs, ref)
if currentRevision != "" && currentRevision == c.LastRevision {
return nil, git.NoChangesError{
Message: "no changes since last reconcilation",
Expand Down Expand Up @@ -119,9 +112,31 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g
return buildCommitWithRef(cc, ref)
}

func getLastRevision(url string, ref plumbing.ReferenceName, opts *git.AuthOptions, authMethod transport.AuthMethod) (string, error) {
config := &config.RemoteConfig{
Name: git.DefaultOrigin,
URLs: []string{url},
}
rem := extgogit.NewRemote(memory.NewStorage(), config)
listOpts := &extgogit.ListOptions{
Auth: authMethod,
}
if opts != nil && opts.CAFile != nil {
listOpts.CABundle = opts.CAFile
}
refs, err := rem.List(listOpts)
if err != nil {
return "", fmt.Errorf("unable to list remote for '%s': %w", url, err)
}

currentRevision := filterRefs(refs, ref)
return currentRevision, nil
}

type CheckoutTag struct {
Tag string
RecurseSubmodules bool
LastRevision string
}

func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
Expand All @@ -130,6 +145,20 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.
return nil, fmt.Errorf("failed to construct auth method with options: %w", err)
}
ref := plumbing.NewTagReferenceName(c.Tag)
// check if previous revision has changed before attempting to clone
if c.LastRevision != "" {
currentRevision, err := getLastRevision(url, ref, opts, authMethod)
if err != nil {
return nil, err
}

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,
Expand Down
27 changes: 26 additions & 1 deletion pkg/git/gogit/checkout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,29 @@ func TestCheckoutTag_Checkout(t *testing.T) {
checkoutTag string
expectTag string
expectErr string
lastRev string
setLastRev bool
}{
{
name: "Tag",
tag: "tag-1",
checkoutTag: "tag-1",
expectTag: "tag-1",
},
{
name: "Skip Tag if last revision hasn't changed",
tag: "tag-2",
checkoutTag: "tag-2",
setLastRev: true,
expectErr: "no changes since last reconcilation",
},
{
name: "Last revision changed",
tag: "tag-3",
checkoutTag: "tag-3",
expectTag: "tag-3",
lastRev: "tag-3/<fake-hash>",
},
{
name: "Annotated",
tag: "annotated",
Expand All @@ -168,12 +184,13 @@ func TestCheckoutTag_Checkout(t *testing.T) {
}

var h plumbing.Hash
var tagHash *plumbing.Reference
if tt.tag != "" {
h, err = commitFile(repo, "tag", tt.tag, time.Now())
if err != nil {
t.Fatal(err)
}
_, err = tag(repo, h, !tt.annotated, tt.tag, time.Now())
tagHash, err = tag(repo, h, !tt.annotated, tt.tag, time.Now())
if err != nil {
t.Fatal(err)
}
Expand All @@ -182,10 +199,18 @@ func TestCheckoutTag_Checkout(t *testing.T) {
tag := CheckoutTag{
Tag: tt.checkoutTag,
}
if tt.setLastRev {
tag.LastRevision = fmt.Sprintf("%s/%s", tt.tag, tagHash.Hash().String())
}

if tt.lastRev != "" {
tag.LastRevision = tt.lastRev
}
tmpDir := t.TempDir()

cc, err := tag.Checkout(context.TODO(), tmpDir, path, nil)
if tt.expectErr != "" {
g.Expect(err).ToNot(BeNil())
g.Expect(err.Error()).To(ContainSubstring(tt.expectErr))
g.Expect(cc).To(BeNil())
return
Expand Down

0 comments on commit 07c44d9

Please sign in to comment.