diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index c787f9410a..74c2f0b38b 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -18,6 +18,10 @@ |=== | | Description | PR +| 🎁 +| Add JSON/YAML output format for version command +| https://github.com/knative/client/pull/709[#709] + | 🐣 | Replaced `kn source cron` with `kn source ping`. `--schedule` is not mandatory anymore and defaults to "* * * * *" (every minute) | https://github.com/knative/client/issues/564[#564] diff --git a/docs/cmd/kn_version.md b/docs/cmd/kn_version.md index 089e4a09ef..fcf26b8400 100644 --- a/docs/cmd/kn_version.md +++ b/docs/cmd/kn_version.md @@ -13,7 +13,8 @@ kn version [flags] ### Options ``` - -h, --help help for version + -h, --help help for version + -o, --output string Output format. One of: json|yaml. ``` ### Options inherited from parent commands diff --git a/pkg/kn/commands/version/version.go b/pkg/kn/commands/version/version.go index 769941a2a1..7d243815b2 100644 --- a/pkg/kn/commands/version/version.go +++ b/pkg/kn/commands/version/version.go @@ -15,11 +15,13 @@ package version import ( + "encoding/json" "fmt" - "knative.dev/client/pkg/kn/commands" - "github.com/spf13/cobra" + "sigs.k8s.io/yaml" + + "knative.dev/client/pkg/kn/commands" ) var Version string @@ -38,12 +40,22 @@ var apiVersions = map[string][]string{ }, } +type knVersion struct { + Version string + BuildDate string + GitRevision string + SupportedAPIs map[string][]string +} + // NewVersionCommand implements 'kn version' command func NewVersionCommand(p *commands.KnParams) *cobra.Command { versionCmd := &cobra.Command{ Use: "version", Short: "Prints the client version", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("output") { + return printVersionMachineReadable(cmd) + } out := cmd.OutOrStdout() fmt.Fprintf(out, "Version: %s\n", Version) fmt.Fprintf(out, "Build Date: %s\n", BuildDate) @@ -57,7 +69,37 @@ func NewVersionCommand(p *commands.KnParams) *cobra.Command { for _, api := range apiVersions["eventing"] { fmt.Fprintf(out, " - %s\n", api) } + return nil }, } + versionCmd.Flags().StringP( + "output", + "o", + "", + "Output format. One of: json|yaml.", + ) return versionCmd } + +func printVersionMachineReadable(cmd *cobra.Command) error { + out := cmd.OutOrStdout() + v := knVersion{Version, BuildDate, GitRevision, apiVersions} + format := cmd.Flag("output").Value.String() + switch format { + case "JSON", "json": + b, err := json.MarshalIndent(v, "", "\t") + if err != nil { + return err + } + fmt.Fprint(out, string(b)) + case "YAML", "yaml": + b, err := yaml.Marshal(v) + if err != nil { + return err + } + fmt.Fprint(out, string(b)) + default: + return fmt.Errorf("Invalid value for output flag, choose one among 'json' or 'yaml'.") + } + return nil +} diff --git a/pkg/kn/commands/version/version_test.go b/pkg/kn/commands/version/version_test.go index 8ae035b38b..c514d717f7 100644 --- a/pkg/kn/commands/version/version_test.go +++ b/pkg/kn/commands/version/version_test.go @@ -16,31 +16,25 @@ package version import ( "bytes" + "encoding/json" "testing" "text/template" - "knative.dev/client/pkg/kn/commands" - "github.com/spf13/cobra" "gotest.tools/assert" -) + "sigs.k8s.io/yaml" -type versionOutput struct { - Version string - BuildDate string - GitRevision string -} + "knative.dev/client/pkg/kn/commands" +) var versionOutputTemplate = `Version: {{.Version}} Build Date: {{.BuildDate}} Git Revision: {{.GitRevision}} Supported APIs: -* Serving - - serving.knative.dev/v1 (knative-serving v0.13.0) -* Eventing - - sources.eventing.knative.dev/v1alpha1 (knative-eventing v0.13.1) - - sources.eventing.knative.dev/v1alpha2 (knative-eventing v0.13.1) - - eventing.knative.dev/v1alpha1 (knative-eventing v0.13.1) +* Serving{{range $apis := .SupportedAPIs.serving }} + - {{$apis}}{{end}} +* Eventing{{range $apis := .SupportedAPIs.eventing }} + - {{$apis}}{{end}} ` const ( @@ -51,53 +45,79 @@ const ( func TestVersion(t *testing.T) { var ( - versionCmd *cobra.Command - knParams *commands.KnParams - expectedVersionOutput string - output *bytes.Buffer + versionCmd *cobra.Command + knParams *commands.KnParams + expectedOutput string + knVersionObj knVersion + output *bytes.Buffer ) setup := func() { Version = fakeVersion BuildDate = fakeBuildDate GitRevision = fakeGitRevision - - expectedVersionOutput = genVersionOuput(t, versionOutputTemplate, - versionOutput{ - fakeVersion, - fakeBuildDate, - fakeGitRevision}) - + knVersionObj = knVersion{fakeVersion, fakeBuildDate, fakeGitRevision, apiVersions} + expectedOutput = genVersionOuput(t, knVersionObj) knParams = &commands.KnParams{} versionCmd = NewVersionCommand(knParams) output = new(bytes.Buffer) versionCmd.SetOutput(output) } - t.Run("creates a VersionCommand", func(t *testing.T) { + runVersionCmd := func(args []string) error { setup() + versionCmd.SetArgs(args) + return versionCmd.Execute() + } + t.Run("creates a VersionCommand", func(t *testing.T) { + setup() assert.Equal(t, versionCmd.Use, "version") assert.Equal(t, versionCmd.Short, "Prints the client version") - assert.Assert(t, versionCmd.Run != nil) + assert.Assert(t, versionCmd.RunE != nil) }) t.Run("prints version, build date, git revision, supported APIs", func(t *testing.T) { - setup() + err := runVersionCmd([]string{}) + assert.NilError(t, err) + assert.Equal(t, output.String(), expectedOutput) + }) - versionCmd.Run(versionCmd, []string{}) - assert.Equal(t, output.String(), expectedVersionOutput) + t.Run("print version command with machine readable output", func(t *testing.T) { + t.Run("json", func(t *testing.T) { + err := runVersionCmd([]string{"-oJSON"}) + assert.NilError(t, err) + in := knVersion{} + err = json.Unmarshal(output.Bytes(), &in) + assert.NilError(t, err) + assert.DeepEqual(t, in, knVersionObj) + }) + + t.Run("yaml", func(t *testing.T) { + err := runVersionCmd([]string{"-oyaml"}) + assert.NilError(t, err) + jsonData, err := yaml.YAMLToJSON(output.Bytes()) + assert.NilError(t, err) + in := knVersion{} + err = json.Unmarshal(jsonData, &in) + assert.NilError(t, err) + assert.DeepEqual(t, in, knVersionObj) + }) + + t.Run("invalid format", func(t *testing.T) { + err := runVersionCmd([]string{"-o", "jsonpath"}) + assert.Assert(t, err != nil) + assert.ErrorContains(t, err, "Invalid", "output", "flag", "choose", "among") + }) }) } -func genVersionOuput(t *testing.T, templ string, vOutput versionOutput) string { +func genVersionOuput(t *testing.T, obj knVersion) string { tmpl, err := template.New("versionOutput").Parse(versionOutputTemplate) assert.NilError(t, err) - buf := bytes.Buffer{} - err = tmpl.Execute(&buf, vOutput) + err = tmpl.Execute(&buf, obj) assert.NilError(t, err) - return buf.String() }