github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/step/verify/step_verify_behavior.go (about)

     1  package verify
     2  
     3  import (
     4  	"strings"
     5  	"time"
     6  
     7  	"github.com/olli-ai/jx/v2/pkg/tekton"
     8  	"github.com/olli-ai/jx/v2/pkg/tekton/metapipeline"
     9  	"github.com/sirupsen/logrus"
    10  
    11  	"github.com/jenkins-x/jx-logging/pkg/log"
    12  	"github.com/olli-ai/jx/v2/pkg/builds"
    13  	"github.com/olli-ai/jx/v2/pkg/cmd/get"
    14  	"github.com/olli-ai/jx/v2/pkg/cmd/helper"
    15  	"github.com/olli-ai/jx/v2/pkg/cmd/importcmd"
    16  	"github.com/olli-ai/jx/v2/pkg/cmd/opts"
    17  	"github.com/olli-ai/jx/v2/pkg/cmd/start"
    18  	"github.com/olli-ai/jx/v2/pkg/cmd/templates"
    19  	"github.com/olli-ai/jx/v2/pkg/gits"
    20  	"github.com/olli-ai/jx/v2/pkg/kube"
    21  	"github.com/olli-ai/jx/v2/pkg/util"
    22  	"github.com/pkg/errors"
    23  
    24  	v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1"
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  
    28  	"github.com/spf13/cobra"
    29  )
    30  
    31  // BehaviorOptions contains the command line options
    32  type BehaviorOptions struct {
    33  	*opts.CommonOptions
    34  
    35  	SourceGitURL      string
    36  	Branch            string
    37  	NoImport          bool
    38  	CredentialsSecret string
    39  	GitOrganisation   string
    40  	UseGoProxy        bool
    41  	TestSuite         string
    42  }
    43  
    44  var (
    45  	verifyBehaviorLong = templates.LongDesc(`
    46  		Verifies the cluster behaves correctly by running the BDD tests to verify we can create quickstarts, previews and promote applications.
    47  
    48  `)
    49  
    50  	verifyBehaviorExample = templates.Examples(`
    51  		# runs the BDD tests on the current cluster to verify it behaves nicely
    52  		jx step verify behavior
    53  	`)
    54  )
    55  
    56  // NewCmdStepVerifyBehavior creates the command
    57  func NewCmdStepVerifyBehavior(commonOpts *opts.CommonOptions) *cobra.Command {
    58  	options := &BehaviorOptions{
    59  		CommonOptions: commonOpts,
    60  	}
    61  
    62  	cmd := &cobra.Command{
    63  		Use:     "behavior [flags]",
    64  		Short:   "Verifies the cluster behaves correctly by running the BDD tests to verify we can create quickstarts, previews and promote applications",
    65  		Long:    verifyBehaviorLong,
    66  		Example: verifyBehaviorExample,
    67  		Aliases: []string{"tck", "bdd", "behavior", "behave"},
    68  		Run: func(cmd *cobra.Command, args []string) {
    69  			options.Cmd = cmd
    70  			options.Args = args
    71  			err := options.Run()
    72  			helper.CheckErr(err)
    73  		},
    74  	}
    75  	cmd.Flags().StringVarP(&options.SourceGitURL, "git-url", "u", "https://github.com/jenkins-x/bdd-jx.git", "The git URL of the BDD tests pipeline")
    76  	cmd.Flags().StringVarP(&options.Branch, "branch", "", "master", "The git branch to use to run the BDD tests")
    77  	cmd.Flags().BoolVarP(&options.NoImport, "no-import", "", false, "Create the pipeline directly, don't import the repository")
    78  	cmd.Flags().StringVarP(&options.CredentialsSecret, "credentials-secret", "", "", "The name of the secret to generate the bdd credentials from, if not specified, the default git auth will be used")
    79  	cmd.Flags().StringVarP(&options.GitOrganisation, "git-organisation", "", "", "Override the git org for the tests rather than reading from teamSettings")
    80  	cmd.Flags().BoolVarP(&options.UseGoProxy, "use-go-proxy", "", false, "Enable the GoProxy for the bdd tests")
    81  	cmd.Flags().StringVarP(&options.TestSuite, "test-suite", "", "", "Override the default test suite ")
    82  
    83  	return cmd
    84  }
    85  
    86  // Run implements this command
    87  func (o *BehaviorOptions) Run() error {
    88  	jxClient, ns, err := o.JXClientAndDevNamespace()
    89  	if err != nil {
    90  		return err
    91  	}
    92  
    93  	if o.NoImport {
    94  		owner := "jenkins-x"
    95  		repo := "bdd-jx"
    96  		err = o.runPipelineDirectly(owner, repo, o.SourceGitURL)
    97  		if err != nil {
    98  			return errors.Wrapf(err, "unable to run job directly %s/%s", owner, repo)
    99  		}
   100  		// let sleep a little bit to give things a head start
   101  		time.Sleep(time.Second * 3)
   102  
   103  		return o.followLogs(owner, repo)
   104  	}
   105  
   106  	list, err := jxClient.JenkinsV1().SourceRepositories(ns).List(metav1.ListOptions{})
   107  	if err != nil && !apierrors.IsNotFound(err) {
   108  		return errors.Wrapf(err, "failed to load SourceRepositories in namespace '%s'", ns)
   109  	}
   110  	gitInfo, err := gits.ParseGitURL(o.SourceGitURL)
   111  	if err != nil {
   112  		return errors.Wrapf(err, "failed to parse git URL '%s'", o.SourceGitURL)
   113  	}
   114  	sr, err := o.findSourceRepository(list.Items, o.SourceGitURL, gitInfo)
   115  	if err != nil {
   116  		return errors.Wrapf(err, "failed to find SourceRepository for URL '%s'", o.SourceGitURL)
   117  	}
   118  	owner := ""
   119  	repo := ""
   120  	trigger := true
   121  	if sr == nil {
   122  		err = o.importSourceRepository(gitInfo)
   123  		if err != nil {
   124  			return errors.Wrapf(err, "failed to import SourceRepository for URL '%s'", o.SourceGitURL)
   125  		}
   126  		trigger = false
   127  	} else {
   128  		owner = sr.Spec.Org
   129  		repo = sr.Spec.Repo
   130  	}
   131  	if owner == "" {
   132  		owner = gitInfo.Organisation
   133  	}
   134  	if owner == "" {
   135  		owner = gitInfo.Organisation
   136  	}
   137  	if trigger {
   138  		err = o.triggerPipeline(owner, repo)
   139  		if err != nil {
   140  			return errors.Wrapf(err, "failed to trigger Pipeline for URL '%s/%s'", owner, repo)
   141  		}
   142  	}
   143  
   144  	// let sleep a little bit to give things a head start
   145  	time.Sleep(time.Second * 3)
   146  
   147  	return o.followLogs(owner, repo)
   148  }
   149  
   150  func (o *BehaviorOptions) followLogs(owner string, repo string) error {
   151  	commonOptions := *o.CommonOptions
   152  	commonOptions.BatchMode = true
   153  	lo := &get.GetBuildLogsOptions{
   154  		Options: get.Options{
   155  			CommonOptions: &commonOptions,
   156  		},
   157  		Tail:           true,
   158  		Wait:           true,
   159  		FailIfPodFails: true,
   160  		BuildFilter: builds.BuildPodInfoFilter{
   161  			Owner:      owner,
   162  			Repository: repo,
   163  			Branch:     o.Branch,
   164  		},
   165  	}
   166  	return lo.Run()
   167  }
   168  
   169  func (o *BehaviorOptions) findSourceRepository(repositories []v1.SourceRepository, url string, gitInfo *gits.GitRepository) (*v1.SourceRepository, error) {
   170  	for i := range repositories {
   171  		repo := &repositories[i]
   172  		u2, _ := kube.GetRepositoryGitURL(repo)
   173  		if url == u2 || strings.TrimSuffix(url, ".git") == strings.TrimSuffix(u2, ".git") {
   174  			return repo, nil
   175  		}
   176  	}
   177  	for i := range repositories {
   178  		repo := &repositories[i]
   179  		if repo.Spec.Org == gitInfo.Organisation && repo.Spec.Repo == gitInfo.Name {
   180  			return repo, nil
   181  		}
   182  	}
   183  	return nil, nil
   184  }
   185  
   186  func (o *BehaviorOptions) importSourceRepository(gitInfo *gits.GitRepository) error {
   187  	log.Logger().Infof("importing project %s", util.ColorInfo(o.SourceGitURL))
   188  
   189  	io := &importcmd.ImportOptions{
   190  		CommonOptions:           o.CommonOptions,
   191  		RepoURL:                 o.SourceGitURL,
   192  		DisableDraft:            true,
   193  		DisableJenkinsfileCheck: true,
   194  		DisableMaven:            true,
   195  		DisableWebhooks:         true,
   196  		Organisation:            gitInfo.Organisation,
   197  		Repository:              gitInfo.Name,
   198  		AppName:                 gitInfo.Name,
   199  	}
   200  	err := io.Run()
   201  	if err != nil {
   202  		return errors.Wrapf(err, "failed to import project %s", o.SourceGitURL)
   203  	}
   204  	return nil
   205  }
   206  
   207  func (o *BehaviorOptions) triggerPipeline(owner string, repo string) error {
   208  	pipeline := owner + "/" + repo + "/" + o.Branch
   209  	log.Logger().Infof("triggering pipeline %s", util.ColorInfo(pipeline))
   210  
   211  	so := &start.StartPipelineOptions{
   212  		CommonOptions: o.CommonOptions,
   213  		Filter:        pipeline,
   214  		Branch:        o.Branch,
   215  	}
   216  	err := so.Run()
   217  	if err != nil {
   218  		return errors.Wrapf(err, "failed to start pipeline %s", pipeline)
   219  	}
   220  	return nil
   221  }
   222  
   223  func (o *BehaviorOptions) runPipelineDirectly(owner string, repo string, sourceURL string) error {
   224  	pullRefs := ""
   225  	branch := "master"
   226  	pullRefs = branch + ":"
   227  	kind := metapipeline.ReleasePipeline
   228  	sa := tekton.DefaultPipelineSA
   229  
   230  	l := logrus.WithFields(logrus.Fields(map[string]interface{}{
   231  		"Owner":     owner,
   232  		"Name":      repo,
   233  		"SourceURL": sourceURL,
   234  		"Branch":    branch,
   235  		"PullRefs":  pullRefs,
   236  		//"Job":       job,
   237  	}))
   238  	l.Info("about to start Jenkinx X meta pipeline")
   239  
   240  	pullRefData := metapipeline.NewPullRef(sourceURL, branch, "")
   241  	envVars := map[string]string{}
   242  	if o.CredentialsSecret != "" {
   243  		envVars["JX_CREDENTIALS_FROM_SECRET"] = o.CredentialsSecret
   244  	}
   245  
   246  	if o.GitOrganisation != "" {
   247  		envVars["GIT_ORGANISATION"] = o.GitOrganisation
   248  	}
   249  
   250  	if o.UseGoProxy {
   251  		envVars["GOPROXY"] = "https://proxy.golang.org"
   252  	}
   253  
   254  	if o.TestSuite != "" {
   255  		envVars["SUITE"] = o.TestSuite
   256  	}
   257  
   258  	pipelineCreateParam := metapipeline.PipelineCreateParam{
   259  		PullRef:      pullRefData,
   260  		PipelineKind: kind,
   261  		Context:      "",
   262  		// No equivalent to https://github.com/olli-ai/jx/blob/bb59278c2707e0e99b3c24be926745c324824388/pkg/cmd/controller/pipeline/pipelinerunner_controller.go#L236
   263  		//   for getting environment variables from the prow job here, so far as I can tell (abayer)
   264  		// Also not finding an equivalent to labels from the PipelineRunRequest
   265  		ServiceAccount: sa,
   266  		// I believe we can use an empty string default image?
   267  		DefaultImage:        "",
   268  		EnvVariables:        envVars,
   269  		UseBranchAsRevision: true,
   270  		NoReleasePrepare:    true,
   271  	}
   272  
   273  	c, err := metapipeline.NewMetaPipelineClient()
   274  	if err != nil {
   275  		return errors.Wrap(err, "unable to create metapipeline client")
   276  	}
   277  
   278  	pipelineActivity, tektonCRDs, err := c.Create(pipelineCreateParam)
   279  	if err != nil {
   280  		return errors.Wrap(err, "unable to create Tekton CRDs")
   281  	}
   282  
   283  	err = c.Apply(pipelineActivity, tektonCRDs)
   284  	if err != nil {
   285  		return errors.Wrap(err, "unable to apply Tekton CRDs")
   286  	}
   287  	return nil
   288  }