Skip to content

Commit 5ac6e6d

Browse files
feat: task wait command support -f argument (#535)
* feat: task wait command support -f argument * enhance table format * fix test fail * refactor * tidy
1 parent dcce548 commit 5ac6e6d

1 file changed

Lines changed: 104 additions & 4 deletions

File tree

pkg/cmd/task/wait/wait.go

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/OctopusDeploy/cli/pkg/cmd"
1010
"github.com/OctopusDeploy/cli/pkg/constants"
1111
"github.com/OctopusDeploy/cli/pkg/factory"
12+
"github.com/OctopusDeploy/cli/pkg/output"
1213
"github.com/OctopusDeploy/cli/pkg/util"
1314
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
1415
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tasks"
@@ -34,12 +35,23 @@ type WaitOptions struct {
3435
PollInterval int
3536
CancelOnTimeout bool
3637
ShowProgress bool
38+
Command *cobra.Command
3739
}
3840

3941
type ServerTasksCallback func([]string) ([]*tasks.Task, error)
4042
type TaskDetailsCallback func(string) (*tasks.TaskDetailsResource, error)
4143

42-
func NewWaitOps(dependencies *cmd.Dependencies, taskIDs []string, timeout int, pollInterval int, cancelOnTimeout bool, showProgress bool) *WaitOptions {
44+
type TaskAsJson struct {
45+
Id string `json:"Id"`
46+
Description string `json:"Description"`
47+
State string `json:"State"`
48+
StartTime *time.Time `json:"StartTime"`
49+
CompletedTime *time.Time `json:"CompletedTime"`
50+
Duration string `json:"Duration"`
51+
FinishedSuccessfully *bool `json:"FinishedSuccessfully"`
52+
}
53+
54+
func NewWaitOps(dependencies *cmd.Dependencies, taskIDs []string, timeout int, pollInterval int, cancelOnTimeout bool, showProgress bool, cmd *cobra.Command) *WaitOptions {
4355
return &WaitOptions{
4456
Dependencies: dependencies,
4557
TaskIDs: taskIDs,
@@ -50,6 +62,7 @@ func NewWaitOps(dependencies *cmd.Dependencies, taskIDs []string, timeout int, p
5062
PollInterval: pollInterval,
5163
CancelOnTimeout: cancelOnTimeout,
5264
ShowProgress: showProgress,
65+
Command: cmd,
5366
}
5467
}
5568

@@ -70,7 +83,7 @@ func NewCmdWait(f factory.Factory) *cobra.Command {
7083

7184
taskIDs = append(taskIDs, util.ReadValuesFromPipe()...)
7285
dependencies := cmd.NewDependencies(f, c)
73-
opts := NewWaitOps(dependencies, taskIDs, timeout, pollInterval, cancelOnTimeout, showProgress)
86+
opts := NewWaitOps(dependencies, taskIDs, timeout, pollInterval, cancelOnTimeout, showProgress, c)
7487

7588
return WaitRun(opts)
7689
},
@@ -106,6 +119,7 @@ func WaitRun(opts *WaitOptions) error {
106119
pendingTaskIDs := make([]string, 0)
107120
failedTaskIDs := make([]string, 0)
108121
formatter := NewTaskOutputFormatter(opts.Out)
122+
tableHeaderPrinted := false
109123

110124
for _, t := range serverTasks {
111125
if t.IsCompleted == nil || !*t.IsCompleted {
@@ -115,7 +129,11 @@ func WaitRun(opts *WaitOptions) error {
115129
failedTaskIDs = append(failedTaskIDs, t.ID)
116130
}
117131

118-
formatter.PrintTaskInfo(t)
132+
if shouldUseCustomOutputFormat(opts, t) {
133+
printTaskWithCustomFormat(opts, t, &tableHeaderPrinted)
134+
} else {
135+
formatter.PrintTaskInfo(t)
136+
}
119137
}
120138

121139
if len(pendingTaskIDs) == 0 {
@@ -156,7 +174,13 @@ func WaitRun(opts *WaitOptions) error {
156174
if t.FinishedSuccessfully != nil && !*t.FinishedSuccessfully {
157175
failedTaskIDs = append(failedTaskIDs, t.ID)
158176
}
159-
formatter.PrintTaskInfo(t)
177+
178+
if shouldUseCustomOutputFormat(opts, t) {
179+
printTaskWithCustomFormat(opts, t, &tableHeaderPrinted)
180+
} else {
181+
formatter.PrintTaskInfo(t)
182+
}
183+
160184
pendingTaskIDs = removeTaskID(pendingTaskIDs, t.ID)
161185
}
162186
}
@@ -235,3 +259,79 @@ func removeTaskID(taskIDs []string, taskID string) []string {
235259
}
236260
return taskIDs
237261
}
262+
263+
func getTaskMappers() output.Mappers[*tasks.Task] {
264+
return output.Mappers[*tasks.Task]{
265+
Json: func(task *tasks.Task) any {
266+
var duration string
267+
if task.StartTime != nil && task.CompletedTime != nil {
268+
duration = task.CompletedTime.Sub(*task.StartTime).Round(time.Second).String()
269+
}
270+
return TaskAsJson{
271+
Id: task.ID,
272+
Description: task.Description,
273+
State: task.State,
274+
StartTime: task.StartTime,
275+
CompletedTime: task.CompletedTime,
276+
Duration: duration,
277+
FinishedSuccessfully: task.FinishedSuccessfully,
278+
}
279+
},
280+
Table: output.TableDefinition[*tasks.Task]{
281+
Header: []string{"ID", "DESCRIPTION", "STATE", "STARTED", "COMPLETED", "DURATION"},
282+
Row: func(task *tasks.Task) []string {
283+
var startTime, completedTime, duration string
284+
if task.StartTime != nil {
285+
startTime = task.StartTime.Format("02-01-2006 15:04:05")
286+
}
287+
if task.CompletedTime != nil {
288+
completedTime = task.CompletedTime.Format("02-01-2006 15:04:05")
289+
}
290+
if task.StartTime != nil && task.CompletedTime != nil {
291+
duration = task.CompletedTime.Sub(*task.StartTime).Round(time.Second).String()
292+
}
293+
294+
state := task.State
295+
switch task.State {
296+
case "Failed", "TimedOut":
297+
state = output.Red(task.State)
298+
case "Success":
299+
state = output.Green(task.State)
300+
case "Queued", "Executing", "Cancelling", "Canceled":
301+
state = output.Yellow(task.State)
302+
}
303+
304+
return []string{task.ID, task.Description, state, startTime, completedTime, duration}
305+
},
306+
},
307+
Basic: nil, // Not used - we use the existing formatter for basic output
308+
}
309+
}
310+
311+
func shouldUseCustomOutputFormat(opts *WaitOptions, t *tasks.Task) bool {
312+
if opts.Command == nil {
313+
return false
314+
}
315+
316+
outputFormat, _ := opts.Command.Flags().GetString(constants.FlagOutputFormat)
317+
isFormatSpecified := opts.Command.Flags().Changed(constants.FlagOutputFormat)
318+
isJsonOrTable := outputFormat == constants.OutputFormatJson || outputFormat == constants.OutputFormatTable
319+
isTaskReady := !opts.ShowProgress || (t.IsCompleted != nil && *t.IsCompleted)
320+
321+
return isFormatSpecified && isJsonOrTable && isTaskReady
322+
}
323+
324+
func printTaskWithCustomFormat(opts *WaitOptions, t *tasks.Task, tableHeaderPrinted *bool) {
325+
outputFormat, _ := opts.Command.Flags().GetString(constants.FlagOutputFormat)
326+
327+
if outputFormat == constants.OutputFormatJson {
328+
_ = output.PrintResource(t, opts.Command, getTaskMappers())
329+
} else if outputFormat == constants.OutputFormatTable {
330+
mappers := getTaskMappers()
331+
if *tableHeaderPrinted {
332+
mappers.Table.Header = nil // Don't print header for subsequent updates
333+
}
334+
_ = output.PrintResource(t, opts.Command, mappers)
335+
*tableHeaderPrinted = true
336+
}
337+
}

0 commit comments

Comments
 (0)