diff --git a/cmd/cmd.go b/cmd/cmd.go index c4a26fefa16..a911ea8afce 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -64,7 +64,7 @@ func Run() { c, err := cli.New( cli.WithCommandName("kubebuilder"), - cli.WithVersion(versionString()), + cli.WithVersion(versionStruct()), cli.WithCliVersion(getKubebuilderVersion()), cli.WithPlugins( golangv4.Plugin{}, diff --git a/cmd/version.go b/cmd/version.go index 0f26a98c3b5..f0f7b7ba050 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -28,6 +28,7 @@ import ( "time" "golang.org/x/mod/semver" + "sigs.k8s.io/kubebuilder/v4/pkg/cli" ) const ( @@ -48,28 +49,20 @@ var ( buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ') ) -// version contains all the information related to the CLI version -type version struct { - KubeBuilderVersion string `json:"kubeBuilderVersion"` - KubernetesVendor string `json:"kubernetesVendor"` - GitCommit string `json:"gitCommit"` - BuildDate string `json:"buildDate"` - GoOs string `json:"goOs"` - GoArch string `json:"goArch"` -} - // versionString returns the Full CLI version -func versionString() string { +func versionStruct() *cli.Version { kubeBuilderVersion = getKubebuilderVersion() - return fmt.Sprintf("Version: %#v", version{ - kubeBuilderVersion, - kubernetesVendorVersion, - gitCommit, - buildDate, - goos, - goarch, - }) + version := cli.Version{ + KubeBuilderVersion: kubeBuilderVersion, + KubernetesVendor: kubernetesVendorVersion, + GitCommit: gitCommit, + BuildDate: buildDate, + GoOs: goos, + GoArch: goarch, + } + + return &version } // getKubebuilderVersion returns only the CLI version string diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 28645781524..b59712f1f66 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -48,8 +48,8 @@ type CLI struct { // Root command name. It is injected downstream to provide correct help, usage, examples and errors. commandName string - // Full CLI version string. - version string + // Full CLI version struct. + version *Version // CLI version string (just the CLI version number, no extra information). cliVersion string // CLI root's command description. @@ -526,8 +526,8 @@ func (c *CLI) addSubcommands() { c.cmd.AddCommand(c.newInitCmd()) // kubebuilder version - // Only add version if a version string was provided - if c.version != "" { + // Only add version if a version struct was provided + if c.version != nil { c.cmd.AddCommand(c.newVersionCmd()) } } diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index 486b99c4624..ed4b14b6c01 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -623,11 +623,18 @@ plugins: When("providing a version string", func() { It("should create a valid CLI", func() { - const version = "version string" + version := Version{ + KubeBuilderVersion: "123", + KubernetesVendor: "123", + GitCommit: "0123fasdf0123", + BuildDate: "2025-12-3", + GoOs: "os123", + GoArch: "arch123", + } c, err = New( WithPlugins(&golangv4.Plugin{}), WithDefaultPlugins(projectVersion, &golangv4.Plugin{}), - WithVersion(version), + WithVersion(&version), ) Expect(err).NotTo(HaveOccurred()) Expect(hasSubCommand(c.cmd, "version")).To(BeTrue()) @@ -648,7 +655,11 @@ plugins: Expect(err).NotTo(HaveOccurred()) printed, _ := io.ReadAll(r) Expect(string(printed)).To(Equal( - fmt.Sprintf("%s\n", version))) + fmt.Sprintf("Kubebuilder:\t123\n" + + "Kubernetes:\t123\n" + + "Git Commit:\t0123fasdf0123\n" + + "Build Date:\t2025-12-3\n" + + "OS/Arch:\tos123/arch123\n"))) }) }) diff --git a/pkg/cli/options.go b/pkg/cli/options.go index 2f0c2fc56ef..934dffcb48d 100644 --- a/pkg/cli/options.go +++ b/pkg/cli/options.go @@ -50,7 +50,7 @@ func WithCommandName(name string) Option { } // WithVersion is an Option that defines the version string of the CLI. -func WithVersion(version string) Option { +func WithVersion(version *Version) Option { return func(c *CLI) error { c.version = version return nil diff --git a/pkg/cli/options_test.go b/pkg/cli/options_test.go index 55d7bc3015f..ed61be15eca 100644 --- a/pkg/cli/options_test.go +++ b/pkg/cli/options_test.go @@ -539,12 +539,19 @@ var _ = Describe("CLI options", func() { }) Context("WithVersion", func() { - It("should use the provided version string", func() { - version := "Version: 0.0.0" - c, err = newCLI(WithVersion(version)) + It("should use the provided version struct", func() { + version := Version{ + KubeBuilderVersion: "123", + KubernetesVendor: "123", + GitCommit: "asdf1324", + BuildDate: "2025-11-19", + GoOs: "os123", + GoArch: "arch123", + } + c, err = newCLI(WithVersion(&version)) Expect(err).NotTo(HaveOccurred()) Expect(c).NotTo(BeNil()) - Expect(c.version).To(Equal(version)) + Expect(c.version).To(Equal(&version)) }) }) diff --git a/pkg/cli/version.go b/pkg/cli/version.go index f721c41ff0f..dcd15228f72 100644 --- a/pkg/cli/version.go +++ b/pkg/cli/version.go @@ -22,6 +22,32 @@ import ( "github.com/spf13/cobra" ) +// Version contains all the information related to the CLI version +type Version struct { + KubeBuilderVersion string `json:"kubeBuilderVersion"` + KubernetesVendor string `json:"kubernetesVendor"` + GitCommit string `json:"gitCommit"` + BuildDate string `json:"buildDate"` + GoOs string `json:"goOs"` + GoArch string `json:"goArch"` +} + +// String implements Stringer for Version so we can format the output as needed +func (v Version) String() string { + return fmt.Sprintf( + "Kubebuilder:\t%v\n"+ + "Kubernetes:\t%v\n"+ + "Git Commit:\t%v\n"+ + "Build Date:\t%v\n"+ + "OS/Arch:\t%v/%v", + v.KubeBuilderVersion, + v.KubernetesVendor, + v.GitCommit, + v.BuildDate, + v.GoOs, + v.GoArch) +} + func (c CLI) newVersionCmd() *cobra.Command { cmd := &cobra.Command{ Use: "version",