Skip to content

Commit

Permalink
Fix error when output is set to name (knative#775)
Browse files Browse the repository at this point in the history
* fix error when output is set to name

* add e2e test

* change to flags/listprint.go

Signed-off-by: Roland Huß <[email protected]>
# Conflicts:
#	test/e2e/basic_workflow_test.go
  • Loading branch information
Ying Chun Guo authored and rhuss committed Apr 15, 2020
1 parent edb5151 commit 5feaed3
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 10 deletions.
22 changes: 22 additions & 0 deletions pkg/kn/commands/flags/listprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@
package flags

import (
"io"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"

"knative.dev/client/pkg/kn/commands"
hprinters "knative.dev/client/pkg/printers"
"knative.dev/client/pkg/util"
)

// ListFlags composes common printer flag structs
Expand Down Expand Up @@ -56,6 +60,24 @@ func (f *ListPrintFlags) ToPrinter() (hprinters.ResourcePrinter, error) {
return p, nil
}

// Print is to print an Object to a Writer
func (f *ListPrintFlags) Print(obj runtime.Object, w io.Writer) error {
printer, err := f.ToPrinter()
if err != nil {
return err
}

if f.GenericPrintFlags.OutputFlagSpecified() {
unstructuredList, err := util.ToUnstructuredList(obj)
if err != nil {
return err
}
return printer.PrintObj(unstructuredList, w)
}

return printer.PrintObj(obj, w)
}

// AddFlags receives a *cobra.Command reference and binds
// flags related to humanreadable and template printing.
func (f *ListPrintFlags) AddFlags(cmd *cobra.Command) {
Expand Down
15 changes: 15 additions & 0 deletions pkg/kn/commands/flags/listprint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,18 @@ func TestListPrintFlags(t *testing.T) {
_, ok := p.(hprinters.ResourcePrinter)
assert.Check(t, ok == true)
}

func TestListPrintFlagsPrint(t *testing.T) {
var cmd *cobra.Command
flags := NewListPrintFlags(func(h hprinters.PrintHandler) {})

cmd = &cobra.Command{}
flags.AddFlags(cmd)

pr, err := flags.ToPrinter()
assert.NilError(t, err)
assert.Assert(t, pr != nil)

err = flags.Print(nil, cmd.OutOrStdout())
assert.NilError(t, err)
}
11 changes: 1 addition & 10 deletions pkg/kn/commands/service/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ func NewServiceListCommand(p *commands.KnParams) *cobra.Command {
serviceListFlags.EnsureWithNamespace()
}

printer, err := serviceListFlags.ToPrinter()
if err != nil {
return err
}

// Sort serviceList by namespace and name (in this order)
sort.SliceStable(serviceList.Items, func(i, j int) bool {
a := serviceList.Items[i]
Expand All @@ -81,11 +76,7 @@ func NewServiceListCommand(p *commands.KnParams) *cobra.Command {
return a.ObjectMeta.Name < b.ObjectMeta.Name
})

err = printer.PrintObj(serviceList, cmd.OutOrStdout())
if err != nil {
return err
}
return nil
return serviceListFlags.Print(serviceList, cmd.OutOrStdout())
},
}
commands.AddNamespaceFlags(serviceListCommand.Flags(), true)
Expand Down
4 changes: 4 additions & 0 deletions pkg/printers/tableprinter.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ func NewTablePrinter(options PrintOptions) *HumanReadablePrinter {

// PrintObj prints the obj in a human-friendly format according to the type of the obj.
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
if obj == nil {
return nil
}

w, found := output.(*tabwriter.Writer)
if !found {
w = NewTabWriter(output)
Expand Down
64 changes: 64 additions & 0 deletions pkg/util/unstructured.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright © 2020 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package util

import (
"encoding/json"

"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)

// ToUnstructuredList is to converts an object to unstructured.UnstructuredList.
// If the object is not a list type, it will convert to a single item UnstructuredList.
func ToUnstructuredList(obj runtime.Object) (*unstructured.UnstructuredList, error) {
unstructuredList := &unstructured.UnstructuredList{}
if meta.IsListType(obj) {
unstructuredList.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind())
items, err := meta.ExtractList(obj)
if err != nil {
return nil, err
}
for _, obji := range items {
ud, err := toUnstructured(obji)
if err != nil {
return nil, err
}
unstructuredList.Items = append(unstructuredList.Items, *ud)
}

} else {
ud, err := toUnstructured(obj)
if err != nil {
return nil, err
}
unstructuredList.Items = append(unstructuredList.Items, *ud)
}
return unstructuredList, nil

}

func toUnstructured(obj runtime.Object) (*unstructured.Unstructured, error) {
b, err := json.Marshal(obj)
if err != nil {
return nil, err
}
ud := &unstructured.Unstructured{}
if err := json.Unmarshal(b, ud); err != nil {
return nil, err
}
return ud, nil
}
86 changes: 86 additions & 0 deletions pkg/util/unstructured_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package util

import (
"testing"

"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
)

func TestToUnstructuredList(t *testing.T) {
serviceList := servingv1.ServiceList{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "List",
},
Items: []servingv1.Service{createService("s1"), createService("s2")},
}
expectedList := &unstructured.UnstructuredList{
Object: map[string]interface{}{
"apiVersion": string("v1"),
"kind": string("List"),
},
}
expectedList.Items = []unstructured.Unstructured{createUnstructured("s1"), createUnstructured("s2")}
unstructedList, err := ToUnstructuredList(&serviceList)
assert.NilError(t, err)
assert.DeepEqual(t, unstructedList, expectedList)

service1 := createService("s3")
expectedList = &unstructured.UnstructuredList{}
expectedList.Items = []unstructured.Unstructured{createUnstructured("s3")}
unstructedList, err = ToUnstructuredList(&service1)
assert.NilError(t, err)
assert.DeepEqual(t, unstructedList, expectedList)
}

func createService(name string) servingv1.Service {
service := servingv1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
APIVersion: "serving.knative.dev/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: "default",
},
}
return service
}

