From 4c6433318e231b90a12ef2146bfc2cca8ff22464 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Date: Wed, 25 Mar 2020 15:19:46 +0530 Subject: [PATCH] v1beta1 support for pipeline list cmd this adds v1beta1 support for pipeline list command minor refactor to taskrun list Signed-off-by: Pradeep Kumar pradkuma@redhat.com --- pkg/cmd/pipeline/list.go | 46 ++------ pkg/cmd/pipeline/list_test.go | 111 ++++++++++++++---- ...PipelineList_only_pipelines_v1beta1.golden | 4 + pkg/cmd/taskrun/list.go | 7 +- pkg/pipeline/pipeline.go | 27 +++++ pkg/taskrun/list/list.go | 17 +-- pkg/test/builder/unstructured.go | 9 ++ 7 files changed, 152 insertions(+), 69 deletions(-) create mode 100644 pkg/cmd/pipeline/testdata/TestPipelineList_only_pipelines_v1beta1.golden diff --git a/pkg/cmd/pipeline/list.go b/pkg/cmd/pipeline/list.go index ff544cdaa..afb1b3454 100644 --- a/pkg/cmd/pipeline/list.go +++ b/pkg/cmd/pipeline/list.go @@ -16,7 +16,6 @@ package pipeline import ( "fmt" - "io" "os" "text/tabwriter" "text/template" @@ -24,11 +23,11 @@ import ( "github.com/spf13/cobra" "github.com/tektoncd/cli/pkg/cli" "github.com/tektoncd/cli/pkg/formatted" + "github.com/tektoncd/cli/pkg/list" "github.com/tektoncd/cli/pkg/pipeline" - "github.com/tektoncd/cli/pkg/printer" validate "github.com/tektoncd/cli/pkg/validate" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" - "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" cliopts "k8s.io/cli-runtime/pkg/genericclioptions" @@ -73,7 +72,8 @@ func listCommand(p cli.Params) *cobra.Command { } if output != "" { - return printPipelineListObj(cmd.OutOrStdout(), p, f) + pipelineGroupResource := schema.GroupVersionResource{Group: "tekton.dev", Resource: "pipelines"} + return list.PrintObject(pipelineGroupResource, cmd.OutOrStdout(), p, f, p.Namespace()) } stream := &cli.Stream{ Out: cmd.OutOrStdout(), @@ -102,7 +102,7 @@ func printPipelineDetails(s *cli.Stream, p cli.Params) error { } var data = struct { - Pipelines *v1alpha1.PipelineList + Pipelines *v1beta1.PipelineList PipelineRuns pipelineruns Params cli.Params }{ @@ -134,43 +134,11 @@ func printPipelineDetails(s *cli.Stream, p cli.Params) error { return w.Flush() } -func printPipelineListObj(w io.Writer, p cli.Params, f *cliopts.PrintFlags) error { - cs, err := p.Clients() - if err != nil { - return err - } - - ps, err := listAllPipelines(cs.Tekton, p.Namespace()) - if err != nil { - return err - } - - return printer.PrintObject(w, ps, f) -} - -func listAllPipelines(cs versioned.Interface, ns string) (*v1alpha1.PipelineList, error) { - c := cs.TektonV1alpha1().Pipelines(ns) - - ps, err := c.List(metav1.ListOptions{}) - if err != nil { - return nil, err - } - - // NOTE: this is required for -o json|yaml to work properly since - // tektoncd go client fails to set these; probably a bug - ps.GetObjectKind().SetGroupVersionKind( - schema.GroupVersionKind{ - Version: "tekton.dev/v1alpha1", - Kind: "PipelineList", - }) - return ps, nil -} - type pipelineruns map[string]v1alpha1.PipelineRun -func listPipelineDetails(cs *cli.Clients, ns string) (*v1alpha1.PipelineList, pipelineruns, error) { +func listPipelineDetails(cs *cli.Clients, ns string) (*v1beta1.PipelineList, pipelineruns, error) { - ps, err := listAllPipelines(cs.Tekton, ns) + ps, err := pipeline.List(cs, metav1.ListOptions{}, ns) if err != nil { return nil, nil, err } diff --git a/pkg/cmd/pipeline/list_test.go b/pkg/cmd/pipeline/list_test.go index 01ee1a889..7efe71244 100644 --- a/pkg/cmd/pipeline/list_test.go +++ b/pkg/cmd/pipeline/list_test.go @@ -22,6 +22,7 @@ import ( "github.com/jonboulle/clockwork" "github.com/tektoncd/cli/pkg/test" cb "github.com/tektoncd/cli/pkg/test/builder" + testDynamic "github.com/tektoncd/cli/pkg/test/dynamic" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun/resources" pipelinetest "github.com/tektoncd/pipeline/test" @@ -66,7 +67,13 @@ func TestPipelinesList_empty(t *testing.T) { } cs, _ := test.SeedTestData(t, pipelinetest.Data{Namespaces: nsList}) - p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube} + cs.Pipeline.Resources = cb.APIResourceList("v1alpha1", "pipeline") + dc, err := testDynamic.Client() + if err != nil { + t.Errorf("unable to create dynamic clinet: %v", err) + } + + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dc} pipeline := Command(p) output, err := test.ExecuteCommand(pipeline, "list", "-n", "foo") @@ -91,10 +98,55 @@ func TestPipelineList_only_pipelines(t *testing.T) { }, }, } + version := "v1alpha1" + clock := clockwork.NewFakeClock() + cs, pdata := seedPipelines(t, clock, pipelines, "namespace", nsList) + cs.Pipeline.Resources = cb.APIResourceList(version, "pipeline") + dc, err := testDynamic.Client( + cb.UnstructuredP(pdata[0], version), + cb.UnstructuredP(pdata[1], version), + cb.UnstructuredP(pdata[2], version), + ) + if err != nil { + t.Errorf("unable to create dynamic clinet: %v", err) + } + p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube, Dynamic: dc} + pipeline := Command(p) + output, err := test.ExecuteCommand(pipeline, "list", "-n", "namespace") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + golden.Assert(t, output, fmt.Sprintf("%s.golden", t.Name())) +} + +func TestPipelineList_only_pipelines_v1beta1(t *testing.T) { + pipelines := []pipelineDetails{ + {"tomatoes", 1 * time.Minute}, + {"mangoes", 20 * time.Second}, + {"bananas", 512 * time.Hour}, // 3 weeks + } + + nsList := []*corev1.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "namespace", + }, + }, + } + version := "v1beta1" clock := clockwork.NewFakeClock() - cs, _ := seedPipelines(t, clock, pipelines, "namespace", nsList) - p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube} + cs, pdata := seedPipelines(t, clock, pipelines, "namespace", nsList) + cs.Pipeline.Resources = cb.APIResourceList(version, "pipeline") + dc, err := testDynamic.Client( + cb.UnstructuredP(pdata[0], version), + cb.UnstructuredP(pdata[1], version), + cb.UnstructuredP(pdata[2], version), + ) + if err != nil { + t.Errorf("unable to create dynamic clinet: %v", err) + } + p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube, Dynamic: dc} pipeline := Command(p) output, err := test.ExecuteCommand(pipeline, "list", "-n", "namespace") @@ -106,14 +158,16 @@ func TestPipelineList_only_pipelines(t *testing.T) { func TestPipelinesList_with_single_run(t *testing.T) { clock := clockwork.NewFakeClock() + version := "v1alpha1" + pdata := []*v1alpha1.Pipeline{ + tb.Pipeline("pipeline", "ns", + // created 5 minutes back + cb.PipelineCreationTimestamp(clock.Now().Add(-5*time.Minute)), + ), + } cs, _ := test.SeedTestData(t, pipelinetest.Data{ - Pipelines: []*v1alpha1.Pipeline{ - tb.Pipeline("pipeline", "ns", - // created 5 minutes back - cb.PipelineCreationTimestamp(clock.Now().Add(-5*time.Minute)), - ), - }, + Pipelines: pdata, PipelineRuns: []*v1alpha1.PipelineRun{ tb.PipelineRun("pipeline-run-1", "ns", @@ -140,8 +194,15 @@ func TestPipelinesList_with_single_run(t *testing.T) { }, }, }) + cs.Pipeline.Resources = cb.APIResourceList(version, "pipeline") - p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube} + dc, err := testDynamic.Client( + cb.UnstructuredP(pdata[0], version), + ) + if err != nil { + t.Errorf("unable to create dynamic clinet: %v", err) + } + p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube, Dynamic: dc} pipeline := Command(p) // -5 : pipeline created @@ -158,6 +219,7 @@ func TestPipelinesList_with_single_run(t *testing.T) { } func TestPipelinesList_latest_run(t *testing.T) { + version := "v1alpha1" clock := clockwork.NewFakeClock() // Time ---> // |---5m ---|------------ ││--││------------- ---│--│ @@ -180,14 +242,14 @@ func TestPipelinesList_latest_run(t *testing.T) { secondRunStarted = secondRunCreated.Add(2 * time.Second) secondRunCompleted = secondRunStarted.Add(runDuration) // takes less thus completes ) - + pdata := []*v1alpha1.Pipeline{ + tb.Pipeline("pipeline", "ns", + // created 5 minutes back + cb.PipelineCreationTimestamp(pipelineCreated), + ), + } cs, _ := test.SeedTestData(t, pipelinetest.Data{ - Pipelines: []*v1alpha1.Pipeline{ - tb.Pipeline("pipeline", "ns", - // created 5 minutes back - cb.PipelineCreationTimestamp(pipelineCreated), - ), - }, + Pipelines: pdata, PipelineRuns: []*v1alpha1.PipelineRun{ tb.PipelineRun("pipeline-run-1", "ns", @@ -225,8 +287,14 @@ func TestPipelinesList_latest_run(t *testing.T) { }, }, }) - - p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube} + cs.Pipeline.Resources = cb.APIResourceList(version, "pipeline") + dc, err := testDynamic.Client( + cb.UnstructuredP(pdata[0], version), + ) + if err != nil { + t.Errorf("unable to create dynamic clinet: %v", err) + } + p := &test.Params{Tekton: cs.Pipeline, Clock: clock, Kube: cs.Kube, Dynamic: dc} pipeline := Command(p) clock.Advance(30 * time.Minute) @@ -243,7 +311,7 @@ type pipelineDetails struct { age time.Duration } -func seedPipelines(t *testing.T, clock clockwork.Clock, ps []pipelineDetails, ns string, nsList []*corev1.Namespace) (pipelinetest.Clients, pipelinetest.Informers) { +func seedPipelines(t *testing.T, clock clockwork.Clock, ps []pipelineDetails, ns string, nsList []*corev1.Namespace) (pipelinetest.Clients, []*v1alpha1.Pipeline) { pipelines := []*v1alpha1.Pipeline{} for _, p := range ps { pipelines = append(pipelines, @@ -252,6 +320,7 @@ func seedPipelines(t *testing.T, clock clockwork.Clock, ps []pipelineDetails, ns ), ) } + cs, _ := test.SeedTestData(t, pipelinetest.Data{Pipelines: pipelines, Namespaces: nsList}) - return test.SeedTestData(t, pipelinetest.Data{Pipelines: pipelines, Namespaces: nsList}) + return cs, pipelines } diff --git a/pkg/cmd/pipeline/testdata/TestPipelineList_only_pipelines_v1beta1.golden b/pkg/cmd/pipeline/testdata/TestPipelineList_only_pipelines_v1beta1.golden new file mode 100644 index 000000000..55150acfc --- /dev/null +++ b/pkg/cmd/pipeline/testdata/TestPipelineList_only_pipelines_v1beta1.golden @@ -0,0 +1,4 @@ +NAME AGE LAST RUN STARTED DURATION STATUS +tomatoes 1 minute ago --- --- --- --- +mangoes 20 seconds ago --- --- --- --- +bananas 3 weeks ago --- --- --- --- diff --git a/pkg/cmd/taskrun/list.go b/pkg/cmd/taskrun/list.go index d2f33e8b7..a9511d912 100644 --- a/pkg/cmd/taskrun/list.go +++ b/pkg/cmd/taskrun/list.go @@ -185,7 +185,12 @@ func list(p cli.Params, task string, limit int, labelselector string, allnamespa ns = "" } - trs, err := trlist.TaskRuns(p, options, ns) + cs, err := p.Clients() + if err != nil { + return nil, err + } + + trs, err := trlist.TaskRuns(cs, options, ns) if err != nil { return nil, err } diff --git a/pkg/pipeline/pipeline.go b/pkg/pipeline/pipeline.go index e44cbd737..f34dc707d 100644 --- a/pkg/pipeline/pipeline.go +++ b/pkg/pipeline/pipeline.go @@ -15,8 +15,15 @@ package pipeline import ( + "fmt" + "os" + "github.com/tektoncd/cli/pkg/cli" + plist "github.com/tektoncd/cli/pkg/list" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" ) func GetAllPipelineNames(p cli.Params) ([]string, error) { @@ -37,3 +44,23 @@ func GetAllPipelineNames(p cli.Params) ([]string, error) { } return ret, nil } + +func List(c *cli.Clients, opts metav1.ListOptions, ns string) (*v1beta1.PipelineList, error) { + + pipelineGroupResource := schema.GroupVersionResource{Group: "tekton.dev", Resource: "pipelines"} + unstructuredP, err := plist.AllObjecs(pipelineGroupResource, c, ns, opts) + if err != nil { + return nil, err + } + + var pipelines *v1beta1.PipelineList + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredP.UnstructuredContent(), &pipelines); err != nil { + return nil, err + } + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to list pipelines from %s namespace \n", ns) + return nil, err + } + + return pipelines, nil +} diff --git a/pkg/taskrun/list/list.go b/pkg/taskrun/list/list.go index bbe510950..24587541c 100644 --- a/pkg/taskrun/list/list.go +++ b/pkg/taskrun/list/list.go @@ -29,7 +29,12 @@ import ( ) func GetAllTaskRuns(p cli.Params, opts metav1.ListOptions, limit int) ([]string, error) { - runs, err := TaskRuns(p, opts, p.Namespace()) + cs, err := p.Clients() + if err != nil { + return nil, err + } + + runs, err := TaskRuns(cs, opts, p.Namespace()) if err != nil { return nil, err } @@ -49,14 +54,10 @@ func GetAllTaskRuns(p cli.Params, opts metav1.ListOptions, limit int) ([]string, return ret, nil } -func TaskRuns(p cli.Params, opts metav1.ListOptions, ns string) (*v1beta1.TaskRunList, error) { - cs, err := p.Clients() - if err != nil { - return nil, err - } +func TaskRuns(c *cli.Clients, opts metav1.ListOptions, ns string) (*v1beta1.TaskRunList, error) { trGroupResource := schema.GroupVersionResource{Group: "tekton.dev", Resource: "taskruns"} - unstructuredTR, err := trlist.AllObjecs(trGroupResource, cs, ns, opts) + unstructuredTR, err := trlist.AllObjecs(trGroupResource, c, ns, opts) if err != nil { return nil, err } @@ -66,7 +67,7 @@ func TaskRuns(p cli.Params, opts metav1.ListOptions, ns string) (*v1beta1.TaskRu return nil, err } if err != nil { - fmt.Fprintf(os.Stderr, "Failed to list taskruns from %s namespace \n", p.Namespace()) + fmt.Fprintf(os.Stderr, "Failed to list taskruns from %s namespace \n", ns) return nil, err } diff --git a/pkg/test/builder/unstructured.go b/pkg/test/builder/unstructured.go index b10c99674..d7117c05b 100644 --- a/pkg/test/builder/unstructured.go +++ b/pkg/test/builder/unstructured.go @@ -20,6 +20,15 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +func UnstructuredP(pipeline *v1alpha1.Pipeline, version string) *unstructured.Unstructured { + pipeline.APIVersion = "tekton.dev/" + version + pipeline.Kind = "pipeline" + object, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(pipeline) + return &unstructured.Unstructured{ + Object: object, + } +} + func UnstructuredTR(taskrun *v1alpha1.TaskRun, version string) *unstructured.Unstructured { taskrun.APIVersion = "tekton.dev/" + version taskrun.Kind = "taskrun"