Repository: knative/client (go)

Issue:
Add machine readable output (-o flag) to kn source apiserver describe
use case: `kn source apiserver describe NAME -oyaml`

see `kn service describe NAME -oyaml` for ref

/kind good-first-issue



Pull request description:
Add machine readable output (-o flag) to kn source apiserver describe
Signed-off-by: Arghya Sadhu <arghya88@gmail.com>


## Description

<!-- Please add a short summary about what the pull request is going to bring on the table -->

## Changes

<!-- Please add list of more detailed changes. These changes should be reflected also in the commit messages -->

*Add machine readable output (-o flag) to kn source apiserver describe

## Reference

<!-- Please add the corresponding issue number which this pull request is about to fix -->
Fixes #1096

<!--
Please add an entry to CHANGELOG.adoc file, too, as part of your Pull Request.

In the following cases, add a short description of PR to the unreleased section in CHANGELOG.adoc:

- 🎁 New feature
- 🐛 Bug fix
- ✨ Feature Update
- 🐣 Refactoring
- 🗑️ Remove feature or internal logic

See other entries in CHANGELOG.adoc as an example for how to add the entry, including a reference to the corresponding issue/PR

PLEASE DON'T ADD THAT LINE HERE IN THE PULL-REQUEST DESCRIPTION BUT DIRECTLY IN CHANGELOG.ADOC AND ADD CHANGELOG.ADOC AS PART OF YOUR PULL-REQUEST.
-->

<!--
To automatically lint go code in this pull request uncomment the line below. You get feedback as comments on your pull request then -->

<!--
/lint
-->


Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 67d28284..aca91015 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -17,6 +17,10 @@
 |===
 | | Description | PR
 
+| 🐛
+| Add machine readable output (-o flag) to kn source apiserver describe
+| https://github.com/knative/client/pull/1146[#1146]
+
 | 🐛
 | Fix a race condition when using Kubernetes watches
 | https://github.com/knative/client/pull/1113[#1113]
diff --git a/docs/cmd/kn_source_apiserver_describe.md b/docs/cmd/kn_source_apiserver_describe.md
index d681c6e4..97d64421 100644
--- a/docs/cmd/kn_source_apiserver_describe.md
+++ b/docs/cmd/kn_source_apiserver_describe.md
@@ -14,16 +14,22 @@ kn source apiserver describe NAME
 
 ```
 
-  # Describe an ApiServer source with name 'k8sevents'
+  # Describe an api-server source with name 'k8sevents'
   kn source apiserver describe k8sevents
+
+  # Describe an api-server source with name 'k8sevents' in YAML format
+  kn source apiserver describe k8sevents -o yaml
 ```
 
 ### Options
 
 ```
-  -h, --help               help for describe
-  -n, --namespace string   Specify the namespace to operate in.
-  -v, --verbose            More output.
+      --allow-missing-template-keys   If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
+  -h, --help                          help for describe
+  -n, --namespace string              Specify the namespace to operate in.
+  -o, --output string                 Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
+      --template string               Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
+  -v, --verbose                       More output.
 ```
 
 ### Options inherited from parent commands
