diff --git a/cmd/argo/commands/common.go b/cmd/argo/commands/common.go index 364eba970de6..cc252fc9d039 100644 --- a/cmd/argo/commands/common.go +++ b/cmd/argo/commands/common.go @@ -46,6 +46,9 @@ const ( FgDefault = 39 ) +// Default status for printWorkflow +const DefaultStatus = "" + func initializeSession() { jobStatusIconMap = map[wfv1.NodePhase]string{ wfv1.NodePending: ansiFormat("◷", FgYellow), diff --git a/cmd/argo/commands/get.go b/cmd/argo/commands/get.go index ef7b399887f0..edd741090218 100644 --- a/cmd/argo/commands/get.go +++ b/cmd/argo/commands/get.go @@ -18,9 +18,14 @@ import ( const onExitSuffix = "onExit" +type getFlags struct { + output string + status string +} + func NewGetCommand() *cobra.Command { var ( - output string + getArgs getFlags ) var command = &cobra.Command{ @@ -40,17 +45,22 @@ func NewGetCommand() *cobra.Command { if err != nil { log.Fatal(err) } - printWorkflow(wf, output) + printWorkflow(wf, getArgs.output, getArgs.status) }, } - command.Flags().StringVarP(&output, "output", "o", "", "Output format. One of: json|yaml|wide") + command.Flags().StringVarP(&getArgs.output, "output", "o", "", "Output format. One of: json|yaml|wide") command.Flags().BoolVar(&noColor, "no-color", false, "Disable colorized output") + command.Flags().StringVar(&getArgs.status, "status", "", "Filter by status (Pending, Running, Succeeded, Skipped, Failed, Error)") return command } -func printWorkflow(wf *wfv1.Workflow, outFmt string) { - switch outFmt { +func printWorkflow(wf *wfv1.Workflow, output, status string) { + getArgs := getFlags{ + output: output, + status: status, + } + switch getArgs.output { case "name": fmt.Println(wf.ObjectMeta.Name) case "json": @@ -60,13 +70,13 @@ func printWorkflow(wf *wfv1.Workflow, outFmt string) { outBytes, _ := yaml.Marshal(wf) fmt.Print(string(outBytes)) case "wide", "": - printWorkflowHelper(wf, outFmt) + printWorkflowHelper(wf, getArgs) default: - log.Fatalf("Unknown output format: %s", outFmt) + log.Fatalf("Unknown output format: %s", getArgs.output) } } -func printWorkflowHelper(wf *wfv1.Workflow, outFmt string) { +func printWorkflowHelper(wf *wfv1.Workflow, getArgs getFlags) { const fmtStr = "%-20s %v\n" fmt.Printf(fmtStr, "Name:", wf.ObjectMeta.Name) fmt.Printf(fmtStr, "Namespace:", wf.ObjectMeta.Namespace) @@ -128,7 +138,7 @@ func printWorkflowHelper(wf *wfv1.Workflow, outFmt string) { w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) fmt.Println() // apply a dummy FgDefault format to align tabwriter with the rest of the columns - if outFmt == "wide" { + if getArgs.output == "wide" { fmt.Fprintf(w, "%s\tPODNAME\tDURATION\tARTIFACTS\tMESSAGE\n", ansiFormat("STEP", FgDefault)) } else { fmt.Fprintf(w, "%s\tPODNAME\tDURATION\tMESSAGE\n", ansiFormat("STEP", FgDefault)) @@ -139,12 +149,12 @@ func printWorkflowHelper(wf *wfv1.Workflow, outFmt string) { // Print main and onExit Trees mainRoot := roots[wf.ObjectMeta.Name] - mainRoot.renderNodes(w, wf, 0, " ", " ", outFmt) + mainRoot.renderNodes(w, wf, 0, " ", " ", getArgs) onExitID := wf.NodeID(wf.ObjectMeta.Name + "." + onExitSuffix) if onExitRoot, ok := roots[onExitID]; ok { fmt.Fprintf(w, "\t\t\t\t\t\n") - onExitRoot.renderNodes(w, wf, 0, " ", " ", outFmt) + onExitRoot.renderNodes(w, wf, 0, " ", " ", getArgs) } _ = w.Flush() } @@ -175,7 +185,7 @@ func (n *nodeInfo) getStartTime(wf *wfv1.Workflow) metav1.Time { // Interface to represent Nodes in render form types type renderNode interface { // Render this renderNode and its children - renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string) + renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, getArgs getFlags) nodeInfoInterface } @@ -364,7 +374,7 @@ func filterNode(node wfv1.NodeStatus) (bool, bool) { // whether it was filtered and does this child need special indent func renderChild(w *tabwriter.Writer, wf *wfv1.Workflow, nInfo renderNode, depth int, nodePrefix string, childPrefix string, parentFiltered bool, - childIndex int, maxIndex int, childIndent bool, outFmt string) { + childIndex int, maxIndex int, childIndent bool, getArgs getFlags) { var part, subp string if parentFiltered && childIndent { if maxIndex == 0 { @@ -402,11 +412,14 @@ func renderChild(w *tabwriter.Writer, wf *wfv1.Workflow, nInfo renderNode, depth } childChldPrefix = childPrefix + subp } - nInfo.renderNodes(w, wf, depth, childNodePrefix, childChldPrefix, outFmt) + nInfo.renderNodes(w, wf, depth, childNodePrefix, childChldPrefix, getArgs) } // Main method to print information of node in get -func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, depth int, nodePrefix string, childPrefix string, outFmt string) { +func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, depth int, nodePrefix string, childPrefix string, getArgs getFlags) { + if getArgs.status != "" && string(node.Phase) != getArgs.status { + return + } nodeName := fmt.Sprintf("%s %s", jobStatusIconMap[node.Phase], node.DisplayName) var args []interface{} duration := humanize.RelativeDurationShort(node.StartedAt.Time, node.FinishedAt.Time) @@ -415,7 +428,7 @@ func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, dep } else { args = []interface{}{nodePrefix, nodeName, "", "", node.Message} } - if outFmt == "wide" { + if getArgs.output == "wide" { msg := args[len(args)-1] args[len(args)-1] = getArtifactsString(node) args = append(args, msg) @@ -427,36 +440,36 @@ func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, dep // renderNodes for each renderNode Type // boundaryNode -func (nodeInfo *boundaryNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string) { +func (nodeInfo *boundaryNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, getArgs getFlags) { filtered, childIndent := filterNode(nodeInfo.getNodeStatus(wf)) if !filtered { - printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, outFmt) + printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, getArgs) } for i, nInfo := range nodeInfo.boundaryContained { renderChild(w, wf, nInfo, depth, nodePrefix, childPrefix, filtered, i, - len(nodeInfo.boundaryContained)-1, childIndent, outFmt) + len(nodeInfo.boundaryContained)-1, childIndent, getArgs) } } // nonBoundaryParentNode -func (nodeInfo *nonBoundaryParentNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string) { +func (nodeInfo *nonBoundaryParentNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, getArgs getFlags) { filtered, childIndent := filterNode(nodeInfo.getNodeStatus(wf)) if !filtered { - printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, outFmt) + printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, getArgs) } for i, nInfo := range nodeInfo.children { renderChild(w, wf, nInfo, depth, nodePrefix, childPrefix, filtered, i, - len(nodeInfo.children)-1, childIndent, outFmt) + len(nodeInfo.children)-1, childIndent, getArgs) } } // executionNode -func (nodeInfo *executionNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string) { +func (nodeInfo *executionNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, getArgs getFlags) { filtered, _ := filterNode(nodeInfo.getNodeStatus(wf)) if !filtered { - printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, outFmt) + printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, getArgs) } } diff --git a/cmd/argo/commands/resubmit.go b/cmd/argo/commands/resubmit.go index 94437b0b61b3..b5243723de6b 100644 --- a/cmd/argo/commands/resubmit.go +++ b/cmd/argo/commands/resubmit.go @@ -30,7 +30,7 @@ func NewResubmitCommand() *cobra.Command { errors.CheckError(err) created, err := util.SubmitWorkflow(wfClient, newWF, nil) errors.CheckError(err) - printWorkflow(created, cliSubmitOpts.output) + printWorkflow(created, cliSubmitOpts.output, DefaultStatus) waitOrWatch([]string{created.Name}, cliSubmitOpts) }, } diff --git a/cmd/argo/commands/retry.go b/cmd/argo/commands/retry.go index 43002427d9a2..95434b7de0a7 100644 --- a/cmd/argo/commands/retry.go +++ b/cmd/argo/commands/retry.go @@ -32,7 +32,7 @@ func NewRetryCommand() *cobra.Command { if err != nil { log.Fatal(err) } - printWorkflow(wf, cliSubmitOpts.output) + printWorkflow(wf, cliSubmitOpts.output, DefaultStatus) waitOrWatch([]string{wf.Name}, cliSubmitOpts) }, } diff --git a/cmd/argo/commands/submit.go b/cmd/argo/commands/submit.go index 6210bf8d93f2..0337f588b84d 100644 --- a/cmd/argo/commands/submit.go +++ b/cmd/argo/commands/submit.go @@ -118,7 +118,7 @@ func SubmitWorkflows(filePaths []string, submitOpts *util.SubmitOpts, cliOpts *c if err != nil { log.Fatalf("Failed to submit workflow: %v", err) } - printWorkflow(created, cliOpts.output) + printWorkflow(created, cliOpts.output, DefaultStatus) workflowNames = append(workflowNames, created.Name) } waitOrWatch(workflowNames, *cliOpts) diff --git a/cmd/argo/commands/watch.go b/cmd/argo/commands/watch.go index c1ca07f4396a..4fa5531e7c84 100644 --- a/cmd/argo/commands/watch.go +++ b/cmd/argo/commands/watch.go @@ -58,7 +58,7 @@ func watchWorkflow(name string) { errors.CheckError(err) print("\033[H\033[2J") print("\033[0;0H") - printWorkflowHelper(wf, "") + printWorkflowHelper(wf, getFlags{}) if !wf.Status.FinishedAt.IsZero() { break }