func createUnstructured(name string) unstructured.Unstructured {
return unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "serving.knative.dev/v1",
"kind": "Service",
"metadata": map[string]interface{}{
"namespace": "default",
"name": name,
"creationTimestamp": nil,
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"metadata": map[string]interface{}{"creationTimestamp": nil},
"spec": map[string]interface{}{"containers": nil},
},
},
"status": map[string]interface{}{},
},
}
}
9 changes: 9 additions & 0 deletions test/e2e/basic_workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func TestBasicWorkflow(t *testing.T) {
serviceList(t, it, r, "hello")
serviceDescribe(t, it, r, "hello")

t.Log("return list --output name about hello service")
serviceListOutput(t, it, r, "hello")

t.Log("update hello service's configuration and return no error")
serviceUpdate(t, it, r, "hello", "--env", "TARGET=kn", "--port", "8888")

Expand Down Expand Up @@ -111,6 +114,12 @@ func serviceDescribe(t *testing.T, it *test.KnTest, r *test.KnRunResultCollector
assert.Assert(t, util.ContainsAll(out.Stdout, "Name", "Namespace", "URL", "Age", "Revisions"))
}

func serviceListOutput(t *testing.T, it *test.KnTest, r *test.KnRunResultCollector, serviceName string) {
out := it.Kn().Run("service", "list", serviceName, "--output", "name")
r.AssertNoError(out)
assert.Check(t, util.ContainsAll(out.Stdout, serviceName, "service.serving.knative.dev"))
}

func serviceUpdate(t *testing.T, it *test.KnTest, r *test.KnRunResultCollector, serviceName string, args ...string) {
fullArgs := append([]string{}, "service", "update", serviceName)
fullArgs = append(fullArgs, args...)
Expand Down

0 comments on commit 5feaed3

Please sign in to comment.