gogit: allow checkout of commit without branch
This commit changes the `gogit` behavior for commit checkouts, now allowing one to reference to just a commit while omitting any branch reference. Doing this creates an Artifact with a `HEAD/<commit>` revision. If both a `branch` and `commit` are defined, the commit is expected to exist within the branch. This results in a more efficient clone of just the target branch, and also makes this change backwards compatible. Fixes #407 Fixes #315 Signed-off-by: Hidde Beydals <hello@hidde.co>
This commit is contained in:
		
							parent
							
								
									5a1fcc213b
								
							
						
					
					
						commit
						b7376ce94c
					
				|  | @ -120,7 +120,6 @@ type GitRepositoryInclude struct { | ||||||
| // GitRepositoryRef defines the Git ref used for pull and checkout operations.
 | // GitRepositoryRef defines the Git ref used for pull and checkout operations.
 | ||||||
| type GitRepositoryRef struct { | type GitRepositoryRef struct { | ||||||
| 	// The Git branch to checkout, defaults to master.
 | 	// The Git branch to checkout, defaults to master.
 | ||||||
| 	// +kubebuilder:default:=master
 |  | ||||||
| 	// +optional
 | 	// +optional
 | ||||||
| 	Branch string `json:"branch,omitempty"` | 	Branch string `json:"branch,omitempty"` | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -91,7 +91,6 @@ spec: | ||||||
|                 description: The Git reference to checkout and monitor for changes, defaults to master branch. |                 description: The Git reference to checkout and monitor for changes, defaults to master branch. | ||||||
|                 properties: |                 properties: | ||||||
|                   branch: |                   branch: | ||||||
|                     default: master |  | ||||||
|                     description: The Git branch to checkout, defaults to master. |                     description: The Git branch to checkout, defaults to master. | ||||||
|                     type: string |                     type: string | ||||||
|                   commit: |                   commit: | ||||||
|  |  | ||||||
|  | @ -249,14 +249,15 @@ func (r *GitRepositoryReconciler) reconcile(ctx context.Context, repository sour | ||||||
| 			return sourcev1.GitRepositoryNotReady(repository, sourcev1.AuthenticationFailedReason, err.Error()), err | 			return sourcev1.GitRepositoryNotReady(repository, sourcev1.AuthenticationFailedReason, err.Error()), err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 	checkoutOpts := git.CheckoutOptions{RecurseSubmodules: repository.Spec.RecurseSubmodules} | ||||||
| 	checkoutStrategy, err := strategy.CheckoutStrategyForRef( | 	if ref := repository.Spec.Reference; ref != nil { | ||||||
| 		repository.Spec.Reference, | 		checkoutOpts.Branch = ref.Branch | ||||||
| 		git.CheckoutOptions{ | 		checkoutOpts.Commit = ref.Commit | ||||||
| 			GitImplementation: repository.Spec.GitImplementation, | 		checkoutOpts.Tag = ref.Tag | ||||||
| 			RecurseSubmodules: repository.Spec.RecurseSubmodules, | 		checkoutOpts.SemVer = ref.SemVer | ||||||
| 		}, | 	} | ||||||
| 	) | 	checkoutStrategy, err := strategy.CheckoutStrategyForImplementation(ctx, | ||||||
|  | 		git.Implementation(repository.Spec.GitImplementation), checkoutOpts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return sourcev1.GitRepositoryNotReady(repository, sourcev1.GitOperationFailedReason, err.Error()), err | 		return sourcev1.GitRepositoryNotReady(repository, sourcev1.GitOperationFailedReason, err.Error()), err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -263,7 +263,7 @@ var _ = Describe("GitRepositoryReconciler", func() { | ||||||
| 				}, | 				}, | ||||||
| 				waitForReason:  sourcev1.GitOperationSucceedReason, | 				waitForReason:  sourcev1.GitOperationSucceedReason, | ||||||
| 				expectStatus:   metav1.ConditionTrue, | 				expectStatus:   metav1.ConditionTrue, | ||||||
| 				expectRevision: "master", | 				expectRevision: "HEAD", | ||||||
| 			}), | 			}), | ||||||
| 			Entry("commit in branch", refTestCase{ | 			Entry("commit in branch", refTestCase{ | ||||||
| 				reference: &sourcev1.GitRepositoryRef{ | 				reference: &sourcev1.GitRepositoryRef{ | ||||||
|  |  | ||||||
|  | @ -26,6 +26,8 @@ import ( | ||||||
| 	"github.com/ProtonMail/go-crypto/openpgp" | 	"github.com/ProtonMail/go-crypto/openpgp" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | type Implementation string | ||||||
|  | 
 | ||||||
| type Hash []byte | type Hash []byte | ||||||
| 
 | 
 | ||||||
| // String returns the SHA1 Hash as a string.
 | // String returns the SHA1 Hash as a string.
 | ||||||
|  |  | ||||||
|  | @ -25,40 +25,38 @@ import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/Masterminds/semver/v3" | 	"github.com/Masterminds/semver/v3" | ||||||
| 	"github.com/fluxcd/pkg/gitutil" |  | ||||||
| 	"github.com/fluxcd/pkg/version" |  | ||||||
| 	extgogit "github.com/go-git/go-git/v5" | 	extgogit "github.com/go-git/go-git/v5" | ||||||
| 	"github.com/go-git/go-git/v5/plumbing" | 	"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/object" | ||||||
| 
 | 
 | ||||||
| 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" | 	"github.com/fluxcd/pkg/gitutil" | ||||||
|  | 	"github.com/fluxcd/pkg/version" | ||||||
|  | 
 | ||||||
| 	"github.com/fluxcd/source-controller/pkg/git" | 	"github.com/fluxcd/source-controller/pkg/git" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func CheckoutStrategyForRef(ref *sourcev1.GitRepositoryRef, opt git.CheckoutOptions) git.CheckoutStrategy { | // CheckoutStrategyForOptions returns the git.CheckoutStrategy for the given
 | ||||||
|  | // git.CheckoutOptions.
 | ||||||
|  | func CheckoutStrategyForOptions(_ context.Context, opts git.CheckoutOptions) git.CheckoutStrategy { | ||||||
| 	switch { | 	switch { | ||||||
| 	case ref == nil: | 	case opts.Commit != "": | ||||||
| 		return &CheckoutBranch{branch: git.DefaultBranch} | 		return &CheckoutCommit{Branch: opts.Branch, Commit: opts.Commit, RecurseSubmodules: opts.RecurseSubmodules} | ||||||
| 	case ref.SemVer != "": | 	case opts.SemVer != "": | ||||||
| 		return &CheckoutSemVer{semVer: ref.SemVer, recurseSubmodules: opt.RecurseSubmodules} | 		return &CheckoutSemVer{SemVer: opts.SemVer, RecurseSubmodules: opts.RecurseSubmodules} | ||||||
| 	case ref.Tag != "": | 	case opts.Tag != "": | ||||||
| 		return &CheckoutTag{tag: ref.Tag, recurseSubmodules: opt.RecurseSubmodules} | 		return &CheckoutTag{Tag: opts.Tag, RecurseSubmodules: opts.RecurseSubmodules} | ||||||
| 	case ref.Commit != "": |  | ||||||
| 		strategy := &CheckoutCommit{branch: ref.Branch, commit: ref.Commit, recurseSubmodules: opt.RecurseSubmodules} |  | ||||||
| 		if strategy.branch == "" { |  | ||||||
| 			strategy.branch = git.DefaultBranch |  | ||||||
| 		} |  | ||||||
| 		return strategy |  | ||||||
| 	case ref.Branch != "": |  | ||||||
| 		return &CheckoutBranch{branch: ref.Branch, recurseSubmodules: opt.RecurseSubmodules} |  | ||||||
| 	default: | 	default: | ||||||
| 		return &CheckoutBranch{branch: git.DefaultBranch} | 		branch := opts.Branch | ||||||
|  | 		if branch == "" { | ||||||
|  | 			branch = git.DefaultBranch | ||||||
|  | 		} | ||||||
|  | 		return &CheckoutBranch{Branch: branch, RecurseSubmodules: opts.RecurseSubmodules} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutBranch struct { | type CheckoutBranch struct { | ||||||
| 	branch            string | 	Branch            string | ||||||
| 	recurseSubmodules bool | 	RecurseSubmodules bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
|  | @ -66,16 +64,16 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to construct auth method with options: %w", err) | 		return nil, fmt.Errorf("failed to construct auth method with options: %w", err) | ||||||
| 	} | 	} | ||||||
| 	ref := plumbing.NewBranchReferenceName(c.branch) | 	ref := plumbing.NewBranchReferenceName(c.Branch) | ||||||
| 	repo, err := extgogit.PlainCloneContext(ctx, path, false, &extgogit.CloneOptions{ | 	repo, err := extgogit.PlainCloneContext(ctx, path, false, &extgogit.CloneOptions{ | ||||||
| 		URL:               url, | 		URL:               url, | ||||||
| 		Auth:              authMethod, | 		Auth:              authMethod, | ||||||
| 		RemoteName:        git.DefaultOrigin, | 		RemoteName:        git.DefaultOrigin, | ||||||
| 		ReferenceName:     plumbing.NewBranchReferenceName(c.branch), | 		ReferenceName:     plumbing.NewBranchReferenceName(c.Branch), | ||||||
| 		SingleBranch:      true, | 		SingleBranch:      true, | ||||||
| 		NoCheckout:        false, | 		NoCheckout:        false, | ||||||
| 		Depth:             1, | 		Depth:             1, | ||||||
| 		RecurseSubmodules: recurseSubmodules(c.recurseSubmodules), | 		RecurseSubmodules: recurseSubmodules(c.RecurseSubmodules), | ||||||
| 		Progress:          nil, | 		Progress:          nil, | ||||||
| 		Tags:              extgogit.NoTags, | 		Tags:              extgogit.NoTags, | ||||||
| 		CABundle:          caBundle(opts), | 		CABundle:          caBundle(opts), | ||||||
|  | @ -85,7 +83,7 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 	} | 	} | ||||||
| 	head, err := repo.Head() | 	head, err := repo.Head() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to resolve HEAD of branch '%s': %w", c.branch, err) | 		return nil, fmt.Errorf("failed to resolve HEAD of branch '%s': %w", c.Branch, err) | ||||||
| 	} | 	} | ||||||
| 	cc, err := repo.CommitObject(head.Hash()) | 	cc, err := repo.CommitObject(head.Hash()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -95,8 +93,8 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutTag struct { | type CheckoutTag struct { | ||||||
| 	tag               string | 	Tag               string | ||||||
| 	recurseSubmodules bool | 	RecurseSubmodules bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
|  | @ -104,16 +102,16 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git. | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to construct auth method with options: %w", err) | 		return nil, fmt.Errorf("failed to construct auth method with options: %w", err) | ||||||
| 	} | 	} | ||||||
| 	ref := plumbing.NewTagReferenceName(c.tag) | 	ref := plumbing.NewTagReferenceName(c.Tag) | ||||||
| 	repo, err := extgogit.PlainCloneContext(ctx, path, false, &extgogit.CloneOptions{ | 	repo, err := extgogit.PlainCloneContext(ctx, path, false, &extgogit.CloneOptions{ | ||||||
| 		URL:               url, | 		URL:               url, | ||||||
| 		Auth:              authMethod, | 		Auth:              authMethod, | ||||||
| 		RemoteName:        git.DefaultOrigin, | 		RemoteName:        git.DefaultOrigin, | ||||||
| 		ReferenceName:     plumbing.NewTagReferenceName(c.tag), | 		ReferenceName:     plumbing.NewTagReferenceName(c.Tag), | ||||||
| 		SingleBranch:      true, | 		SingleBranch:      true, | ||||||
| 		NoCheckout:        false, | 		NoCheckout:        false, | ||||||
| 		Depth:             1, | 		Depth:             1, | ||||||
| 		RecurseSubmodules: recurseSubmodules(c.recurseSubmodules), | 		RecurseSubmodules: recurseSubmodules(c.RecurseSubmodules), | ||||||
| 		Progress:          nil, | 		Progress:          nil, | ||||||
| 		Tags:              extgogit.NoTags, | 		Tags:              extgogit.NoTags, | ||||||
| 		CABundle:          caBundle(opts), | 		CABundle:          caBundle(opts), | ||||||
|  | @ -123,7 +121,7 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git. | ||||||
| 	} | 	} | ||||||
| 	head, err := repo.Head() | 	head, err := repo.Head() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to resolve HEAD of tag '%s': %w", c.tag, err) | 		return nil, fmt.Errorf("failed to resolve HEAD of tag '%s': %w", c.Tag, err) | ||||||
| 	} | 	} | ||||||
| 	cc, err := repo.CommitObject(head.Hash()) | 	cc, err := repo.CommitObject(head.Hash()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -133,9 +131,9 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git. | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutCommit struct { | type CheckoutCommit struct { | ||||||
| 	branch            string | 	Branch            string | ||||||
| 	commit            string | 	Commit            string | ||||||
| 	recurseSubmodules bool | 	RecurseSubmodules bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
|  | @ -143,19 +141,22 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to construct auth method with options: %w", err) | 		return nil, fmt.Errorf("failed to construct auth method with options: %w", err) | ||||||
| 	} | 	} | ||||||
| 	ref := plumbing.NewBranchReferenceName(c.branch) | 	cloneOpts := &extgogit.CloneOptions{ | ||||||
| 	repo, err := extgogit.PlainCloneContext(ctx, path, false, &extgogit.CloneOptions{ |  | ||||||
| 		URL:               url, | 		URL:               url, | ||||||
| 		Auth:              authMethod, | 		Auth:              authMethod, | ||||||
| 		RemoteName:        git.DefaultOrigin, | 		RemoteName:        git.DefaultOrigin, | ||||||
| 		ReferenceName:     ref, | 		SingleBranch:      false, | ||||||
| 		SingleBranch:      true, | 		NoCheckout:        true, | ||||||
| 		NoCheckout:        false, | 		RecurseSubmodules: recurseSubmodules(c.RecurseSubmodules), | ||||||
| 		RecurseSubmodules: recurseSubmodules(c.recurseSubmodules), |  | ||||||
| 		Progress:          nil, | 		Progress:          nil, | ||||||
| 		Tags:              extgogit.NoTags, | 		Tags:              extgogit.NoTags, | ||||||
| 		CABundle:          caBundle(opts), | 		CABundle:          caBundle(opts), | ||||||
| 	}) | 	} | ||||||
|  | 	if c.Branch != "" { | ||||||
|  | 		cloneOpts.SingleBranch = true | ||||||
|  | 		cloneOpts.ReferenceName = plumbing.NewBranchReferenceName(c.Branch) | ||||||
|  | 	} | ||||||
|  | 	repo, err := extgogit.PlainCloneContext(ctx, path, false, cloneOpts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.GoGitError(err)) | 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.GoGitError(err)) | ||||||
| 	} | 	} | ||||||
|  | @ -163,29 +164,27 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to open Git worktree: %w", err) | 		return nil, fmt.Errorf("failed to open Git worktree: %w", err) | ||||||
| 	} | 	} | ||||||
| 	f, _ := repo.Head() | 	cc, err := repo.CommitObject(plumbing.NewHash(c.Commit)) | ||||||
| 	f.String() |  | ||||||
| 	cc, err := repo.CommitObject(plumbing.NewHash(c.commit)) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to resolve commit object for '%s': %w", c.commit, err) | 		return nil, fmt.Errorf("failed to resolve commit object for '%s': %w", c.Commit, err) | ||||||
| 	} | 	} | ||||||
| 	err = w.Checkout(&extgogit.CheckoutOptions{ | 	err = w.Checkout(&extgogit.CheckoutOptions{ | ||||||
| 		Hash:  cc.Hash, | 		Hash:  cc.Hash, | ||||||
| 		Force: true, | 		Force: true, | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to checkout commit '%s': %w", c.commit, err) | 		return nil, fmt.Errorf("failed to checkout commit '%s': %w", c.Commit, err) | ||||||
| 	} | 	} | ||||||
| 	return commitWithRef(cc, ref) | 	return commitWithRef(cc, cloneOpts.ReferenceName) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutSemVer struct { | type CheckoutSemVer struct { | ||||||
| 	semVer            string | 	SemVer            string | ||||||
| 	recurseSubmodules bool | 	RecurseSubmodules bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
| 	verConstraint, err := semver.NewConstraint(c.semVer) | 	verConstraint, err := semver.NewConstraint(c.SemVer) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("semver parse error: %w", err) | 		return nil, fmt.Errorf("semver parse error: %w", err) | ||||||
| 	} | 	} | ||||||
|  | @ -201,7 +200,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 		RemoteName:        git.DefaultOrigin, | 		RemoteName:        git.DefaultOrigin, | ||||||
| 		NoCheckout:        false, | 		NoCheckout:        false, | ||||||
| 		Depth:             1, | 		Depth:             1, | ||||||
| 		RecurseSubmodules: recurseSubmodules(c.recurseSubmodules), | 		RecurseSubmodules: recurseSubmodules(c.RecurseSubmodules), | ||||||
| 		Progress:          nil, | 		Progress:          nil, | ||||||
| 		Tags:              extgogit.AllTags, | 		Tags:              extgogit.AllTags, | ||||||
| 		CABundle:          caBundle(opts), | 		CABundle:          caBundle(opts), | ||||||
|  | @ -247,7 +246,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 		matchedVersions = append(matchedVersions, v) | 		matchedVersions = append(matchedVersions, v) | ||||||
| 	} | 	} | ||||||
| 	if len(matchedVersions) == 0 { | 	if len(matchedVersions) == 0 { | ||||||
| 		return nil, fmt.Errorf("no match found for semver: %s", c.semVer) | 		return nil, fmt.Errorf("no match found for semver: %s", c.SemVer) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Sort versions
 | 	// Sort versions
 | ||||||
|  |  | ||||||
|  | @ -83,7 +83,7 @@ func TestCheckoutBranch_Checkout(t *testing.T) { | ||||||
| 			g := NewWithT(t) | 			g := NewWithT(t) | ||||||
| 
 | 
 | ||||||
| 			branch := CheckoutBranch{ | 			branch := CheckoutBranch{ | ||||||
| 				branch: tt.branch, | 				Branch: tt.branch, | ||||||
| 			} | 			} | ||||||
| 			tmpDir, _ := os.MkdirTemp("", "test") | 			tmpDir, _ := os.MkdirTemp("", "test") | ||||||
| 			defer os.RemoveAll(tmpDir) | 			defer os.RemoveAll(tmpDir) | ||||||
|  | @ -152,7 +152,7 @@ func TestCheckoutTag_Checkout(t *testing.T) { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			tag := CheckoutTag{ | 			tag := CheckoutTag{ | ||||||
| 				tag: tt.checkoutTag, | 				Tag: tt.checkoutTag, | ||||||
| 			} | 			} | ||||||
| 			tmpDir, _ := os.MkdirTemp("", "test") | 			tmpDir, _ := os.MkdirTemp("", "test") | ||||||
| 			defer os.RemoveAll(tmpDir) | 			defer os.RemoveAll(tmpDir) | ||||||
|  | @ -173,46 +173,87 @@ func TestCheckoutTag_Checkout(t *testing.T) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestCheckoutCommit_Checkout(t *testing.T) { | func TestCheckoutCommit_Checkout(t *testing.T) { | ||||||
| 	g := NewWithT(t) |  | ||||||
| 
 |  | ||||||
| 	repo, path, err := initRepo() | 	repo, path, err := initRepo() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	defer os.RemoveAll(path) | 	defer os.RemoveAll(path) | ||||||
| 
 | 
 | ||||||
| 	c, err := commitFile(repo, "commit", "init", time.Now()) | 	firstCommit, err := commitFile(repo, "commit", "init", time.Now()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	if _, err = commitFile(repo, "commit", "second", time.Now()); err != nil { | 	if err = createBranch(repo, "other-branch"); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	secondCommit, err := commitFile(repo, "commit", "second", time.Now()) | ||||||
|  | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	commit := CheckoutCommit{ | 	tests := []struct { | ||||||
| 		commit: c.String(), | 		name         string | ||||||
|  | 		commit       string | ||||||
|  | 		branch       string | ||||||
|  | 		expectCommit string | ||||||
|  | 		expectFile   string | ||||||
|  | 		expectError  string | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			name:         "Commit", | ||||||
|  | 			commit:       firstCommit.String(), | ||||||
|  | 			expectCommit: "HEAD/" + firstCommit.String(), | ||||||
|  | 			expectFile:   "init", | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:         "Commit in specific branch", | ||||||
|  | 			commit:       secondCommit.String(), | ||||||
|  | 			branch:       "other-branch", | ||||||
|  | 			expectCommit: "other-branch/" + secondCommit.String(), | ||||||
|  | 			expectFile:   "second", | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Non existing commit", | ||||||
|  | 			commit:      "a-random-invalid-commit", | ||||||
|  | 			expectError: "failed to resolve commit object for 'a-random-invalid-commit': object not found", | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:        "Non existing commit in specific branch", | ||||||
|  | 			commit:      secondCommit.String(), | ||||||
| 			branch:      "master", | 			branch:      "master", | ||||||
|  | 			expectError: "object not found", | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	for _, tt := range tests { | ||||||
|  | 		t.Run(tt.name, func(t *testing.T) { | ||||||
|  | 			g := NewWithT(t) | ||||||
|  | 
 | ||||||
|  | 			commit := CheckoutCommit{ | ||||||
|  | 				Commit: tt.commit, | ||||||
|  | 				Branch: tt.branch, | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			tmpDir, err := os.MkdirTemp("", "git2go") | ||||||
|  | 			if err != nil { | ||||||
|  | 				t.Fatal(err) | ||||||
| 			} | 			} | ||||||
| 	tmpDir, _ := os.MkdirTemp("", "git2go") |  | ||||||
| 			defer os.RemoveAll(tmpDir) | 			defer os.RemoveAll(tmpDir) | ||||||
| 
 | 
 | ||||||
| 			cc, err := commit.Checkout(context.TODO(), tmpDir, path, nil) | 			cc, err := commit.Checkout(context.TODO(), tmpDir, path, nil) | ||||||
| 	g.Expect(err).ToNot(HaveOccurred()) | 			if tt.expectError != "" { | ||||||
| 	g.Expect(cc.String()).To(Equal("master" + "/" + c.String())) |  | ||||||
| 	g.Expect(filepath.Join(tmpDir, "commit")).To(BeARegularFile()) |  | ||||||
| 	g.Expect(os.ReadFile(filepath.Join(tmpDir, "commit"))).To(BeEquivalentTo("init")) |  | ||||||
| 
 |  | ||||||
| 	commit = CheckoutCommit{ |  | ||||||
| 		commit: "4dc3185c5fc94eb75048376edeb44571cece25f4", |  | ||||||
| 		branch: "master", |  | ||||||
| 	} |  | ||||||
| 	tmpDir2, _ := os.MkdirTemp("", "git2go") |  | ||||||
| 	defer os.RemoveAll(tmpDir) |  | ||||||
| 
 |  | ||||||
| 	cc, err = commit.Checkout(context.TODO(), tmpDir2, path, nil) |  | ||||||
| 				g.Expect(err).To(HaveOccurred()) | 				g.Expect(err).To(HaveOccurred()) | ||||||
| 	g.Expect(err.Error()).To(ContainSubstring("object not found")) | 				g.Expect(err.Error()).To(ContainSubstring(tt.expectError)) | ||||||
| 				g.Expect(cc).To(BeNil()) | 				g.Expect(cc).To(BeNil()) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			g.Expect(err).ToNot(HaveOccurred()) | ||||||
|  | 			g.Expect(cc).ToNot(BeNil()) | ||||||
|  | 			g.Expect(cc.String()).To(Equal(tt.expectCommit)) | ||||||
|  | 			g.Expect(filepath.Join(tmpDir, "commit")).To(BeARegularFile()) | ||||||
|  | 			g.Expect(os.ReadFile(filepath.Join(tmpDir, "commit"))).To(BeEquivalentTo(tt.expectFile)) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestCheckoutTagSemVer_Checkout(t *testing.T) { | func TestCheckoutTagSemVer_Checkout(t *testing.T) { | ||||||
|  | @ -300,7 +341,7 @@ func TestCheckoutTagSemVer_Checkout(t *testing.T) { | ||||||
| 			g := NewWithT(t) | 			g := NewWithT(t) | ||||||
| 
 | 
 | ||||||
| 			semVer := CheckoutSemVer{ | 			semVer := CheckoutSemVer{ | ||||||
| 				semVer: tt.constraint, | 				SemVer: tt.constraint, | ||||||
| 			} | 			} | ||||||
| 			tmpDir, _ := os.MkdirTemp("", "test") | 			tmpDir, _ := os.MkdirTemp("", "test") | ||||||
| 			defer os.RemoveAll(tmpDir) | 			defer os.RemoveAll(tmpDir) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | /* | ||||||
|  | Copyright 2021 The Flux authors | ||||||
|  | 
 | ||||||
|  | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | you may not use this file except in compliance with the License. | ||||||
|  | You may obtain a copy of the License at | ||||||
|  | 
 | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | 
 | ||||||
|  | Unless required by applicable law or agreed to in writing, software | ||||||
|  | distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | See the License for the specific language governing permissions and | ||||||
|  | limitations under the License. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | package gogit | ||||||
|  | 
 | ||||||
|  | import "github.com/fluxcd/source-controller/pkg/git" | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	Implementation git.Implementation = "go-git" | ||||||
|  | ) | ||||||
|  | @ -24,38 +24,39 @@ import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/Masterminds/semver/v3" | 	"github.com/Masterminds/semver/v3" | ||||||
|  | 	"github.com/go-logr/logr" | ||||||
| 	git2go "github.com/libgit2/git2go/v31" | 	git2go "github.com/libgit2/git2go/v31" | ||||||
| 
 | 
 | ||||||
| 	"github.com/fluxcd/pkg/gitutil" | 	"github.com/fluxcd/pkg/gitutil" | ||||||
| 	"github.com/fluxcd/pkg/version" | 	"github.com/fluxcd/pkg/version" | ||||||
| 
 | 
 | ||||||
| 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" |  | ||||||
| 	"github.com/fluxcd/source-controller/pkg/git" | 	"github.com/fluxcd/source-controller/pkg/git" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func CheckoutStrategyForRef(ref *sourcev1.GitRepositoryRef, opt git.CheckoutOptions) git.CheckoutStrategy { | // CheckoutStrategyForOptions returns the git.CheckoutStrategy for the given
 | ||||||
| 	switch { | // git.CheckoutOptions.
 | ||||||
| 	case ref == nil: | func CheckoutStrategyForOptions(ctx context.Context, opt git.CheckoutOptions) git.CheckoutStrategy { | ||||||
| 		return &CheckoutBranch{branch: git.DefaultBranch} | 	if opt.RecurseSubmodules { | ||||||
| 	case ref.SemVer != "": | 		logr.FromContextOrDiscard(ctx).Info("git submodule recursion not supported by '%s'", Implementation) | ||||||
| 		return &CheckoutSemVer{semVer: ref.SemVer} |  | ||||||
| 	case ref.Tag != "": |  | ||||||
| 		return &CheckoutTag{tag: ref.Tag} |  | ||||||
| 	case ref.Commit != "": |  | ||||||
| 		strategy := &CheckoutCommit{branch: ref.Branch, commit: ref.Commit} |  | ||||||
| 		if strategy.branch == "" { |  | ||||||
| 			strategy.branch = git.DefaultBranch |  | ||||||
| 	} | 	} | ||||||
| 		return strategy | 	switch { | ||||||
| 	case ref.Branch != "": | 	case opt.Commit != "": | ||||||
| 		return &CheckoutBranch{branch: ref.Branch} | 		return &CheckoutCommit{Commit: opt.Commit} | ||||||
|  | 	case opt.SemVer != "": | ||||||
|  | 		return &CheckoutSemVer{SemVer: opt.SemVer} | ||||||
|  | 	case opt.Tag != "": | ||||||
|  | 		return &CheckoutTag{Tag: opt.Tag} | ||||||
| 	default: | 	default: | ||||||
| 		return &CheckoutBranch{branch: git.DefaultBranch} | 		branch := opt.Branch | ||||||
|  | 		if branch == "" { | ||||||
|  | 			branch = git.DefaultBranch | ||||||
|  | 		} | ||||||
|  | 		return &CheckoutBranch{Branch: branch} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutBranch struct { | type CheckoutBranch struct { | ||||||
| 	branch string | 	Branch string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
|  | @ -64,7 +65,7 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 			DownloadTags:    git2go.DownloadTagsNone, | 			DownloadTags:    git2go.DownloadTagsNone, | ||||||
| 			RemoteCallbacks: remoteCallbacks(opts), | 			RemoteCallbacks: remoteCallbacks(opts), | ||||||
| 		}, | 		}, | ||||||
| 		CheckoutBranch: c.branch, | 		CheckoutBranch: c.Branch, | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) | 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) | ||||||
|  | @ -77,14 +78,14 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 	defer head.Free() | 	defer head.Free() | ||||||
| 	cc, err := repo.LookupCommit(head.Target()) | 	cc, err := repo.LookupCommit(head.Target()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("could not find commit '%s' in branch '%s': %w", head.Target(), c.branch, err) | 		return nil, fmt.Errorf("could not find commit '%s' in branch '%s': %w", head.Target(), c.Branch, err) | ||||||
| 	} | 	} | ||||||
| 	defer cc.Free() | 	defer cc.Free() | ||||||
| 	return commit(cc, "refs/heads/"+c.branch), nil | 	return commit(cc, "refs/heads/"+c.Branch), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutTag struct { | type CheckoutTag struct { | ||||||
| 	tag string | 	Tag string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
|  | @ -98,17 +99,16 @@ func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git. | ||||||
| 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) | 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) | ||||||
| 	} | 	} | ||||||
| 	defer repo.Free() | 	defer repo.Free() | ||||||
| 	cc, err := checkoutDetachedDwim(repo, c.tag) | 	cc, err := checkoutDetachedDwim(repo, c.Tag) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	defer cc.Free() | 	defer cc.Free() | ||||||
| 	return commit(cc, "refs/tags/"+c.tag), nil | 	return commit(cc, "refs/tags/"+c.Tag), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutCommit struct { | type CheckoutCommit struct { | ||||||
| 	branch string | 	Commit string | ||||||
| 	commit string |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
|  | @ -122,9 +122,9 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) | 		return nil, fmt.Errorf("unable to clone '%s', error: %w", url, gitutil.LibGit2Error(err)) | ||||||
| 	} | 	} | ||||||
| 	defer repo.Free() | 	defer repo.Free() | ||||||
| 	oid, err := git2go.NewOid(c.commit) | 	oid, err := git2go.NewOid(c.Commit) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("could not create oid for '%s': %w", c.commit, err) | 		return nil, fmt.Errorf("could not create oid for '%s': %w", c.Commit, err) | ||||||
| 	} | 	} | ||||||
| 	cc, err := checkoutDetachedHEAD(repo, oid) | 	cc, err := checkoutDetachedHEAD(repo, oid) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -134,11 +134,11 @@ func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type CheckoutSemVer struct { | type CheckoutSemVer struct { | ||||||
| 	semVer string | 	SemVer string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) { | ||||||
| 	verConstraint, err := semver.NewConstraint(c.semVer) | 	verConstraint, err := semver.NewConstraint(c.SemVer) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("semver parse error: %w", err) | 		return nil, fmt.Errorf("semver parse error: %w", err) | ||||||
| 	} | 	} | ||||||
|  | @ -202,7 +202,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g | ||||||
| 		matchedVersions = append(matchedVersions, v) | 		matchedVersions = append(matchedVersions, v) | ||||||
| 	} | 	} | ||||||
| 	if len(matchedVersions) == 0 { | 	if len(matchedVersions) == 0 { | ||||||
| 		return nil, fmt.Errorf("no match found for semver: %s", c.semVer) | 		return nil, fmt.Errorf("no match found for semver: %s", c.SemVer) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Sort versions
 | 	// Sort versions
 | ||||||
|  |  | ||||||
|  | @ -77,7 +77,7 @@ func TestCheckoutBranch_Checkout(t *testing.T) { | ||||||
| 			g := NewWithT(t) | 			g := NewWithT(t) | ||||||
| 
 | 
 | ||||||
| 			branch := CheckoutBranch{ | 			branch := CheckoutBranch{ | ||||||
| 				branch: tt.branch, | 				Branch: tt.branch, | ||||||
| 			} | 			} | ||||||
| 			tmpDir, _ := os.MkdirTemp("", "test") | 			tmpDir, _ := os.MkdirTemp("", "test") | ||||||
| 			defer os.RemoveAll(tmpDir) | 			defer os.RemoveAll(tmpDir) | ||||||
|  | @ -148,7 +148,7 @@ func TestCheckoutTag_Checkout(t *testing.T) { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			tag := CheckoutTag{ | 			tag := CheckoutTag{ | ||||||
| 				tag: tt.checkoutTag, | 				Tag: tt.checkoutTag, | ||||||
| 			} | 			} | ||||||
| 			tmpDir, _ := os.MkdirTemp("", "test") | 			tmpDir, _ := os.MkdirTemp("", "test") | ||||||
| 			defer os.RemoveAll(tmpDir) | 			defer os.RemoveAll(tmpDir) | ||||||
|  | @ -188,8 +188,7 @@ func TestCheckoutCommit_Checkout(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	commit := CheckoutCommit{ | 	commit := CheckoutCommit{ | ||||||
| 		commit: c.String(), | 		Commit: c.String(), | ||||||
| 		branch: "main", |  | ||||||
| 	} | 	} | ||||||
| 	tmpDir, _ := os.MkdirTemp("", "git2go") | 	tmpDir, _ := os.MkdirTemp("", "git2go") | ||||||
| 	defer os.RemoveAll(tmpDir) | 	defer os.RemoveAll(tmpDir) | ||||||
|  | @ -202,7 +201,7 @@ func TestCheckoutCommit_Checkout(t *testing.T) { | ||||||
| 	g.Expect(os.ReadFile(filepath.Join(tmpDir, "commit"))).To(BeEquivalentTo("init")) | 	g.Expect(os.ReadFile(filepath.Join(tmpDir, "commit"))).To(BeEquivalentTo("init")) | ||||||
| 
 | 
 | ||||||
| 	commit = CheckoutCommit{ | 	commit = CheckoutCommit{ | ||||||
| 		commit: "4dc3185c5fc94eb75048376edeb44571cece25f4", | 		Commit: "4dc3185c5fc94eb75048376edeb44571cece25f4", | ||||||
| 	} | 	} | ||||||
| 	tmpDir2, _ := os.MkdirTemp("", "git2go") | 	tmpDir2, _ := os.MkdirTemp("", "git2go") | ||||||
| 	defer os.RemoveAll(tmpDir) | 	defer os.RemoveAll(tmpDir) | ||||||
|  | @ -309,7 +308,7 @@ func TestCheckoutTagSemVer_Checkout(t *testing.T) { | ||||||
| 			g := NewWithT(t) | 			g := NewWithT(t) | ||||||
| 
 | 
 | ||||||
| 			semVer := CheckoutSemVer{ | 			semVer := CheckoutSemVer{ | ||||||
| 				semVer: tt.constraint, | 				SemVer: tt.constraint, | ||||||
| 			} | 			} | ||||||
| 			tmpDir, _ := os.MkdirTemp("", "test") | 			tmpDir, _ := os.MkdirTemp("", "test") | ||||||
| 			defer os.RemoveAll(tmpDir) | 			defer os.RemoveAll(tmpDir) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | /* | ||||||
|  | Copyright 2021 The Flux authors | ||||||
|  | 
 | ||||||
|  | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | you may not use this file except in compliance with the License. | ||||||
|  | You may obtain a copy of the License at | ||||||
|  | 
 | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | 
 | ||||||
|  | Unless required by applicable law or agreed to in writing, software | ||||||
|  | distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | See the License for the specific language governing permissions and | ||||||
|  | limitations under the License. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | package libgit2 | ||||||
|  | 
 | ||||||
|  | import "github.com/fluxcd/source-controller/pkg/git" | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	Implementation git.Implementation = "libgit2" | ||||||
|  | ) | ||||||
|  | @ -32,7 +32,22 @@ const ( | ||||||
| 
 | 
 | ||||||
| // CheckoutOptions are the options used for a Git checkout.
 | // CheckoutOptions are the options used for a Git checkout.
 | ||||||
| type CheckoutOptions struct { | type CheckoutOptions struct { | ||||||
| 	GitImplementation string | 	// Branch to checkout, can be combined with Branch with some
 | ||||||
|  | 	// Implementations.
 | ||||||
|  | 	Branch string | ||||||
|  | 
 | ||||||
|  | 	// Tag to checkout, takes precedence over Branch.
 | ||||||
|  | 	Tag string | ||||||
|  | 
 | ||||||
|  | 	// SemVer tag expression to checkout, takes precedence over Tag.
 | ||||||
|  | 	SemVer string `json:"semver,omitempty"` | ||||||
|  | 
 | ||||||
|  | 	// Commit SHA1 to checkout, takes precedence over Tag and SemVer,
 | ||||||
|  | 	// can be combined with Branch with some Implementations.
 | ||||||
|  | 	Commit string | ||||||
|  | 
 | ||||||
|  | 	// RecurseSubmodules defines if submodules should be checked out,
 | ||||||
|  | 	// not supported by all Implementations.
 | ||||||
| 	RecurseSubmodules bool | 	RecurseSubmodules bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,21 +17,23 @@ limitations under the License. | ||||||
| package strategy | package strategy | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 
 | 
 | ||||||
| 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" |  | ||||||
| 	"github.com/fluxcd/source-controller/pkg/git" | 	"github.com/fluxcd/source-controller/pkg/git" | ||||||
| 	"github.com/fluxcd/source-controller/pkg/git/gogit" | 	"github.com/fluxcd/source-controller/pkg/git/gogit" | ||||||
| 	"github.com/fluxcd/source-controller/pkg/git/libgit2" | 	"github.com/fluxcd/source-controller/pkg/git/libgit2" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func CheckoutStrategyForRef(ref *sourcev1.GitRepositoryRef, opt git.CheckoutOptions) (git.CheckoutStrategy, error) { | // CheckoutStrategyForImplementation returns the CheckoutStrategy for the given
 | ||||||
| 	switch opt.GitImplementation { | // git.Implementation and git.CheckoutOptions.
 | ||||||
| 	case sourcev1.GoGitImplementation: | func CheckoutStrategyForImplementation(ctx context.Context, impl git.Implementation, opts git.CheckoutOptions) (git.CheckoutStrategy, error) { | ||||||
| 		return gogit.CheckoutStrategyForRef(ref, opt), nil | 	switch impl { | ||||||
| 	case sourcev1.LibGit2Implementation: | 	case gogit.Implementation: | ||||||
| 		return libgit2.CheckoutStrategyForRef(ref, opt), nil | 		return gogit.CheckoutStrategyForOptions(ctx, opts), nil | ||||||
|  | 	case libgit2.Implementation: | ||||||
|  | 		return libgit2.CheckoutStrategyForOptions(ctx, opts), nil | ||||||
| 	default: | 	default: | ||||||
| 		return nil, fmt.Errorf("unsupported Git implementation %s", opt.GitImplementation) | 		return nil, fmt.Errorf("unsupported Git implementation '%s'", impl) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue