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

     1  package step
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/jenkins-x/jx/v2/pkg/cmd/opts/step"
    12  	"github.com/jenkins-x/jx/v2/pkg/gits"
    13  
    14  	"github.com/jenkins-x/jx/v2/pkg/cmd/helper"
    15  
    16  	"github.com/jenkins-x/jx-logging/pkg/log"
    17  	"github.com/jenkins-x/jx/v2/pkg/cmd/opts"
    18  	"github.com/jenkins-x/jx/v2/pkg/cmd/templates"
    19  	"github.com/jenkins-x/jx/v2/pkg/jenkins"
    20  	"github.com/jenkins-x/jx/v2/pkg/jenkinsfile"
    21  	"github.com/jenkins-x/jx/v2/pkg/util"
    22  	"github.com/pkg/errors"
    23  	"github.com/spf13/cobra"
    24  )
    25  
    26  // StepCustomPipelineOptions contains the command line arguments for this command
    27  type StepCustomPipelineOptions struct {
    28  	step.StepOptions
    29  
    30  	MultiBranchProject bool
    31  	Dir                string
    32  	Jenkinsfile        string
    33  	JenkinsPath        string
    34  	JenkinsSelector    opts.JenkinsSelectorOptions
    35  }
    36  
    37  var (
    38  	stepCustomPipelineLong = templates.LongDesc(`
    39  		This pipeline step lazily creates a Pipeline job inside a custom Jenkins App and then triggers it
    40  
    41  `)
    42  
    43  	stepCustomPipelineExample = templates.Examples(`
    44  		# triggers the Jenkinsfile in the current directory in the custom Jenkins App
    45  		jx step custom pipeline
    46  `)
    47  )
    48  
    49  // NewCmdStepCustomPipeline creates the new command
    50  func NewCmdStepCustomPipeline(commonOpts *opts.CommonOptions) *cobra.Command {
    51  	options := StepCustomPipelineOptions{
    52  		StepOptions: step.StepOptions{
    53  			CommonOptions: commonOpts,
    54  		},
    55  		JenkinsSelector: opts.JenkinsSelectorOptions{
    56  			UseCustomJenkins: true,
    57  		},
    58  	}
    59  	cmd := &cobra.Command{
    60  		Use:     "custom pipeline",
    61  		Short:   "Triggers a pipeline in a custom Jenkins server using the local Jenkinsfile",
    62  		Long:    stepCustomPipelineLong,
    63  		Example: stepCustomPipelineExample,
    64  		Run: func(cmd *cobra.Command, args []string) {
    65  			options.Cmd = cmd
    66  			options.Args = args
    67  			err := options.Run()
    68  			helper.CheckErr(err)
    69  		},
    70  	}
    71  
    72  	cmd.Flags().StringVarP(&options.JenkinsSelector.CustomJenkinsName, "jenkins-name", "j", "", "The name of the custom Jenkins App if you don't wish to use the default execution engine in Jenkins X")
    73  
    74  	cmd.Flags().BoolVarP(&options.MultiBranchProject, "multi-branch-project", "", false, "Use a Multi Branch Project in Jenkins")
    75  	cmd.Flags().StringVarP(&options.Dir, "dir", "d", ".", "the directory to look for the Jenkisnfile inside")
    76  	cmd.Flags().StringVarP(&options.Jenkinsfile, "jenkinsfile", "f", jenkinsfile.Name, "The name of the Jenkinsfile to use")
    77  	cmd.Flags().StringVarP(&options.JenkinsPath, "jenkins-path", "p", "", "The Jenkins folder path to create the pipeline inside. If not specified it defaults to the git 'owner/repoName/branch'")
    78  	return cmd
    79  }
    80  
    81  // Run implements the command
    82  func (o *StepCustomPipelineOptions) Run() error {
    83  	jenkinsClient, err := o.CreateCustomJenkinsClient(&o.JenkinsSelector)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	if o.Dir == "" {
    88  		o.Dir, err = os.Getwd()
    89  		if err != nil {
    90  			return err
    91  		}
    92  	}
    93  	if o.Jenkinsfile == "" {
    94  		o.Jenkinsfile = jenkinsfile.Name
    95  	}
    96  	jenkinsfileName := filepath.Join(o.Dir, o.Jenkinsfile)
    97  	exists, err := util.FileExists(jenkinsfileName)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if !exists {
   102  		return fmt.Errorf("%s does not exist", jenkinsfileName)
   103  	}
   104  
   105  	gitInfo, err := o.FindGitInfo(o.Dir)
   106  	if err != nil {
   107  		return err
   108  	}
   109  
   110  	gitKind, err := o.GitServerKind(gitInfo)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	branch, err := o.Git().Branch(o.Dir)
   116  	if err != nil {
   117  		return err
   118  	}
   119  	if branch == "" {
   120  		branch = "master"
   121  	}
   122  
   123  	if o.JenkinsPath == "" {
   124  		o.JenkinsPath = fmt.Sprintf("%s/%s/%s", gitInfo.Organisation, gitInfo.Name, branch)
   125  	}
   126  
   127  	paths := strings.Split(o.JenkinsPath, "/")
   128  	last := len(paths) - 1
   129  	for i, path := range paths {
   130  		folderPath := paths[0 : i+1]
   131  		folder, err := jenkinsClient.GetJobByPath(folderPath...)
   132  		fullPath := util.UrlJoin(folderPath...)
   133  		jobURL := util.UrlJoin(jenkinsClient.BaseURL(), fullPath)
   134  
   135  		if i < last {
   136  			// lets ensure there's a folder
   137  			err = o.Retry(3, time.Second*10, func() error {
   138  				if err != nil {
   139  					folderXML := jenkins.CreateFolderXML(jobURL, path)
   140  					if i == 0 {
   141  						err = jenkinsClient.CreateJobWithXML(folderXML, path)
   142  						if err != nil {
   143  							return errors.Wrapf(err, "failed to create the %s folder at %s in Jenkins", path, jobURL)
   144  						}
   145  					} else {
   146  						folders := strings.Join(paths[0:i], "/job/")
   147  						err = jenkinsClient.CreateFolderJobWithXML(folderXML, folders, path)
   148  						if err != nil {
   149  							return errors.Wrapf(err, "failed to create the %s folder in folders %s at %s in Jenkins", path, folders, jobURL)
   150  						}
   151  					}
   152  				} else {
   153  					c := folder.Class
   154  					if c != "com.cloudbees.hudson.plugins.folder.Folder" {
   155  						log.Logger().Warnf("Warning the folder %s is of class %s", jobURL, c)
   156  					}
   157  				}
   158  				return nil
   159  			})
   160  			if err != nil {
   161  				return err
   162  			}
   163  		} else {
   164  			gitURL := gits.HttpCloneURL(gitInfo, gitKind)
   165  			log.Logger().Infof("Using git URL %s and branch %s", util.ColorInfo(gitURL), util.ColorInfo(branch))
   166  
   167  			err = o.Retry(3, time.Second*10, func() error {
   168  				if err != nil {
   169  					pipelineXML := jenkins.CreatePipelineXML(gitURL, branch, o.Jenkinsfile)
   170  					if i == 0 {
   171  						err = jenkinsClient.CreateJobWithXML(pipelineXML, path)
   172  						if err != nil {
   173  							return errors.Wrapf(err, "failed to create the %s pipeline at %s in Jenkins", path, jobURL)
   174  						}
   175  					} else {
   176  						folders := strings.Join(paths[0:i], "/job/")
   177  						err = jenkinsClient.CreateFolderJobWithXML(pipelineXML, folders, path)
   178  						if err != nil {
   179  							return errors.Wrapf(err, "failed to create the %s pipeline in folders %s at %s in Jenkins", path, folders, jobURL)
   180  						}
   181  					}
   182  				}
   183  				return nil
   184  			})
   185  			if err != nil {
   186  				return err
   187  			}
   188  
   189  			job, err := jenkinsClient.GetJobByPath(paths...)
   190  			if err != nil {
   191  				return err
   192  			}
   193  			job.Url = jenkins.SwitchJenkinsBaseURL(job.Url, jenkinsClient.BaseURL())
   194  			jobPath := strings.Join(paths, "/")
   195  			log.Logger().Infof("triggering pipeline job %s", util.ColorInfo(jobPath))
   196  			err = jenkinsClient.Build(job, url.Values{})
   197  			if err != nil {
   198  				return errors.Wrapf(err, "failed to trigger job %s", jobPath)
   199  			}
   200  		}
   201  	}
   202  	return nil
   203  }