From 019d0a0c11054f44bfa23a5d840c175e8b954b6b Mon Sep 17 00:00:00 2001 From: Debashich Date: Sat, 29 Aug 2026 00:13:29 +0530 Subject: [PATCH] feat: add JSON output to taskrun delete Signed-off-by: Debashich --- pkg/cmd/taskrun/delete.go | 53 +++++++++++++++++++++++++--------- pkg/cmd/taskrun/delete_test.go | 40 +++++++++++++++++++++++++ pkg/deleter/deleter.go | 8 +++++ pkg/deleter/deleter_test.go | 24 +++++++++++++++ 4 files changed, 112 insertions(+), 13 deletions(-) diff --git a/pkg/cmd/taskrun/delete.go b/pkg/cmd/taskrun/delete.go index aded57b77b..526cec4748 100644 --- a/pkg/cmd/taskrun/delete.go +++ b/pkg/cmd/taskrun/delete.go @@ -15,6 +15,7 @@ package taskrun import ( + "encoding/json" "errors" "fmt" "strings" @@ -92,6 +93,11 @@ or Err: cmd.OutOrStderr(), } + output, err := cmd.LocalFlags().GetString("output") + if err != nil { + return err + } + if deleteOpts.TaskName != "" { opts.ParentResource = "Task" opts.ParentResourceName = deleteOpts.TaskName @@ -122,11 +128,15 @@ or return errs } - if err := opts.CheckOptions(s, availableTrs, p.Namespace()); err != nil { - return err - } + checkStreams := s + if output == "json" { + checkStreams = &cli.Stream{In: strings.NewReader("y\n"), Out: &strings.Builder{}, Err: s.Err} + } + if err := opts.CheckOptions(checkStreams, availableTrs, p.Namespace()); err != nil { + return err + } - if err := deleteTaskRuns(s, p, availableTrs, opts); err != nil { + if err := deleteTaskRuns(s, p, availableTrs, opts, output); err != nil { return err } return errs @@ -144,7 +154,7 @@ or return c } -func deleteTaskRuns(s *cli.Stream, p cli.Params, trNames []string, opts *options.DeleteOptions) error { +func deleteTaskRuns(s *cli.Stream, p cli.Params, trNames []string, opts *options.DeleteOptions, output string) error { var numberOfDeletedTr, numberOfKeptTr int cs, err := p.Clients() if err != nil { @@ -177,9 +187,13 @@ func deleteTaskRuns(s *cli.Stream, p cli.Params, trNames []string, opts *options prFinished := ownerPrFinished(cs, *tr) if !prFinished && opts.ForceDelete { - fmt.Fprintf(s.Out, "warning: Taskrun %s related pipelinerun still running.\n", tr.Name) + if output == "json" { + fmt.Fprintf(s.Err, "warning: Taskrun %s related pipelinerun still running.\n", tr.Name) + } else { + fmt.Fprintf(s.Out, "warning: Taskrun %s related pipelinerun still running.\n", tr.Name) + } } - if !prFinished && !opts.ForceDelete { + if !prFinished && !opts.ForceDelete && output != "json" { fmt.Fprintf(s.Out, "TaskRun(s): %s attached to PipelineRun is still running deleting will restart the completed taskrun. Proceed (y/n): ", tr.Name) if err := opts.TakeInput(s, ""); err != nil { continue @@ -212,16 +226,29 @@ func deleteTaskRuns(s *cli.Stream, p cli.Params, trNames []string, opts *options }) if opts.Keep > 0 && opts.Keep == len(trToKeep) && len(trToDelete) == 0 { - fmt.Fprintf(s.Out, "Associated %s (%d) for Task:%s is/are equal to keep (%d) \n", opts.Resource, len(trToKeep), opts.ParentResourceName, opts.Keep) - return nil - } - if opts.Keep > len(trToKeep) { - fmt.Fprintf(s.Out, "There is/are only %d %s(s) associated for %s: %s \n", len(trToKeep), opts.Resource, opts.ParentResource, opts.ParentResourceName) - return nil + if output != "json" { + fmt.Fprintf(s.Out, "Associated %s (%d) for Task:%s is/are equal to keep (%d) \n", opts.Resource, len(trToKeep), opts.ParentResourceName, opts.Keep) + return nil + } + } else if opts.Keep > len(trToKeep) { + if output != "json" { + fmt.Fprintf(s.Out, "There is/are only %d %s(s) associated for %s: %s \n", len(trToKeep), opts.Resource, opts.ParentResource, opts.ParentResourceName) + return nil + } } d.DeleteRelated([]string{opts.ParentResourceName}) } + if output == "json" { + result := struct { + Deleted []string `json:"deleted"` + }{ + Deleted: append(append([]string(nil), d.SuccessfulRelatedDeletes()...), d.SuccessfulDeletes()...), + } + encodeErr := json.NewEncoder(s.Out).Encode(result) + return multierr.Append(encodeErr, d.Errors()) + } + if !opts.DeleteAllNs { if d.Errors() == nil { switch { diff --git a/pkg/cmd/taskrun/delete_test.go b/pkg/cmd/taskrun/delete_test.go index 061853d43d..38cdcf198a 100644 --- a/pkg/cmd/taskrun/delete_test.go +++ b/pkg/cmd/taskrun/delete_test.go @@ -572,6 +572,46 @@ func TestTaskRunDelete_v1beta1(t *testing.T) { wantError: false, want: "All 6 TaskRuns associated with Task \"random\" deleted in namespace \"ns\"\n", }, + { + name: "With JSON output", + command: []string{"rm", "tr0-1", "-n", "ns", "-o", "json"}, + dynamic: seeds[15].dynamicClient, + input: seeds[15].pipelineClient, + inputStream: nil, + wantError: false, + want: `{"deleted":["tr0-1"]} +`, + }, + { + name: "With JSON output for multiple TaskRuns", + command: []string{"rm", "tr0-1", "tr0-2", "-n", "ns", "-o", "json"}, + dynamic: seeds[16].dynamicClient, + input: seeds[16].pipelineClient, + inputStream: strings.NewReader("y\n"), + wantError: false, + want: `{"deleted":["tr0-1","tr0-2"]} +`, + }, + { + name: "Delete with JSON output for --task but keep meets or exceeds existing (no-op)", + command: []string{"rm", "--task", "random", "-n", "ns", "--keep", "10", "-o", "json"}, + dynamic: seeds[15].dynamicClient, + input: seeds[15].pipelineClient, + inputStream: nil, + wantError: false, + want: `{"deleted":[]} +`, + }, + { + name: "Delete with JSON output for --task", + command: []string{"rm", "--task", "random", "-n", "ns", "-o", "json"}, + dynamic: seeds[15].dynamicClient, + input: seeds[15].pipelineClient, + inputStream: nil, + wantError: false, + want: `{"deleted":["tr0-1","tr0-2","tr0-3","tr0-4"]} +`, + }, } for _, tp := range testParams { diff --git a/pkg/deleter/deleter.go b/pkg/deleter/deleter.go index 016b33b4b1..3264e07ac3 100644 --- a/pkg/deleter/deleter.go +++ b/pkg/deleter/deleter.go @@ -104,6 +104,14 @@ func (d *Deleter) PrintSuccesses(streams *cli.Stream) { } } +func (d *Deleter) SuccessfulDeletes() []string { + return append([]string(nil), d.successfulDeletes...) +} + +func (d *Deleter) SuccessfulRelatedDeletes() []string { + return append([]string(nil), d.successfulRelatedDeletes...) +} + // appendError adds that error to the list of accumulated errors that // have occurred during execution. func (d *Deleter) appendError(err error) { diff --git a/pkg/deleter/deleter_test.go b/pkg/deleter/deleter_test.go index 391bfe9bf9..054c22324b 100644 --- a/pkg/deleter/deleter_test.go +++ b/pkg/deleter/deleter_test.go @@ -1,6 +1,7 @@ package deleter import ( + "reflect" "strings" "testing" @@ -50,6 +51,29 @@ func TestDelete(t *testing.T) { } } +func TestSuccessfulDeletes(t *testing.T) { + d := New("FooBar", successfulDeleteFunc()) + d.Delete([]string{"foo", "bar"}) + + expected := []string{"foo", "bar"} + if got := d.SuccessfulDeletes(); !reflect.DeepEqual(got, expected) { + t.Errorf("expected %v, received %v", expected, got) + } +} + +func TestSuccessfulRelatedDeletes(t *testing.T) { + d := New("FooBar", successfulDeleteFunc()) + d.WithRelated("FooBarRun", successfulListFunc("fbr1", "fbr2"), successfulDeleteFunc()) + + deletedNames := d.Delete([]string{"foo"}) + d.DeleteRelated(deletedNames) + + expected := []string{"fbr1", "fbr2"} + if got := d.SuccessfulRelatedDeletes(); !reflect.DeepEqual(got, expected) { + t.Errorf("expected %v, received %v", expected, got) + } +} + func TestDeleteRelated(t *testing.T) { for _, tc := range []struct { description string