From ea2d256e87103307aef76ace3bb072658cc4b0f2 Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Tue, 20 Jun 2023 15:21:54 +0530 Subject: [PATCH] Add support for JSON Signed-off-by: Parthvi Vala --- pkg/api/version.go | 47 ++++++++++++++++++++ pkg/odo/cli/version/version.go | 61 +++++++++++++++++++++----- tests/helper/helper_generic.go | 7 +++ tests/integration/generic_test.go | 71 ++++++++++++++++++++++--------- 4 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 pkg/api/version.go diff --git a/pkg/api/version.go b/pkg/api/version.go new file mode 100644 index 00000000000..672202fd1d3 --- /dev/null +++ b/pkg/api/version.go @@ -0,0 +1,47 @@ +package api + +/* +{ + "version": "v3.11.0", + "gitCommit": "0acf1a5af", + "cluster": { + "serverURL": "https://kubernetes.docker.internal:6443", + "kubernetes": { + "version": "v1.25.9" + }, + "openshift": { + "version": "4.13.0" + } + }, + "podman": { + "client": { + "version": "4.5.1" + } + } +} +*/ + +type OdoVersion struct { + Version string `json:"version"` + GitCommit string `json:"gitCommit"` + Cluster *ClusterInfo `json:"cluster,omitempty"` + Podman *PodmanInfo `json:"podman,omitempty"` +} + +type ClusterInfo struct { + ServerURL string `json:"serverURL,omitempty"` + Kubernetes ClusterClientInfo `json:"kubernetes,omitempty"` + OpenShift ClusterClientInfo `json:"openshift,omitempty"` +} + +type ClusterClientInfo struct { + Version string `json:"version,omitempty"` +} + +type PodmanInfo struct { + Client PodmanClientInfo `json:"client,omitempty"` +} + +type PodmanClientInfo struct { + Version string `json:"version,omitempty"` +} diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index 115e9699cec..e331bea3c87 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -3,6 +3,8 @@ package version import ( "context" "fmt" + "github.com/redhat-developer/odo/pkg/api" + "github.com/redhat-developer/odo/pkg/odo/commonflags" "github.com/redhat-developer/odo/pkg/podman" "os" "strings" @@ -45,6 +47,7 @@ type VersionOptions struct { } var _ genericclioptions.Runnable = (*VersionOptions)(nil) +var _ genericclioptions.JsonOutputter = (*VersionOptions)(nil) // NewVersionOptions creates a new VersionOptions instance func NewVersionOptions() *VersionOptions { @@ -69,7 +72,7 @@ func (o *VersionOptions) Complete(ctx context.Context, cmdline cmdline.Cmdline, if o.clientset.PodmanClient != nil { o.podmanInfo, err = o.clientset.PodmanClient.Version(ctx) if err != nil { - klog.V(4).Info("unable to fetch the podman version: ", err) + klog.V(4).Info("unable to fetch the podman client version: ", err) } } @@ -82,35 +85,70 @@ func (o *VersionOptions) Validate(ctx context.Context) (err error) { return nil } +func (o *VersionOptions) RunForJsonOutput(ctx context.Context) (out interface{}, err error) { + return o.run(), nil +} + +func (o *VersionOptions) run() api.OdoVersion { + result := api.OdoVersion{ + Version: odoversion.VERSION, + GitCommit: odoversion.GITCOMMIT, + } + + if o.clientFlag { + return result + } + + if o.serverInfo != nil { + clusterInfo := &api.ClusterInfo{ + ServerURL: o.serverInfo.Address, + Kubernetes: api.ClusterClientInfo{Version: o.serverInfo.KubernetesVersion}, + OpenShift: api.ClusterClientInfo{Version: o.serverInfo.OpenShiftVersion}, + } + result.Cluster = clusterInfo + } + + if o.podmanInfo.Client != nil { + podmanInfo := &api.PodmanInfo{Client: api.PodmanClientInfo{Version: o.podmanInfo.Client.Version}} + result.Podman = podmanInfo + } + + return result +} + // Run contains the logic for the odo service create command func (o *VersionOptions) Run(ctx context.Context) (err error) { - // If verbose mode is enabled, dump all KUBECLT_* env variables - // this is usefull for debuging oc plugin integration + // If verbose mode is enabled, dump all KUBECTL_* env variables + // this is useful for debugging oc plugin integration for _, v := range os.Environ() { if strings.HasPrefix(v, "KUBECTL_") { klog.V(4).Info(v) } } - fmt.Println("odo " + odoversion.VERSION + " (" + odoversion.GITCOMMIT + ")") + odoVersion := o.run() + fmt.Println("odo " + odoVersion.Version + " (" + odoVersion.GitCommit + ")") if o.clientFlag { return nil } message := "\n" - if o.serverInfo != nil { - message = fmt.Sprintf("Server: %v\n", o.serverInfo.Address) + if odoVersion.Cluster != nil { + cluster := odoVersion.Cluster + message = fmt.Sprintf("Server: %v\n", cluster.ServerURL) // make sure we only include OpenShift info if we actually have it - if len(o.serverInfo.OpenShiftVersion) > 0 { - message += fmt.Sprintf("OpenShift: %v\n", o.serverInfo.OpenShiftVersion) + if cluster.OpenShift.Version != "" { + message += fmt.Sprintf("OpenShift: %v\n", cluster.OpenShift.Version) } - message += fmt.Sprintf("Kubernetes: %v\n", o.serverInfo.KubernetesVersion) + + message += fmt.Sprintf("Kubernetes: %v\n", cluster.Kubernetes.Version) + } - if o.podmanInfo.Client != nil { - message += fmt.Sprintf("Podman (Client): %v\n", o.podmanInfo.Client.Version) + if odoVersion.Podman != nil { + message += fmt.Sprintf("Podman Client: %v\n", odoVersion.Podman.Client.Version) } fmt.Print(message) @@ -131,6 +169,7 @@ func NewCmdVersion(name, fullName string, testClientset clientset.Clientset) *co return genericclioptions.GenericRun(o, testClientset, cmd, args) }, } + commonflags.UseOutputFlag(versionCmd) clientset.Add(versionCmd, clientset.PREFERENCE, clientset.KUBERNETES_NULLABLE, clientset.PODMAN_NULLABLE) util.SetCommandGroup(versionCmd, util.UtilityGroup) diff --git a/tests/helper/helper_generic.go b/tests/helper/helper_generic.go index 9e74f10c7be..f0c0880a79a 100644 --- a/tests/helper/helper_generic.go +++ b/tests/helper/helper_generic.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/onsi/gomega/types" "os" "path/filepath" "regexp" @@ -324,6 +325,12 @@ func JsonPathContentContain(json string, path string, value string) { Expect(result.String()).To(ContainSubstring(value), fmt.Sprintf("content of path %q should contain %q but is %q", path, value, result.String())) } +// JsonPathSatisfies expects content of the path to satisfy all the matchers passed to it +func JsonPathSatisfies(json string, path string, matchers ...types.GomegaMatcher) { + result := gjson.Get(json, path) + Expect(result.String()).Should(SatisfyAll(matchers...)) +} + // JsonPathDoesNotExist expects that the content of the path does not exist in the JSON string func JsonPathDoesNotExist(json string, path string) { result := gjson.Get(json, path) diff --git a/tests/integration/generic_test.go b/tests/integration/generic_test.go index 1df847f74e0..6fb133cdb1d 100644 --- a/tests/integration/generic_test.go +++ b/tests/integration/generic_test.go @@ -114,8 +114,9 @@ var _ = Describe("odo generic", func() { Context("executing odo version command", func() { const ( reOdoVersion = `^odo\s*v[0-9]+.[0-9]+.[0-9]+(?:-\w+)?\s*\(\w+\)` - rekubernetesVersion = `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` - rePodmanVersion = `Podman \(Client\):\s*[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + reKubernetesVersion = `Kubernetes:\s*v[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + rePodmanVersion = `Podman Client:\s*[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` + reJSONVersion = `^v{0,1}[0-9]+.[0-9]+.[0-9]+((-\w+\.[0-9]+)?\+\w+)?` ) When("executing the complete command with server info", func() { var odoVersion string @@ -125,20 +126,37 @@ var _ = Describe("odo generic", func() { for _, podman := range []bool{true, false} { podman := podman It("should show the version of odo major components including server login URL", helper.LabelPodmanIf(podman, func() { - Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) - - // odo tests setup (CommonBeforeEach) is designed in a way that if a test is labelled with 'podman', it will not have cluster configuration - // so we only test podman info on podman labelled test, and clsuter info otherwise - // TODO (pvala): Change this behavior when we write tests that should be tested on both podman and cluster simultaneously - // Ref: https://github.com/redhat-developer/odo/issues/6719 - if podman { - Expect(odoVersion).Should(MatchRegexp(rePodmanVersion)) - Expect(odoVersion).To(ContainSubstring(helper.GetPodmanVersion())) - } else { - Expect(odoVersion).Should(MatchRegexp(rekubernetesVersion)) - serverURL := oc.GetCurrentServerURL() - Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) - } + By("checking the human readable output", func() { + Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + + // odo tests setup (CommonBeforeEach) is designed in a way that if a test is labelled with 'podman', it will not have cluster configuration + // so we only test podman info on podman labelled test, and clsuter info otherwise + // TODO (pvala): Change this behavior when we write tests that should be tested on both podman and cluster simultaneously + // Ref: https://github.com/redhat-developer/odo/issues/6719 + if podman { + Expect(odoVersion).Should(MatchRegexp(rePodmanVersion)) + Expect(odoVersion).To(ContainSubstring(helper.GetPodmanVersion())) + } else { + Expect(odoVersion).Should(MatchRegexp(reKubernetesVersion)) + serverURL := oc.GetCurrentServerURL() + Expect(odoVersion).Should(ContainSubstring("Server: " + serverURL)) + } + }) + + By("checking the JSON output", func() { + odoVersion = helper.Cmd("odo", "version", "-o", "json").ShouldPass().Out() + Expect(helper.IsJSON(odoVersion)).To(BeTrue()) + helper.JsonPathSatisfies(odoVersion, "version", MatchRegexp(reJSONVersion)) + helper.JsonPathExist(odoVersion, "gitCommit") + if podman { + helper.JsonPathSatisfies(odoVersion, "podman.client.version", MatchRegexp(reJSONVersion), Equal(helper.GetPodmanVersion())) + } else { + helper.JsonPathSatisfies(odoVersion, "cluster.kubernetes.version", MatchRegexp(reJSONVersion)) + serverURL := oc.GetCurrentServerURL() + helper.JsonPathContentIs(odoVersion, "cluster.serverURL", serverURL) + helper.JsonPathExist(odoVersion, "cluster.openshift") + } + }) })) } @@ -158,13 +176,24 @@ var _ = Describe("odo generic", func() { }) It("should not print podman version if podman cmd timeout has been reached", func() { Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) - Expect(odoVersion).ToNot(ContainSubstring("Podman (Client):")) + Expect(odoVersion).ToNot(ContainSubstring("Podman Client:")) }) }) - It("should only print client info when asked for it", func() { - odoVersion := helper.Cmd("odo", "version", "--client").ShouldPass().Out() - Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) - Expect(odoVersion).ToNot(SatisfyAll(ContainSubstring("Server"), ContainSubstring("Kubernetes"), ContainSubstring("Podman (Client)"))) + It("should only print client info when using --client flag", func() { + By("checking human readable output", func() { + odoVersion := helper.Cmd("odo", "version", "--client").ShouldPass().Out() + Expect(odoVersion).Should(MatchRegexp(reOdoVersion)) + Expect(odoVersion).ToNot(SatisfyAll(ContainSubstring("Server"), ContainSubstring("Kubernetes"), ContainSubstring("Podman Client"))) + }) + + By("checking JSON output", func() { + odoVersion := helper.Cmd("odo", "version", "--client", "-o", "json").ShouldPass().Out() + Expect(helper.IsJSON(odoVersion)).To(BeTrue()) + helper.JsonPathSatisfies(odoVersion, "version", MatchRegexp(reJSONVersion)) + helper.JsonPathExist(odoVersion, "gitCommit") + helper.JsonPathSatisfies(odoVersion, "cluster", BeEmpty()) + helper.JsonPathSatisfies(odoVersion, "podman", BeEmpty()) + }) }) })