// Run contains all the necessary functionality for the OpenShift cli start-build command func (o *StartBuildOptions) Run() error { if len(o.FromWebhook) > 0 { return o.RunStartBuildWebHook() } if len(o.ListWebhooks) > 0 { return o.RunListBuildWebHooks() } buildRequestCauses := []buildapi.BuildTriggerCause{} request := &buildapi.BuildRequest{ TriggeredBy: append(buildRequestCauses, buildapi.BuildTriggerCause{ Message: "Manually triggered", }, ), ObjectMeta: kapi.ObjectMeta{Name: o.Name}, } if len(o.EnvVar) > 0 { request.Env = o.EnvVar } if len(o.Commit) > 0 { request.Revision = &buildapi.SourceRevision{ Git: &buildapi.GitSourceRevision{ Commit: o.Commit, }, } } var err error var newBuild *buildapi.Build switch { case o.AsBinary: request := &buildapi.BinaryBuildRequestOptions{ ObjectMeta: kapi.ObjectMeta{ Name: o.Name, Namespace: o.Namespace, }, Commit: o.Commit, } if len(o.EnvVar) > 0 { fmt.Fprintf(o.ErrOut, "WARNING: Specifying environment variables with binary builds is not supported.\n") } if newBuild, err = streamPathToBuild(o.Git, o.In, o.ErrOut, o.Client.BuildConfigs(o.Namespace), o.FromDir, o.FromFile, o.FromRepo, request); err != nil { return err } case len(o.FromBuild) > 0: if newBuild, err = o.Client.Builds(o.Namespace).Clone(request); err != nil { if isInvalidSourceInputsError(err) { return fmt.Errorf("Build %s/%s has no valid source inputs and '--from-build' cannot be used for binary builds", o.Namespace, o.Name) } return err } default: if newBuild, err = o.Client.BuildConfigs(o.Namespace).Instantiate(request); err != nil { if isInvalidSourceInputsError(err) { return fmt.Errorf("Build configuration %s/%s has no valid source inputs, if this is a binary build you must specify one of '--from-dir', '--from-repo', or '--from-file'", o.Namespace, o.Name) } return err } } // TODO: support -o on this command fmt.Fprintln(o.Out, newBuild.Name) var ( wg sync.WaitGroup exitErr error ) // Wait for the build to complete if o.WaitForComplete { wg.Add(1) go func() { defer wg.Done() exitErr = WaitForBuildComplete(o.Client.Builds(o.Namespace), newBuild.Name) }() } // Stream the logs from the build if o.Follow { wg.Add(1) go func() { // if --wait option is set, then don't wait for logs to finish streaming // but wait for the build to reach its final state if o.WaitForComplete { wg.Done() } else { defer wg.Done() } opts := buildapi.BuildLogOptions{ Follow: true, NoWait: false, } for { rd, err := o.Client.BuildLogs(o.Namespace).Get(newBuild.Name, opts).Stream() if err != nil { // if --wait options is set, then retry the connection to build logs // when we hit the timeout. if o.WaitForComplete && oerrors.IsTimeoutErr(err) { continue } fmt.Fprintf(o.ErrOut, "error getting logs: %v\n", err) return } defer rd.Close() if _, err = io.Copy(o.Out, rd); err != nil { fmt.Fprintf(o.ErrOut, "error streaming logs: %v\n", err) } break } }() } wg.Wait() return exitErr }
// Run contains all the necessary functionality for the OpenShift cli start-build command func (o *StartBuildOptions) Run() error { if len(o.FromWebhook) > 0 { return o.RunStartBuildWebHook() } if len(o.ListWebhooks) > 0 { return o.RunListBuildWebHooks() } buildRequestCauses := []buildapi.BuildTriggerCause{} request := &buildapi.BuildRequest{ TriggeredBy: append(buildRequestCauses, buildapi.BuildTriggerCause{ Message: "Manually triggered", }, ), ObjectMeta: kapi.ObjectMeta{Name: o.Name}, } if len(o.EnvVar) > 0 { request.Env = o.EnvVar } if len(o.Commit) > 0 { request.Revision = &buildapi.SourceRevision{ Git: &buildapi.GitSourceRevision{ Commit: o.Commit, }, } } var err error var newBuild *buildapi.Build switch { case o.AsBinary: request := &buildapi.BinaryBuildRequestOptions{ ObjectMeta: kapi.ObjectMeta{ Name: o.Name, Namespace: o.Namespace, }, Commit: o.Commit, } if len(o.EnvVar) > 0 { fmt.Fprintf(o.ErrOut, "WARNING: Specifying environment variables with binary builds is not supported.\n") } if newBuild, err = streamPathToBuild(o.Git, o.In, o.ErrOut, o.Client.BuildConfigs(o.Namespace), o.FromDir, o.FromFile, o.FromRepo, request); err != nil { return err } case len(o.FromBuild) > 0: if newBuild, err = o.Client.Builds(o.Namespace).Clone(request); err != nil { if isInvalidSourceInputsError(err) { return fmt.Errorf("Build %s/%s has no valid source inputs and '--from-build' cannot be used for binary builds", o.Namespace, o.Name) } return err } default: if newBuild, err = o.Client.BuildConfigs(o.Namespace).Instantiate(request); err != nil { if isInvalidSourceInputsError(err) { return fmt.Errorf("Build configuration %s/%s has no valid source inputs, if this is a binary build you must specify one of '--from-dir', '--from-repo', or '--from-file'", o.Namespace, o.Name) } return err } } kcmdutil.PrintSuccess(o.Mapper, o.ShortOutput, o.Out, "build", newBuild.Name, "started") // Stream the logs from the build if o.Follow { opts := buildapi.BuildLogOptions{ Follow: true, NoWait: false, } for { rd, err := o.Client.BuildLogs(o.Namespace).Get(newBuild.Name, opts).Stream() if err != nil { // retry the connection to build logs when we hit the timeout. if oerrors.IsTimeoutErr(err) { fmt.Fprintf(o.ErrOut, "timed out getting logs, retrying\n") continue } fmt.Fprintf(o.ErrOut, "error getting logs (%v), waiting for build to complete\n", err) break } defer rd.Close() if _, err = io.Copy(o.Out, rd); err != nil { fmt.Fprintf(o.ErrOut, "error streaming logs (%v), waiting for build to complete\n", err) } break } } if o.Follow || o.WaitForComplete { return WaitForBuildComplete(o.Client.Builds(o.Namespace), newBuild.Name) } return nil }
// RunStartBuild contains all the necessary functionality for the OpenShift cli start-build command func RunStartBuild(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Command, envParams []string, args []string, webhooks util.StringFlag) error { webhook := kcmdutil.GetFlagString(cmd, "from-webhook") buildName := kcmdutil.GetFlagString(cmd, "from-build") follow := kcmdutil.GetFlagBool(cmd, "follow") commit := kcmdutil.GetFlagString(cmd, "commit") waitForComplete := kcmdutil.GetFlagBool(cmd, "wait") fromFile := kcmdutil.GetFlagString(cmd, "from-file") fromDir := kcmdutil.GetFlagString(cmd, "from-dir") fromRepo := kcmdutil.GetFlagString(cmd, "from-repo") buildLogLevel := kcmdutil.GetFlagString(cmd, "build-loglevel") switch { case len(webhook) > 0: if len(args) > 0 || len(buildName) > 0 || len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0 { return kcmdutil.UsageError(cmd, "The '--from-webhook' flag is incompatible with arguments and all '--from-*' flags") } path := kcmdutil.GetFlagString(cmd, "git-repository") postReceivePath := kcmdutil.GetFlagString(cmd, "git-post-receive") repo := git.NewRepository() return RunStartBuildWebHook(f, out, webhook, path, postReceivePath, repo) case len(args) != 1 && len(buildName) == 0: return kcmdutil.UsageError(cmd, "Must pass a name of a build config or specify build name with '--from-build' flag") } namespace, _, err := f.DefaultNamespace() if err != nil { return err } var ( name = buildName resource = "builds" ) if len(name) == 0 && len(args) > 0 && len(args[0]) > 0 { mapper, _ := f.Object() resource, name, err = cmdutil.ResolveResource("buildconfigs", args[0], mapper) if err != nil { return err } switch resource { case "buildconfigs": // no special handling required case "builds": return fmt.Errorf("use --from-build to rerun your builds") default: return fmt.Errorf("invalid resource provided: %s", resource) } } if len(name) == 0 { return fmt.Errorf("a resource name is required either as an argument or by using --from-build") } if webhooks.Provided() { return RunListBuildWebHooks(f, out, cmd.Out(), name, resource, webhooks.String()) } client, _, err := f.Clients() if err != nil { return err } env, _, err := cmdutil.ParseEnv(envParams, in) if err != nil { return err } if len(buildLogLevel) > 0 { env = append(env, kapi.EnvVar{Name: "BUILD_LOGLEVEL", Value: buildLogLevel}) } request := &buildapi.BuildRequest{ ObjectMeta: kapi.ObjectMeta{Name: name}, } if len(env) > 0 { request.Env = env } if len(commit) > 0 { request.Revision = &buildapi.SourceRevision{ Git: &buildapi.GitSourceRevision{ Commit: commit, }, } } git := git.NewRepository() var newBuild *buildapi.Build switch { case len(args) > 0 && (len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0): request := &buildapi.BinaryBuildRequestOptions{ ObjectMeta: kapi.ObjectMeta{ Name: name, Namespace: namespace, }, Commit: commit, } if len(env) > 0 { fmt.Fprintf(cmd.Out(), "WARNING: Specifying environment variables with binary builds is not supported.\n") } if newBuild, err = streamPathToBuild(git, in, cmd.Out(), client.BuildConfigs(namespace), fromDir, fromFile, fromRepo, request); err != nil { return err } case resource == "builds": if newBuild, err = client.Builds(namespace).Clone(request); err != nil { return err } case resource == "buildconfigs": if newBuild, err = client.BuildConfigs(namespace).Instantiate(request); err != nil { return err } default: return fmt.Errorf("invalid resource provided: %s", resource) } fmt.Fprintln(out, newBuild.Name) // mapper, typer := f.Object() // resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()} // info, err := resourceMapper.InfoForObject(newBuild) // if err != nil { // return err // } // shortOutput := kcmdutil.GetFlagString(cmd, "output") == "name" // kcmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "started") var ( wg sync.WaitGroup exitErr error ) // Wait for the build to complete if waitForComplete { wg.Add(1) go func() { defer wg.Done() exitErr = WaitForBuildComplete(client.Builds(namespace), newBuild.Name) }() } // Stream the logs from the build if follow { wg.Add(1) go func() { // if --wait option is set, then don't wait for logs to finish streaming // but wait for the build to reach its final state if waitForComplete { wg.Done() } else { defer wg.Done() } opts := buildapi.BuildLogOptions{ Follow: true, NoWait: false, } for { rd, err := client.BuildLogs(namespace).Get(newBuild.Name, opts).Stream() if err != nil { // if --wait options is set, then retry the connection to build logs // when we hit the timeout. if waitForComplete && errors.IsTimeoutErr(err) { continue } fmt.Fprintf(cmd.Out(), "error getting logs: %v\n", err) return } defer rd.Close() if _, err = io.Copy(out, rd); err != nil { fmt.Fprintf(cmd.Out(), "error streaming logs: %v\n", err) } break } }() } wg.Wait() return exitErr }