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 }