github.com/jenkins-x/jx/v2@v2.1.155/pkg/cmd/step/git/step_git_merge.go (about)

     1  package git
     2  
     3  import (
     4  	"os"
     5  
     6  	"github.com/jenkins-x/jx/v2/pkg/cmd/opts/step"
     7  	"github.com/jenkins-x/jx/v2/pkg/util"
     8  
     9  	"github.com/jenkins-x/jx/v2/pkg/cmd/helper"
    10  
    11  	"github.com/jenkins-x/jx/v2/pkg/prow"
    12  	"github.com/pkg/errors"
    13  
    14  	"github.com/jenkins-x/jx-logging/pkg/log"
    15  
    16  	"github.com/jenkins-x/jx/v2/pkg/gits"
    17  
    18  	"github.com/jenkins-x/jx/v2/pkg/cmd/opts"
    19  	"github.com/jenkins-x/jx/v2/pkg/cmd/templates"
    20  	"github.com/spf13/cobra"
    21  )
    22  
    23  var (
    24  	// StepGitMergeLong command long description
    25  	StepGitMergeLong = templates.LongDesc(`
    26  		This pipeline step merges any SHAs specified into the HEAD of master. 
    27  
    28  If no SHAs are specified then the PULL_REFS environment variable will be parsed for a branch:sha comma separated list of
    29  shas to merge. For example:
    30  
    31  master:ef08a6cd194c2687d4bc12df6bb8a86f53c348ba,2739:5b351f4eae3c4afbb90dd7787f8bf2f8c454723f,2822:bac2a1f34fd54811fb767f69543f59eb3949b2a5
    32  
    33  `)
    34  	// StepGitMergeExample command example
    35  	StepGitMergeExample = templates.Examples(`
    36  		# Merge the SHAs from the PULL_REFS environment variable
    37  		jx step git merge
    38  
    39  		# Merge the SHA into the HEAD of master
    40  		jx step git merge --sha 123456a
    41  
    42  		# Merge a number of SHAs into the HEAD of master
    43  		jx step git merge --sha 123456a --sha 789012b
    44  `)
    45  )
    46  
    47  // StepGitMergeOptions contains the command line flags
    48  type StepGitMergeOptions struct {
    49  	step.StepOptions
    50  
    51  	SHAs       []string
    52  	Remote     string
    53  	Dir        string
    54  	BaseBranch string
    55  	BaseSHA    string
    56  }
    57  
    58  // NewCmdStepGitMerge create the 'step git envs' command
    59  func NewCmdStepGitMerge(commonOpts *opts.CommonOptions) *cobra.Command {
    60  	options := StepGitMergeOptions{
    61  		StepOptions: step.StepOptions{
    62  			CommonOptions: commonOpts,
    63  		},
    64  	}
    65  	cmd := &cobra.Command{
    66  		Use:     "merge",
    67  		Short:   "Merge a number of SHAs into the HEAD of master",
    68  		Long:    StepGitMergeLong,
    69  		Example: StepGitMergeExample,
    70  		Run: func(cmd *cobra.Command, args []string) {
    71  			options.Cmd = cmd
    72  			options.Args = args
    73  			err := options.Run()
    74  			helper.CheckErr(err)
    75  		},
    76  	}
    77  
    78  	cmd.Flags().StringArrayVarP(&options.SHAs, "sha", "", make([]string, 0), "The SHA(s) to merge, "+
    79  		"if not specified then the value of the env var PULL_REFS is used")
    80  	cmd.Flags().StringVarP(&options.Remote, "remote", "", "origin", "The name of the remote")
    81  	cmd.Flags().StringVarP(&options.Dir, "dir", "", "", "The directory in which the git repo is checked out")
    82  	cmd.Flags().StringVarP(&options.BaseBranch, "baseBranch", "", "", "The branch to merge to, "+
    83  		"if not specified then the  first entry in PULL_REFS is used ")
    84  	cmd.Flags().StringVarP(&options.BaseSHA, "baseSHA", "", "", "The SHA to use on the base branch, "+
    85  		"if not specified then the first entry in PULL_REFS is used")
    86  
    87  	return cmd
    88  }
    89  
    90  // Run implements the command
    91  func (o *StepGitMergeOptions) Run() error {
    92  	if o.Remote == "" {
    93  		o.Remote = "origin"
    94  	}
    95  
    96  	// set dummy git config details if none set so we can do a local commit when merging
    97  	err := o.setGitConfig()
    98  	if err != nil {
    99  		return errors.Wrapf(err, "failed to set git config")
   100  	}
   101  	if len(o.SHAs) == 0 || o.BaseBranch == "" || o.BaseSHA == "" {
   102  		// Try to look in the env vars
   103  		if pullRefs := os.Getenv("PULL_REFS"); pullRefs != "" {
   104  			log.Logger().Infof("Using SHAs from PULL_REFS=%s", pullRefs)
   105  			pullRefs, err := prow.ParsePullRefs(pullRefs)
   106  			if err != nil {
   107  				return errors.Wrapf(err, "parsing PULL_REFS=%s", pullRefs)
   108  			}
   109  			if len(o.SHAs) == 0 {
   110  				o.SHAs = make([]string, 0)
   111  				for _, sha := range pullRefs.ToMerge {
   112  					o.SHAs = append(o.SHAs, sha)
   113  				}
   114  			}
   115  			if o.BaseBranch == "" {
   116  				o.BaseBranch = pullRefs.BaseBranch
   117  			}
   118  			if o.BaseSHA == "" {
   119  				o.BaseSHA = pullRefs.BaseSha
   120  			}
   121  		}
   122  	}
   123  	if len(o.SHAs) == 0 {
   124  		log.Logger().Warnf("no SHAs to merge, falling back to initial cloned commit")
   125  		return nil
   126  	}
   127  
   128  	err = gits.FetchAndMergeSHAs(o.SHAs, o.BaseBranch, o.BaseSHA, o.Remote, o.Dir, o.Git())
   129  	if err != nil {
   130  		return errors.Wrap(err, "error during merge")
   131  	}
   132  
   133  	if o.Verbose {
   134  		commits, err := o.getMergedCommits()
   135  		if err != nil {
   136  			return errors.Wrap(err, "unable to write merge result")
   137  		}
   138  		o.logCommits(commits, o.BaseBranch)
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  func (o *StepGitMergeOptions) setGitConfig() error {
   145  	user, err := o.GetCommandOutput(o.Dir, "git", "config", "user.name")
   146  	if err != nil || user == "" {
   147  		err := o.RunCommandFromDir(o.Dir, "git", "config", "user.name", util.DefaultGitUserName)
   148  		if err != nil {
   149  			return err
   150  		}
   151  	}
   152  	email, err := o.GetCommandOutput(o.Dir, "git", "config", "user.email")
   153  	if email == "" || err != nil {
   154  		err := o.RunCommandFromDir(o.Dir, "git", "config", "user.email", util.DefaultGitUserEmail)
   155  		if err != nil {
   156  			return err
   157  		}
   158  	}
   159  	return nil
   160  }
   161  
   162  func (o *StepGitMergeOptions) getMergedCommits() ([]gits.GitCommit, error) {
   163  	commits, err := o.Git().GetCommits(o.Dir, o.BaseSHA, "HEAD")
   164  	if err != nil {
   165  		return nil, errors.Wrap(err, "unable to retrieve commits")
   166  	}
   167  
   168  	return commits, nil
   169  }
   170  
   171  func (o *StepGitMergeOptions) logCommits(commits []gits.GitCommit, base string) {
   172  	for _, commit := range commits {
   173  		log.Logger().Infof("Merged SHA %s with commit message '%s' into base branch %s", commit.SHA, commit.Subject(), base)
   174  	}
   175  }