@@ -34,7 +34,6 @@ import (
3434
3535 "github.com/ProtonMail/go-crypto/openpgp"
3636 securejoin "github.com/cyphar/filepath-securejoin"
37- "github.com/go-git/go-git/v5/config"
3837 "github.com/go-git/go-git/v5/plumbing"
3938 "github.com/go-git/go-git/v5/plumbing/object"
4039 "github.com/go-logr/logr"
@@ -214,15 +213,15 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(ctx context.Context, req ctr
214213 }
215214
216215 var repo * gogit.Repository
217- if repo , err = cloneInto (ctx , access , ref , tmp , origin . Spec . GitImplementation ); err != nil {
216+ if repo , err = cloneInto (ctx , access , ref , tmp ); err != nil {
218217 return failWithError (err )
219218 }
220219
221220 // When there's a push spec, the pushed-to branch is where commits
222221 // shall be made
223222
224223 if gitSpec .Push != nil {
225- if err := fetch (ctx , tmp , repo , pushBranch , access , origin . Spec . GitImplementation ); err != nil && err != errRemoteBranchMissing {
224+ if err := fetch (ctx , tmp , pushBranch , access ); err != nil && err != errRemoteBranchMissing {
226225 return failWithError (err )
227226 }
228227 if err = switchBranch (repo , pushBranch ); err != nil {
@@ -307,7 +306,7 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(ctx context.Context, req ctr
307306 return failWithError (err )
308307 }
309308 } else {
310- if err := push (ctx , tmp , repo , pushBranch , access , origin . Spec . GitImplementation ); err != nil {
309+ if err := push (ctx , tmp , pushBranch , access ); err != nil {
311310 return failWithError (err )
312311 }
313312
@@ -424,6 +423,10 @@ func (r *ImageUpdateAutomationReconciler) automationsForImagePolicy(obj client.O
424423
425424// --- git ops
426425
426+ // Note: libgit2 is always used for network operations; for cloning,
427+ // it will do a non-shallow clone, and for anything else, it doesn't
428+ // matter what is used.
429+
427430type repoAccess struct {
428431 auth * git.Auth
429432 url string
@@ -433,19 +436,21 @@ func (r *ImageUpdateAutomationReconciler) getRepoAccess(ctx context.Context, rep
433436 var access repoAccess
434437 access .auth = & git.Auth {}
435438 access .url = repository .Spec .URL
436- authStrat , err := gitstrat .AuthSecretStrategyForURL (access .url , git.CheckoutOptions {GitImplementation : repository .Spec .GitImplementation })
439+
440+ authStrat , err := gitstrat .AuthSecretStrategyForURL (access .url , git.CheckoutOptions {GitImplementation : sourcev1 .LibGit2Implementation })
437441 if err != nil {
438442 return access , err
439443 }
440444
441445 if repository .Spec .SecretRef != nil && authStrat != nil {
446+
442447 name := types.NamespacedName {
443448 Namespace : repository .GetNamespace (),
444449 Name : repository .Spec .SecretRef .Name ,
445450 }
446451
447452 var secret corev1.Secret
448- err : = r .Client .Get (ctx , name , & secret )
453+ err = r .Client .Get (ctx , name , & secret )
449454 if err != nil {
450455 err = fmt .Errorf ("auth secret error: %w" , err )
451456 return access , err
@@ -468,11 +473,10 @@ func (r repoAccess) remoteCallbacks() libgit2.RemoteCallbacks {
468473}
469474
470475// cloneInto clones the upstream repository at the `ref` given (which
471- // can be `nil`), using the git library indicated by `impl`. It
472- // returns a `*gogit.Repository` regardless of the git library, since
473- // that is used for committing changes.
474- func cloneInto (ctx context.Context , access repoAccess , ref * sourcev1.GitRepositoryRef , path , impl string ) (* gogit.Repository , error ) {
475- checkoutStrat , err := gitstrat .CheckoutStrategyForRef (ref , git.CheckoutOptions {GitImplementation : impl })
476+ // can be `nil`). It returns a `*gogit.Repository` since that is used
477+ // for committing changes.
478+ func cloneInto (ctx context.Context , access repoAccess , ref * sourcev1.GitRepositoryRef , path string ) (* gogit.Repository , error ) {
479+ checkoutStrat , err := gitstrat .CheckoutStrategyForRef (ref , git.CheckoutOptions {GitImplementation : sourcev1 .LibGit2Implementation })
476480 if err == nil {
477481 _ , _ , err = checkoutStrat .Checkout (ctx , path , access .url , access .auth )
478482 }
@@ -490,18 +494,12 @@ func switchBranch(repo *gogit.Repository, pushBranch string) error {
490494 localBranch := plumbing .NewBranchReferenceName (pushBranch )
491495
492496 // is the branch already present?
493- _ , err := repo .Reference (localBranch , false )
497+ _ , err := repo .Reference (localBranch , true )
498+ var create bool
494499 switch {
495500 case err == plumbing .ErrReferenceNotFound :
496501 // make a new branch, starting at HEAD
497- head , err := repo .Head ()
498- if err != nil {
499- return err
500- }
501- branchRef := plumbing .NewHashReference (localBranch , head .Hash ())
502- if err = repo .Storer .SetReference (branchRef ); err != nil {
503- return err
504- }
502+ create = true
505503 case err != nil :
506504 return err
507505 default :
@@ -516,6 +514,7 @@ func switchBranch(repo *gogit.Repository, pushBranch string) error {
516514
517515 return tree .Checkout (& gogit.CheckoutOptions {
518516 Branch : localBranch ,
517+ Create : create ,
519518 })
520519}
521520
@@ -608,23 +607,12 @@ var errRemoteBranchMissing = errors.New("remote branch missing")
608607// returns errRemoteBranchMissing (this is to work in sympathy with
609608// `switchBranch`, which will create the branch if it doesn't
610609// exist). For any other problem it will return the error.
611- func fetch (ctx context.Context , path string , repo * gogit. Repository , branch string , access repoAccess , impl string ) error {
610+ func fetch (ctx context.Context , path string , branch string , access repoAccess ) error {
612611 refspec := fmt .Sprintf ("refs/heads/%s:refs/heads/%s" , branch , branch )
613- switch impl {
614- case sourcev1 .LibGit2Implementation :
615- lg2repo , err := libgit2 .OpenRepository (path )
616- if err != nil {
617- return err
618- }
619- return fetchLibgit2 (lg2repo , refspec , access )
620- case sourcev1 .GoGitImplementation :
621- return fetchGoGit (ctx , repo , refspec , access )
622- default :
623- return fmt .Errorf ("unknown git implementation %q" , impl )
612+ repo , err := libgit2 .OpenRepository (path )
613+ if err != nil {
614+ return err
624615 }
625- }
626-
627- func fetchLibgit2 (repo * libgit2.Repository , refspec string , access repoAccess ) error {
628616 origin , err := repo .Remotes .Lookup (originRemote )
629617 if err != nil {
630618 return err
@@ -641,69 +629,15 @@ func fetchLibgit2(repo *libgit2.Repository, refspec string, access repoAccess) e
641629 return err
642630}
643631
644- func fetchGoGit (ctx context.Context , repo * gogit.Repository , refspec string , access repoAccess ) error {
645- err := repo .FetchContext (ctx , & gogit.FetchOptions {
646- RemoteName : originRemote ,
647- RefSpecs : []config.RefSpec {config .RefSpec (refspec )},
648- Auth : access .auth .AuthMethod ,
649- })
650- if err == gogit .NoErrAlreadyUpToDate {
651- return nil
652- }
653- if _ , ok := err .(gogit.NoMatchingRefSpecError ); ok {
654- return errRemoteBranchMissing
655- }
656- return err
657- }
658-
659632// push pushes the branch given to the origin using the git library
660633// indicated by `impl`. It's passed both the path to the repo and a
661634// gogit.Repository value, since the latter may as well be used if the
662635// implementation is GoGit.
663- func push (ctx context.Context , path string , repo * gogit.Repository , branch string , access repoAccess , impl string ) error {
664- switch impl {
665- case sourcev1 .LibGit2Implementation :
666- lg2repo , err := libgit2 .OpenRepository (path )
667- if err != nil {
668- return err
669- }
670- return pushLibgit2 (lg2repo , access , branch )
671- case sourcev1 .GoGitImplementation :
672- return pushGoGit (ctx , repo , access , branch )
673- default :
674- return fmt .Errorf ("unknown git implementation %q" , impl )
675- }
676- }
677-
678- func pushGoGit (ctx context.Context , repo * gogit.Repository , access repoAccess , branch string ) error {
679- refspec := config .RefSpec (fmt .Sprintf ("refs/heads/%s:refs/heads/%s" , branch , branch ))
680- err := repo .PushContext (ctx , & gogit.PushOptions {
681- RemoteName : originRemote ,
682- Auth : access .auth .AuthMethod ,
683- RefSpecs : []config.RefSpec {refspec },
684- })
685- return gogitPushError (err )
686- }
687-
688- func gogitPushError (err error ) error {
689- if err == nil {
690- return nil
691- }
692- switch strings .TrimSpace (err .Error ()) {
693- case "unknown error: remote:" :
694- // this unhelpful error arises because go-git takes the first
695- // line of the output on stderr, and for some git providers
696- // (GitLab, at least) the output has a blank line at the
697- // start. The rest of stderr is thrown away, so we can't get
698- // the actual error; but at least we know what was being
699- // attempted, and the likely cause.
700- return fmt .Errorf ("push rejected; check git secret has write access" )
701- default :
636+ func push (ctx context.Context , path , branch string , access repoAccess ) error {
637+ repo , err := libgit2 .OpenRepository (path )
638+ if err != nil {
702639 return err
703640 }
704- }
705-
706- func pushLibgit2 (repo * libgit2.Repository , access repoAccess , branch string ) error {
707641 origin , err := repo .Remotes .Lookup (originRemote )
708642 if err != nil {
709643 return err
0 commit comments