@@ -31,6 +31,7 @@ import (
3131
3232 utilerrors "k8s.io/apimachinery/pkg/util/errors"
3333 "k8s.io/apimachinery/pkg/util/sets"
34+ "k8s.io/utils/exec"
3435 cherrypicker "sigs.k8s.io/prow/cmd/external-plugins/cherrypicker/lib"
3536 "sigs.k8s.io/prow/pkg/config"
3637 "sigs.k8s.io/prow/pkg/git/v2"
@@ -52,7 +53,6 @@ type githubClient interface {
5253 AddLabel (org , repo string , number int , label string ) error
5354 AssignIssue (org , repo string , number int , logins []string ) error
5455 CreateComment (org , repo string , number int , comment string ) error
55- CreateFork (org , repo string ) (string , error )
5656 CreatePullRequest (org , repo , title , body , head , base string , canModify bool ) (int , error )
5757 CreateIssue (org , repo , title , body string , milestone int , labels , assignees []string ) (int , error )
5858 EnsureFork (forkingUser , org , repo string ) (string , error )
@@ -89,6 +89,9 @@ type Server struct {
8989 botUser * github.UserData
9090 email string
9191
92+ // skip to fork the repo
93+ skipFork bool
94+
9295 gc git.ClientFactory
9396 // Used for unit testing
9497 push func (forkName , newBranch string , force bool ) error
@@ -471,7 +474,7 @@ func (s *Server) handle(logger logrus.FieldLogger, requester string, comment *gi
471474 startClone := time .Now ()
472475 r , err := s .gc .ClientFor (org , repo )
473476 if err != nil {
474- return fmt .Errorf ("failed to get git client for %s/%s: %w" , org , forkName , err )
477+ return fmt .Errorf ("failed to get git client for %s/%s: %w" , org , repo , err )
475478 }
476479 defer func () {
477480 if err := r .Clean (); err != nil {
@@ -531,9 +534,8 @@ func (s *Server) handle(logger logrus.FieldLogger, requester string, comment *gi
531534 titleTargetBranchIndicator := fmt .Sprintf (titleTargetBranchIndicatorTemplate , targetBranch )
532535 title = fmt .Sprintf ("%s%s" , titleTargetBranchIndicator , omitBaseBranchFromTitle (title , baseBranch ))
533536
534- // Apply the patch.
535- if err := r .Am (localPath ); err != nil {
536- errs := []error {fmt .Errorf ("failed to `git am`: %w" , err )}
537+ if err := s .applyToBranch (r , org , repo , localPath , num ); err != nil {
538+ errs := []error {fmt .Errorf ("failed to cherry-pick: %w" , err )}
537539 logger .WithError (err ).Warn ("failed to apply PR on top of target branch" )
538540 resp := fmt .Sprintf ("#%d failed to apply on top of branch %q:\n ```\n %v\n ```" , num , targetBranch , err )
539541 if err := s .createComment (logger , org , repo , num , comment , resp ); err != nil {
@@ -551,6 +553,11 @@ func (s *Server) handle(logger logrus.FieldLogger, requester string, comment *gi
551553 }
552554
553555 push := r .PushToNamedFork
556+ if s .skipFork {
557+ push = func (_ string , branch string , force bool ) error {
558+ return r .PushToCentral (branch , force )
559+ }
560+ }
554561 if s .push != nil {
555562 push = s .push
556563 }
@@ -581,6 +588,11 @@ func (s *Server) handle(logger logrus.FieldLogger, requester string, comment *gi
581588 if err := s .createComment (logger , org , repo , num , comment , resp ); err != nil {
582589 return fmt .Errorf ("failed to create comment: %w" , err )
583590 }
591+
592+ // TODO:
593+ // - Copying original pull request labels.
594+ // - Add picked label.
595+
584596 for _ , label := range s .labels {
585597 if err := s .ghc .AddLabel (org , repo , createdNum , label ); err != nil {
586598 return fmt .Errorf ("failed to add label %s: %w" , label , err )
@@ -598,6 +610,35 @@ func (s *Server) handle(logger logrus.FieldLogger, requester string, comment *gi
598610 return nil
599611}
600612
613+ func (s * Server ) applyToBranch (r git.RepoClient , org , repo , localPath string , num int ) error {
614+ var errs []error
615+
616+ // try to apply the patch using git am.
617+ {
618+ err := r .Am (localPath )
619+ if err == nil {
620+ return nil
621+ }
622+ errs = append (errs , fmt .Errorf ("[try 1] failed to `git am`: %w" , err ))
623+ }
624+ // try to cherry-pick the merge commit
625+ {
626+ pr , err := s .ghc .GetPullRequest (org , repo , num )
627+ if err != nil {
628+ return fmt .Errorf ("[try 2] failed to get pull request %s/%s#%d: %w" , org , repo , num , err )
629+ }
630+ cherrypickCmd := exec .New ().Command ("git" , "cherry-pick" , "-m" , "1" , "--cleanup=verbatim" , * pr .MergeSHA )
631+ cherrypickCmd .SetDir (r .Directory ())
632+ out , err := cherrypickCmd .CombinedOutput ()
633+ if err == nil {
634+ return nil
635+ }
636+ errs = append (errs , fmt .Errorf ("[try 2] Failed to cherry-pick: %v\n ```\n %v\n ```" , err , string (out )))
637+ }
638+
639+ return utilerrors .NewAggregate (errs )
640+ }
641+
601642// omitBaseBranchFromTitle returns the title without the base branch's
602643// indicator, if there is one. We do this to avoid long cherry-pick titles when
603644// doing a backport of a backport.
@@ -646,6 +687,10 @@ func (s *Server) createIssue(l logrus.FieldLogger, org, repo, title, body string
646687
647688// ensureForkExists ensures a fork of org/repo exists for the bot.
648689func (s * Server ) ensureForkExists (org , repo string ) (string , error ) {
690+ if s .skipFork {
691+ return repo , nil
692+ }
693+
649694 fork := s .botUser .Login + "/" + repo
650695
651696 // fork repo if it doesn't exist
0 commit comments