diff --git a/pkg/kn/commands/source/apiserver/describe.go b/pkg/kn/commands/source/apiserver/describe.go
index e5ce8afb..52dfab18 100644
--- a/pkg/kn/commands/source/apiserver/describe.go
+++ b/pkg/kn/commands/source/apiserver/describe.go
@@ -18,8 +18,10 @@ import (
 	"errors"
 	"fmt"
 	"sort"
+	"strings"
 
 	"github.com/spf13/cobra"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
 	v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2"
 
 	"knative.dev/client/lib/printing"
@@ -27,14 +29,23 @@ import (
 	"knative.dev/client/pkg/printers"
 )
 
+var describeExample = `
+  # Describe an api-server source with name 'k8sevents'
+  kn source apiserver describe k8sevents
+
+  # Describe an api-server source with name 'k8sevents' in YAML format
+  kn source apiserver describe k8sevents -o yaml`
+
 // NewAPIServerDescribeCommand to describe an ApiServer source object
 func NewAPIServerDescribeCommand(p *commands.KnParams) *cobra.Command {
-	apiServerDescribe := &cobra.Command{
-		Use:   "describe NAME",
-		Short: "Show details of an api-server source",
-		Example: `
-  # Describe an ApiServer source with name 'k8sevents'
-  kn source apiserver describe k8sevents`,
+
+	// For machine readable output
+	machineReadablePrintFlags := genericclioptions.NewPrintFlags("")
+
+	command := &cobra.Command{
+		Use:     "describe NAME",
+		Short:   "Show details of an api-server source",
+		Example: describeExample,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if len(args) != 1 {
 				return errors.New("'kn source apiserver describe' requires name of the source as single argument")
@@ -52,6 +63,15 @@ func NewAPIServerDescribeCommand(p *commands.KnParams) *cobra.Command {
 			}
 
 			out := cmd.OutOrStdout()
+
+			// Print out machine readable output if requested
+			if machineReadablePrintFlags.OutputFlagSpecified() {
+				printer, err := machineReadablePrintFlags.ToPrinter()
+				if err != nil {
+					return err
+				}
+				return printer.PrintObj(apiSource, out)
+			}
 			dw := printers.NewPrefixWriter(out)
 
 			printDetails, err := cmd.Flags().GetBool("verbose")
@@ -90,11 +110,12 @@ func NewAPIServerDescribeCommand(p *commands.KnParams) *cobra.Command {
 			return nil
 		},
 	}
-	flags := apiServerDescribe.Flags()
+	flags := command.Flags()
 	commands.AddNamespaceFlags(flags, false)
 	flags.BoolP("verbose", "v", false, "More output.")
-
-	return apiServerDescribe
+	machineReadablePrintFlags.AddFlags(command)
+	command.Flag("output").Usage = fmt.Sprintf("Output format. One of: %s.", strings.Join(machineReadablePrintFlags.AllowedFormats(), "|"))
+	return command
 }
 
 func writeResources(dw printers.PrefixWriter, apiVersionKindSelectors []v1alpha2.APIVersionKindSelector) {
diff --git a/pkg/sources/v1alpha2/apiserver_client.go b/pkg/sources/v1alpha2/apiserver_client.go
index 775fd32f..9d90335c 100644
--- a/pkg/sources/v1alpha2/apiserver_client.go
+++ b/pkg/sources/v1alpha2/apiserver_client.go
@@ -74,7 +74,10 @@ func (c *apiServerSourcesClient) GetAPIServerSource(name string) (*v1alpha2.ApiS
 	if err != nil {
 		return nil, knerrors.GetError(err)
 	}
-
+	err = updateSourceGVK(apiSource)
+	if err != nil {
+		return nil, err
+	}
 	return apiSource, nil
 }
 


Test patch:
diff --git a/pkg/kn/commands/source/apiserver/describe_test.go b/pkg/kn/commands/source/apiserver/describe_test.go
index bf61cae7..f6a01c83 100644
--- a/pkg/kn/commands/source/apiserver/describe_test.go
+++ b/pkg/kn/commands/source/apiserver/describe_test.go
@@ -50,6 +50,23 @@ func TestSimpleDescribe(t *testing.T) {
 	apiServerRecorder.Validate()
 }
 
+func TestDescribeMachineReadable(t *testing.T) {
+	apiServerClient := v1alpha2.NewMockKnAPIServerSourceClient(t, "mynamespace")
+
+	apiServerRecorder := apiServerClient.Recorder()
+	sampleSource := createAPIServerSource("testsource", "Event", "v1", "testsa", "Reference", map[string]string{"foo": "bar"}, createSinkv1("testsvc", "default"))
+	sampleSource.APIVersion = "sources.knative.dev/v1"
+	sampleSource.Kind = "ApiServerSource"
+	sampleSource.Namespace = "mynamespace"
+	apiServerRecorder.GetAPIServerSource("testsource", sampleSource, nil)
+
+	out, err := executeAPIServerSourceCommand(apiServerClient, nil, "describe", "testsource", "-o", "yaml")
+	assert.NilError(t, err)
+	assert.Assert(t, util.ContainsAll(out, "kind: ApiServerSource", "spec:", "status:", "metadata:"))
+
+	apiServerRecorder.Validate()
+}
+
 func TestDescribeError(t *testing.T) {
 	apiServerClient := v1alpha2.NewMockKnAPIServerSourceClient(t, "mynamespace")