Skip to content

Commit a2075ff

Browse files
[CAP-8118] fix local dev server task and taskrun list behavior (#325)
Fix local dev server to properly handle `tasks list` and `taskruns list` commands: - `taskruns list`: - list all task runs without requiring a task ID filter (non-interactive only) - resolve task names (not just task IDs) when filtering task runs - populate `parentTaskRunId` and `rootTaskRunId` in task run responses - `tasks list`: - list all tasks without requiring a workflow version ID (non-interactive only) - reject workflow version IDs in local mode (they don't exist locally) GitOrigin-RevId: f4c262c6978c036fed9f9083a56acf891fe0227d
1 parent 3c38af0 commit a2075ff

File tree

12 files changed

+199
-44
lines changed

12 files changed

+199
-44
lines changed

cmd/tasklist.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Examples:
4141
}
4242

4343
var input workflowviews.TaskListInput
44+
input.Local = local
4445
err = command.ParseCommand(cmd, args, &input)
4546
if err != nil {
4647
return fmt.Errorf("failed to parse command: %w", err)

cmd/taskrunlist.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Examples:
4040
}
4141

4242
var input workflowviews.TaskRunListInput
43+
input.Local = local
4344
err = command.ParseCommand(cmd, args, &input)
4445
if err != nil {
4546
return fmt.Errorf("failed to parse command: %w", err)

pkg/tui/flows/workflow.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,7 @@ func (f *Workflow) versionRelease(ctx context.Context, input *workflowviews.Vers
179179

180180
func (f *Workflow) unspecifiedTask(ctx context.Context, action func(t *workflows.Task) tea.Cmd) tea.Cmd {
181181
if f.local {
182-
// when running locally, we don't have a workflow version id, so we just use a dummy one
183-
return f.taskList(ctx, &workflowviews.TaskListInput{WorkflowVersionID: "local"}, action)
182+
return f.taskList(ctx, &workflowviews.TaskListInput{}, action)
184183
}
185184

186185
return f.workflowList(ctx, &workflowviews.WorkflowInput{}, func(ctx context.Context, r resource.Resource) tea.Cmd {

pkg/tui/views/workflows/loader.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,10 @@ func (w *WorkflowLoader) GetTask(ctx context.Context, id string) (*wfclient.Task
275275

276276
func (w *WorkflowLoader) LoadTaskRunList(ctx context.Context, input TaskRunListInput, cur client.Cursor) (client.Cursor, []*wfclient.TaskRun, error) {
277277
pageSize := 20
278-
params := &client.ListTaskRunsParams{Limit: &pageSize, TaskId: pointers.From([]string{input.TaskID})}
278+
params := &client.ListTaskRunsParams{Limit: &pageSize}
279+
if input.TaskID != "" {
280+
params.TaskId = pointers.From([]string{input.TaskID})
281+
}
279282
if cur != "" {
280283
params.Cursor = &cur
281284
}
@@ -312,7 +315,10 @@ func (w *WorkflowLoader) LoadAllTasks(ctx context.Context, input TaskListInput)
312315
// progressive loading, so older runs beyond this limit will not be shown.
313316
func (w *WorkflowLoader) LoadAllTaskRuns(ctx context.Context, input TaskRunListInput) ([]*wfclient.TaskRun, error) {
314317
pageSize := 100
315-
params := &client.ListTaskRunsParams{Limit: &pageSize, TaskId: pointers.From([]string{input.TaskID})}
318+
params := &client.ListTaskRunsParams{Limit: &pageSize}
319+
if input.TaskID != "" {
320+
params.TaskId = pointers.From([]string{input.TaskID})
321+
}
316322

317323
_, taskRuns, err := w.taskRepo.ListTaskRuns(ctx, params)
318324
return taskRuns, err

pkg/tui/views/workflows/types.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type TaskListInput struct {
1111
WorkflowVersionID string `cli:"arg:0"`
1212
WorkflowID string
1313
LatestVersionOnly bool
14+
Local bool
1415
}
1516

1617
type TaskRunInput struct {
@@ -28,6 +29,7 @@ type VersionListInput struct {
2829

2930
type TaskRunListInput struct {
3031
TaskID string `cli:"arg:0"`
32+
Local bool
3133
}
3234

3335
type VersionReleaseInput struct {
@@ -37,14 +39,17 @@ type VersionReleaseInput struct {
3739
}
3840

3941
func (t TaskListInput) Validate(interactive bool) error {
40-
if !interactive && t.WorkflowVersionID == "" {
42+
if !interactive && t.Local && t.WorkflowVersionID != "" {
43+
return errors.New("workflow version id is not supported in local mode")
44+
}
45+
if !interactive && !t.Local && t.WorkflowVersionID == "" {
4146
return errors.New("workflow version id must be specified when output is not interactive")
4247
}
4348
return nil
4449
}
4550

4651
func (t TaskRunListInput) Validate(interactive bool) error {
47-
if !interactive && t.TaskID == "" {
52+
if !interactive && !t.Local && t.TaskID == "" {
4853
return errors.New("task id must be specified when output is not interactive")
4954
}
5055
return nil

pkg/tui/views/workflows/types_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ func TestTaskListInputValidate(t *testing.T) {
2424
input := TaskListInput{WorkflowVersionID: "wfv-123"}
2525
assert.NoError(t, input.Validate(false))
2626
})
27+
28+
t.Run("non-interactive local allows empty version ID", func(t *testing.T) {
29+
input := TaskListInput{Local: true}
30+
assert.NoError(t, input.Validate(false))
31+
})
32+
33+
t.Run("non-interactive local rejects version ID", func(t *testing.T) {
34+
input := TaskListInput{Local: true, WorkflowVersionID: "wfv-123"}
35+
err := input.Validate(false)
36+
require.Error(t, err)
37+
assert.Contains(t, err.Error(), "workflow version id is not supported in local mode")
38+
})
2739
}
2840

2941
func TestTaskRunInputValidate(t *testing.T) {
@@ -76,6 +88,16 @@ func TestTaskRunListInputValidate(t *testing.T) {
7688
input := TaskRunListInput{TaskID: "tsk-1"}
7789
assert.NoError(t, input.Validate(false))
7890
})
91+
92+
t.Run("non-interactive local allows empty task ID", func(t *testing.T) {
93+
input := TaskRunListInput{Local: true}
94+
assert.NoError(t, input.Validate(false))
95+
})
96+
97+
t.Run("non-interactive local with task ID succeeds", func(t *testing.T) {
98+
input := TaskRunListInput{TaskID: "tsk-1", Local: true}
99+
assert.NoError(t, input.Validate(false))
100+
})
79101
}
80102

81103
func TestVersionListInputValidate(t *testing.T) {

pkg/workflows/apiserver/internal/handler.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,17 @@ func GetTask(store *store.TaskStore, taskID string) *workflowclient.Task {
3737
return mapTask(task)
3838
}
3939

40-
func ListTaskRuns(store *store.TaskStore, taskID string) []*workflowclient.TaskRun {
41-
taskRuns := store.GetTaskRuns(taskID)
40+
func ListTaskRuns(s *store.TaskStore, taskID string) []*workflowclient.TaskRun {
41+
var taskRuns []*store.TaskRun
42+
if taskID == "" {
43+
taskRuns = s.GetAllTaskRuns()
44+
} else {
45+
taskRuns = s.GetTaskRuns(taskID)
46+
}
4247

4348
taskRunList := make([]*workflowclient.TaskRun, len(taskRuns))
4449
for i, taskRun := range taskRuns {
45-
taskRunList[i] = MapTaskRun(store, taskRun)
50+
taskRunList[i] = MapTaskRun(s, taskRun)
4651
}
4752

4853
return taskRunList

pkg/workflows/apiserver/internal/handler_test.go

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,53 @@ func (f *fakeRunner) StartTask(ctx context.Context, taskName string, input []byt
5757
}
5858

5959
func TestListTaskRuns(t *testing.T) {
60-
store := store.NewTaskStore()
60+
t.Run("by task ID", func(t *testing.T) {
61+
store := store.NewTaskStore()
6162

62-
store.SetTasks([]taskserver.Task{
63-
{
64-
Name: "test",
65-
},
63+
store.SetTasks([]taskserver.Task{
64+
{Name: "test"},
65+
})
66+
67+
store.StartTaskRun("test", []byte("abc"), nil)
68+
69+
tasks := store.GetTasks()
70+
got := internal.ListTaskRuns(store, tasks[0].ID)
71+
72+
require.Equal(t, 1, len(got))
73+
require.Equal(t, tasks[0].ID, got[0].TaskId)
6674
})
6775

68-
input := []byte("abc")
76+
t.Run("by task name", func(t *testing.T) {
77+
store := store.NewTaskStore()
6978

70-
store.StartTaskRun("test", input, nil)
79+
store.SetTasks([]taskserver.Task{
80+
{Name: "test"},
81+
})
7182

72-
tasks := store.GetTasks()
73-
got := internal.ListTaskRuns(store, tasks[0].ID)
83+
store.StartTaskRun("test", []byte("abc"), nil)
7484

75-
require.Equal(t, 1, len(got))
76-
require.Equal(t, tasks[0].ID, got[0].TaskId)
85+
tasks := store.GetTasks()
86+
got := internal.ListTaskRuns(store, "test")
87+
88+
require.Equal(t, 1, len(got))
89+
require.Equal(t, tasks[0].ID, got[0].TaskId)
90+
})
91+
92+
t.Run("all task runs when taskID is empty", func(t *testing.T) {
93+
store := store.NewTaskStore()
94+
95+
store.SetTasks([]taskserver.Task{
96+
{Name: "task1"},
97+
{Name: "task2"},
98+
})
99+
100+
store.StartTaskRun("task1", []byte("abc"), nil)
101+
store.StartTaskRun("task2", []byte("def"), nil)
102+
103+
got := internal.ListTaskRuns(store, "")
104+
105+
require.Equal(t, 2, len(got))
106+
})
77107
}
78108

79109
func TestGetTaskRun(t *testing.T) {

pkg/workflows/apiserver/internal/map.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,24 @@ func mapTaskRunStatus(status store.TaskRunStatus) workflowClient.TaskRunStatus {
3636
}
3737
}
3838

39+
func parentTaskRunID(taskRun *store.TaskRun) string {
40+
if taskRun.ParentTaskRunID != nil {
41+
return *taskRun.ParentTaskRunID
42+
}
43+
return ""
44+
}
45+
3946
func MapTaskRun(store *store.TaskStore, taskRun *store.TaskRun) *workflowClient.TaskRun {
4047
task := store.GetTaskByName(taskRun.TaskName)
4148

4249
return &workflowClient.TaskRun{
43-
Id: taskRun.ID,
44-
TaskId: task.ID,
45-
Status: mapTaskRunStatus(taskRun.Status),
46-
StartedAt: taskRun.StartedAt,
47-
CompletedAt: taskRun.CompletedAt,
50+
Id: taskRun.ID,
51+
TaskId: task.ID,
52+
Status: mapTaskRunStatus(taskRun.Status),
53+
StartedAt: taskRun.StartedAt,
54+
CompletedAt: taskRun.CompletedAt,
55+
ParentTaskRunId: parentTaskRunID(taskRun),
56+
RootTaskRunId: taskRun.RootTaskRunID,
4857
}
4958
}
5059

@@ -59,14 +68,16 @@ func mapTaskRunDetails(store *store.TaskStore, taskRun *store.TaskRun) *workflow
5968
_ = json.Unmarshal(taskRun.Input, &input)
6069

6170
return &workflowClient.TaskRunDetails{
62-
Id: taskRun.ID,
63-
TaskId: task.ID,
64-
Status: mapTaskRunStatus(taskRun.Status),
65-
StartedAt: taskRun.StartedAt,
66-
CompletedAt: taskRun.CompletedAt,
67-
Results: results,
68-
Input: input,
69-
Error: taskRun.Error,
71+
Id: taskRun.ID,
72+
TaskId: task.ID,
73+
Status: mapTaskRunStatus(taskRun.Status),
74+
StartedAt: taskRun.StartedAt,
75+
CompletedAt: taskRun.CompletedAt,
76+
Results: results,
77+
Input: input,
78+
Error: taskRun.Error,
79+
ParentTaskRunId: parentTaskRunID(taskRun),
80+
RootTaskRunId: taskRun.RootTaskRunID,
7081
}
7182
}
7283

pkg/workflows/apiserver/server.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,6 @@ func (h *ServerHandler) ListTaskRuns(w http.ResponseWriter, r *http.Request) {
175175
w.Header().Set("Content-Type", "application/json")
176176

177177
taskID := r.URL.Query().Get("taskId")
178-
if taskID == "" {
179-
handleError(w, fmt.Errorf("taskId is required"), http.StatusBadRequest)
180-
return
181-
}
182-
183178
json.NewEncoder(w).Encode(internal.ListTaskRuns(h.taskStore, taskID))
184179
}
185180

0 commit comments

Comments
 (0)