diff --git a/pkg/clustertask/clustertask.go b/pkg/clustertask/clustertask.go index 80929c491..338b42c6e 100644 --- a/pkg/clustertask/clustertask.go +++ b/pkg/clustertask/clustertask.go @@ -30,6 +30,24 @@ import ( var clustertaskGroupResource = schema.GroupVersionResource{Group: "tekton.dev", Resource: "clustertasks"} +func GetAllClusterTaskNames(p cli.Params) ([]string, error) { + cs, err := p.Clients() + if err != nil { + return nil, err + } + + clustertasks, err := List(cs, metav1.ListOptions{}) + if err != nil { + return nil, err + } + + ret := []string{} + for _, item := range clustertasks.Items { + ret = append(ret, item.ObjectMeta.Name) + } + return ret, nil +} + func List(c *cli.Clients, opts metav1.ListOptions) (*v1beta1.ClusterTaskList, error) { unstructuredCT, err := actions.List(clustertaskGroupResource, c, "", opts) if err != nil { diff --git a/pkg/clustertask/clustertask_test.go b/pkg/clustertask/clustertask_test.go index 14a9ca7d5..a14675582 100644 --- a/pkg/clustertask/clustertask_test.go +++ b/pkg/clustertask/clustertask_test.go @@ -31,6 +31,90 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +func TestClusterTask_GetAllTaskNames(t *testing.T) { + version := "v1alpha1" + clock := clockwork.NewFakeClock() + ctdata := []*v1alpha1.ClusterTask{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "clustertask", + // created 5 minutes back + CreationTimestamp: metav1.Time{Time: clock.Now().Add(-5 * time.Minute)}, + }, + }, + } + cs, _ := test.SeedTestData(t, pipelinetest.Data{ + ClusterTasks: ctdata, + }) + cs.Pipeline.Resources = cb.APIResourceList(version, []string{"clustertask"}) + tdc := testDynamic.Options{} + dc, err := tdc.Client( + cb.UnstructuredCT(ctdata[0], version), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + + ctdata2 := []*v1alpha1.ClusterTask{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "clustertask", + // created 5 minutes back + CreationTimestamp: metav1.Time{Time: clock.Now().Add(-5 * time.Minute)}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "clustertask2", + // created 5 minutes back + CreationTimestamp: metav1.Time{Time: clock.Now().Add(-5 * time.Minute)}, + }, + }, + } + cs2, _ := test.SeedTestData(t, pipelinetest.Data{ + ClusterTasks: ctdata2, + }) + cs2.Pipeline.Resources = cb.APIResourceList(version, []string{"clustertask"}) + tdc2 := testDynamic.Options{} + dc2, err := tdc2.Client( + cb.UnstructuredCT(ctdata2[0], version), + cb.UnstructuredCT(ctdata2[1], version), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + + p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube, Dynamic: dc} + p2 := &test.Params{Tekton: cs2.Pipeline, Clock: clock, Kube: cs2.Kube, Dynamic: dc2} + + testParams := []struct { + name string + params *test.Params + want []string + }{ + { + name: "Single ClusterTask", + params: p, + want: []string{"clustertask"}, + }, + { + name: "Multi ClusterTasks", + params: p2, + want: []string{"clustertask", "clustertask2"}, + }, + } + + for _, tp := range testParams { + t.Run(tp.name, func(t *testing.T) { + got, err := GetAllClusterTaskNames(tp.params) + if err != nil { + t.Errorf("unexpected Error") + } + test.AssertOutput(t, tp.want, got) + }) + } +} + func TestClusterTask_List(t *testing.T) { version := "v1alpha1" clock := clockwork.NewFakeClock() diff --git a/pkg/cmd/clustertask/delete.go b/pkg/cmd/clustertask/delete.go index 911004428..a142e2c3f 100644 --- a/pkg/cmd/clustertask/delete.go +++ b/pkg/cmd/clustertask/delete.go @@ -86,7 +86,7 @@ func deleteClusterTasks(opts *options.DeleteOptions, s *cli.Stream, p cli.Params }) switch { case opts.DeleteAll: - cts, err := allClusterTaskNames(cs) + cts, err := clustertask.GetAllClusterTaskNames(p) if err != nil { return err } @@ -112,18 +112,6 @@ func deleteClusterTasks(opts *options.DeleteOptions, s *cli.Stream, p cli.Params return d.Errors() } -func allClusterTaskNames(cs *cli.Clients) ([]string, error) { - clusterTasks, err := clustertask.List(cs, metav1.ListOptions{}) - if err != nil { - return nil, err - } - var names []string - for _, ct := range clusterTasks.Items { - names = append(names, ct.Name) - } - return names, nil -} - func taskRunLister(cs *cli.Clients, p cli.Params) func(string) ([]string, error) { return func(taskName string) ([]string, error) { lOpts := metav1.ListOptions{ diff --git a/pkg/cmd/clustertask/describe.go b/pkg/cmd/clustertask/describe.go index a5012d789..d45f618cc 100644 --- a/pkg/cmd/clustertask/describe.go +++ b/pkg/cmd/clustertask/describe.go @@ -165,10 +165,18 @@ or } if len(args) == 0 { - err = askClusterTaskName(opts, p) + clusterTaskNames, err := clustertask.GetAllClusterTaskNames(p) if err != nil { return err } + if len(clusterTaskNames) == 1 { + opts.ClusterTaskName = clusterTaskNames[0] + } else { + err = askClusterTaskName(opts, clusterTaskNames) + if err != nil { + return err + } + } } else { opts.ClusterTaskName = args[0] } @@ -261,20 +269,11 @@ func sortResourcesByTypeAndName(tres []v1beta1.TaskResource) []v1beta1.TaskResou return tres } -func askClusterTaskName(opts *options.DescribeOptions, p cli.Params) error { - cs, err := p.Clients() - if err != nil { - return err - } - clusterTaskNames, err := allClusterTaskNames(cs) - if err != nil { - return err - } +func askClusterTaskName(opts *options.DescribeOptions, clusterTaskNames []string) error { if len(clusterTaskNames) == 0 { return fmt.Errorf("no ClusterTasks found") } - - err = opts.Ask(options.ResourceNameClusterTask, clusterTaskNames) + err := opts.Ask(options.ResourceNameClusterTask, clusterTaskNames) if err != nil { return err } diff --git a/pkg/cmd/clustertask/describe_test.go b/pkg/cmd/clustertask/describe_test.go index d3bd3b97e..2f726d1ee 100644 --- a/pkg/cmd/clustertask/describe_test.go +++ b/pkg/cmd/clustertask/describe_test.go @@ -271,6 +271,34 @@ func Test_ClusterTaskDescribe(t *testing.T) { } } +func TestClusterTaskDescribe_WithoutNameIfOnlyOneClusterTaskPresent(t *testing.T) { + cstasks := []*v1alpha1.ClusterTask{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "task-1", + }, + }, + } + version := "v1alpha1" + tdc := testDynamic.Options{} + dynamic, err := tdc.Client( + cb.UnstructuredCT(cstasks[0], version), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + + cs, _ := test.SeedTestData(t, pipelinetest.Data{ClusterTasks: cstasks}) + cs.Pipeline.Resources = cb.APIResourceList(version, []string{"clustertask", "taskrun"}) + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dynamic} + clusterTask := Command(p) + out, err := test.ExecuteCommand(clusterTask, "desc") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + golden.Assert(t, out, fmt.Sprintf("%s.golden", t.Name())) +} + func TestClusterTask_custom_output(t *testing.T) { name := "clustertask" expected := "clustertask.tekton.dev/" + name @@ -467,3 +495,32 @@ func TestClusterTaskDescribe_With_Workspaces(t *testing.T) { } golden.Assert(t, out, fmt.Sprintf("%s.golden", t.Name())) } + +func TestClusterTaskDescribe_WithoutNameIfOnlyOneV1beta1ClusterTaskPresent(t *testing.T) { + cttasks := []*v1beta1.ClusterTask{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "task-1", + }, + }, + } + + version := "v1beta1" + tdc := testDynamic.Options{} + dynamic, err := tdc.Client( + cb.UnstructuredV1beta1CT(cttasks[0], version), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + + cs, _ := test.SeedV1beta1TestData(t, pipelinev1beta1test.Data{ClusterTasks: cttasks}) + cs.Pipeline.Resources = cb.APIResourceList(version, []string{"clustertask", "taskrun"}) + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dynamic} + cttask := Command(p) + out, err := test.ExecuteCommand(cttask, "desc") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + golden.Assert(t, out, fmt.Sprintf("%s.golden", t.Name())) +} diff --git a/pkg/cmd/clustertask/testdata/TestClusterTaskDescribe_WithoutNameIfOnlyOneClusterTaskPresent.golden b/pkg/cmd/clustertask/testdata/TestClusterTaskDescribe_WithoutNameIfOnlyOneClusterTaskPresent.golden new file mode 100644 index 000000000..a200d5f15 --- /dev/null +++ b/pkg/cmd/clustertask/testdata/TestClusterTaskDescribe_WithoutNameIfOnlyOneClusterTaskPresent.golden @@ -0,0 +1,29 @@ +Name: task-1 + +Input Resources + + No input resources + +Output Resources + + No output resources + +Params + + No params + +Results + + No results + +Workspaces + + No workspaces + +Steps + + No steps + +Taskruns + + No taskruns diff --git a/pkg/cmd/clustertask/testdata/TestClusterTaskDescribe_WithoutNameIfOnlyOneV1beta1ClusterTaskPresent.golden b/pkg/cmd/clustertask/testdata/TestClusterTaskDescribe_WithoutNameIfOnlyOneV1beta1ClusterTaskPresent.golden new file mode 100644 index 000000000..a200d5f15 --- /dev/null +++ b/pkg/cmd/clustertask/testdata/TestClusterTaskDescribe_WithoutNameIfOnlyOneV1beta1ClusterTaskPresent.golden @@ -0,0 +1,29 @@ +Name: task-1 + +Input Resources + + No input resources + +Output Resources + + No output resources + +Params + + No params + +Results + + No results + +Workspaces + + No workspaces + +Steps + + No steps + +Taskruns + + No taskruns diff --git a/pkg/cmd/taskrun/describe.go b/pkg/cmd/taskrun/describe.go index 8624c8ca4..cb3c1a0f2 100644 --- a/pkg/cmd/taskrun/describe.go +++ b/pkg/cmd/taskrun/describe.go @@ -73,13 +73,21 @@ or } if len(args) == 0 { + lOpts := metav1.ListOptions{} if !opts.Last { - err = askTaskRunName(opts, p) + trs, err := trlist.GetAllTaskRuns(p, lOpts, opts.Limit) if err != nil { return err } + if len(trs) == 1 { + opts.TaskrunName = strings.Fields(trs[0])[0] + } else { + err = askTaskRunName(opts, trs) + if err != nil { + return err + } + } } else { - lOpts := metav1.ListOptions{} trs, err := trlist.GetAllTaskRuns(p, lOpts, 1) if err != nil { return err @@ -113,18 +121,12 @@ or return c } -func askTaskRunName(opts *options.DescribeOptions, p cli.Params) error { - lOpts := metav1.ListOptions{} - +func askTaskRunName(opts *options.DescribeOptions, trs []string) error { err := opts.ValidateOpts() if err != nil { return err } - trs, err := trlist.GetAllTaskRuns(opts.Params, lOpts, opts.Limit) - if err != nil { - return err - } if len(trs) == 0 { return fmt.Errorf("no TaskRuns found") } diff --git a/pkg/cmd/taskrun/describe_test.go b/pkg/cmd/taskrun/describe_test.go index 6e3a737fa..5e4c05980 100644 --- a/pkg/cmd/taskrun/describe_test.go +++ b/pkg/cmd/taskrun/describe_test.go @@ -780,6 +780,71 @@ func TestTaskRunWithSpecDescribe_custom_timeout(t *testing.T) { golden.Assert(t, actual, fmt.Sprintf("%s.golden", t.Name())) } +func TestTaskRunDescribe_WithoutNameIfOnlyOneTaskRunPresent(t *testing.T) { + clock := clockwork.NewFakeClock() + + trs := []*v1alpha1.TaskRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Namespace: "ns", + Name: "tr-1", + Labels: map[string]string{"tekton.dev/task": "t1"}, + }, + Spec: v1alpha1.TaskRunSpec{ + TaskRef: &v1alpha1.TaskRef{ + Name: "t1", + }, + }, + Status: v1alpha1.TaskRunStatus{ + Status: duckv1beta1.Status{ + Conditions: duckv1beta1.Conditions{ + { + Status: corev1.ConditionTrue, + Reason: v1beta1.TaskRunReasonSuccessful.String(), + }, + }, + }, + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + StartTime: &metav1.Time{Time: clock.Now().Add(-10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: clock.Now().Add(-5 * time.Minute)}, + }, + }, + }, + } + + cs, _ := test.SeedTestData(t, pipelinetest.Data{ + TaskRuns: trs, + Namespaces: []*corev1.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "ns", + }, + }, + }, + }) + + version := "v1alpha1" + tdc := testDynamic.Options{} + dynamic, err := tdc.Client( + cb.UnstructuredTR(trs[0], version), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + cs.Pipeline.Resources = cb.APIResourceList(version, []string{"taskrun"}) + if err != nil { + fmt.Println(err) + } + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dynamic, Clock: clock} + taskrun := Command(p) + clock.Advance(10 * time.Minute) + actual, err := test.ExecuteCommand(taskrun, "desc", "-n", "ns") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + golden.Assert(t, actual, fmt.Sprintf("%s.golden", t.Name())) +} + func TestTaskRunDescribe_lastV1beta1(t *testing.T) { clock := clockwork.NewFakeClock() taskRuns := []*v1beta1.TaskRun{ @@ -1155,3 +1220,63 @@ func TestTaskRunDescribe_With_Workspaces(t *testing.T) { } golden.Assert(t, got, fmt.Sprintf("%s.golden", t.Name())) } + +func TestTaskRunDescribe_WithoutNameIfOnlyOneV1beta1TaskRunPresent(t *testing.T) { + clock := clockwork.NewFakeClock() + taskRuns := []*v1beta1.TaskRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Namespace: "ns", + Name: "tr-1", + Labels: map[string]string{"tekton.dev/task": "task-1"}, + }, + Spec: v1beta1.TaskRunSpec{ + TaskRef: &v1beta1.TaskRef{ + Name: "task-1", + }, + }, + Status: v1beta1.TaskRunStatus{ + Status: duckv1beta1.Status{ + Conditions: duckv1beta1.Conditions{ + { + Status: corev1.ConditionFalse, + Reason: v1beta1.TaskRunReasonFailed.String(), + }, + }, + }, + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + StartTime: &metav1.Time{Time: clock.Now().Add(-10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: clock.Now().Add(-5 * time.Minute)}, + }, + }, + }, + } + + namespaces := []*corev1.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "ns", + }, + }, + } + + version := "v1beta1" + tdc := testDynamic.Options{} + dynamic, err := tdc.Client( + cb.UnstructuredV1beta1TR(taskRuns[0], version), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + + cs, _ := test.SeedV1beta1TestData(t, pipelinev1beta1test.Data{Namespaces: namespaces, TaskRuns: taskRuns}) + cs.Pipeline.Resources = cb.APIResourceList(version, []string{"taskrun"}) + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dynamic} + p.SetNamespace("ns") + taskrun := Command(p) + out, err := test.ExecuteCommand(taskrun, "desc") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + golden.Assert(t, out, fmt.Sprintf("%s.golden", t.Name())) +} diff --git a/pkg/cmd/taskrun/testdata/TestTaskRunDescribe_WithoutNameIfOnlyOneTaskRunPresent.golden b/pkg/cmd/taskrun/testdata/TestTaskRunDescribe_WithoutNameIfOnlyOneTaskRunPresent.golden new file mode 100644 index 000000000..4a142392d --- /dev/null +++ b/pkg/cmd/taskrun/testdata/TestTaskRunDescribe_WithoutNameIfOnlyOneTaskRunPresent.golden @@ -0,0 +1,38 @@ +Name: tr-1 +Namespace: ns +Task Ref: t1 +Labels: + tekton.dev/task=t1 + +Status + +STARTED DURATION STATUS +20 minutes ago 5 minutes Succeeded + +Input Resources + + No input resources + +Output Resources + + No output resources + +Params + + No params + +Results + + No results + +Workspaces + + No workspaces + +Steps + +No steps + +Sidecars + +No sidecars diff --git a/pkg/cmd/taskrun/testdata/TestTaskRunDescribe_WithoutNameIfOnlyOneV1beta1TaskRunPresent.golden b/pkg/cmd/taskrun/testdata/TestTaskRunDescribe_WithoutNameIfOnlyOneV1beta1TaskRunPresent.golden new file mode 100644 index 000000000..3557c8f79 --- /dev/null +++ b/pkg/cmd/taskrun/testdata/TestTaskRunDescribe_WithoutNameIfOnlyOneV1beta1TaskRunPresent.golden @@ -0,0 +1,38 @@ +Name: tr-1 +Namespace: ns +Task Ref: task-1 +Labels: + tekton.dev/task=task-1 + +Status + +STARTED DURATION STATUS +10 minutes ago 5 minutes Failed + +Input Resources + + No input resources + +Output Resources + + No output resources + +Params + + No params + +Results + + No results + +Workspaces + + No workspaces + +Steps + +No steps + +Sidecars + +No sidecars