Skip to content

✨ Improve version command output: add runtime fallbacks and unit tests. #4898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

Thedarkmatter10
Copy link

🔧 Refactor version logic: expose functions, add fallbacks, remove duplication, and add tests

Summary

This PR improves the internal versioning logic by making it more maintainable, testable, and robust.

✨ What’s Changed

  • Publicly exposed version helpers:

    • VersionInfo struct (was private version)
  • Removed duplication (DRY):

    • Centralized resolution logic using debug.ReadBuildInfo() into a helper

    • Eliminated repeated fallback code for resolving build info

  • Added runtime fallbacks:

    • Uses runtime.GOOS and runtime.GOARCH when not set via ldflags

    • Ensures gitCommit is validated and not left as $Format:%H$

  • Improved output formatting:

    • versionString() provides clean, human-readable output

    • versionJSON() supports structured, machine-readable output (useful in CI)

  • Renamed function Name from getKubebuilderVersion() to getKubeBuilderVersion() .

Added unit tests (version_test.go):

  • Validate output includes expected fields

  • Confirm versionJSON() is parsable and includes required keys

  • Ensure GetVersionInfo() returns non-empty, resolved values

🧠 Why It Matters

  • Ensures test coverage for a previously untested code path

  • Helps catch missing ldflags values (e.g. empty Git commit) early

  • Lays the foundation for long-term maintainability of CLI version reporting

📈 Impact

  • Exposes version info for programmatic and CLI use

  • Adds meaningful tests that reduce risk of silent version resolution failures

  • Improves developer and CI experience with cleaner output and stronger guarantees

Copy link

linux-foundation-easycla bot commented Jul 1, 2025

CLA Signed

The committers listed above are authorized under a signed CLA.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. label Jul 1, 2025
@k8s-ci-robot
Copy link
Contributor

Welcome @Thedarkmatter10!

It looks like this is your first PR to kubernetes-sigs/kubebuilder 🎉. Please refer to our pull request process documentation to help your PR have a smooth ride to approval.

You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. Here is the bot commands documentation.

You can also check if kubernetes-sigs/kubebuilder has its own contribution guidelines.

You may want to refer to our testing guide if you run into trouble with your tests not passing.

If you are having difficulty getting your pull request seen, please follow the recommended escalation practices. Also, for tips and tricks in the contribution process you may want to read the Kubernetes contributor cheat sheet. We want to make sure your contribution gets all the attention it needs!

Thank you, and welcome to Kubernetes. 😃

@k8s-ci-robot
Copy link
Contributor

Hi @Thedarkmatter10. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Jul 1, 2025
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Thedarkmatter10
Once this PR has been reviewed and has the lgtm label, please assign camilamacedo86 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. and removed cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels Jul 1, 2025
@Thedarkmatter10
Copy link
Author

@camilamacedo86 @Kavinjsir

@Thedarkmatter10 Thedarkmatter10 changed the title (✨)refactor: remove duplication, add runtime fallbacks and unit tests. 🌱 refactor: remove duplication, add runtime fallbacks and unit tests. Jul 1, 2025
@Thedarkmatter10 Thedarkmatter10 force-pushed the version/refactor-add-tests branch from 3a825c1 to 0610694 Compare July 1, 2025 19:04
@camilamacedo86
Copy link
Member

/ok-to-test

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Jul 2, 2025
@Thedarkmatter10 Thedarkmatter10 force-pushed the version/refactor-add-tests branch from 0610694 to 63173f7 Compare July 3, 2025 10:26
@camilamacedo86
Copy link
Member

camilamacedo86 commented Jul 3, 2025

Hi @Thedarkmatter10

See that the testdata job will be fixed with: #4905
Also, we must to have just one commit before merge out, could you please squash it?

By last since it will produce a change for end users it should end up in our release notes
The title of PRs is our release notes ,and so, we cannot use 🌱

We need to use like ✨ and add a text that clarifies what was done such as :

Improve output of version command to...

Could you please update those things?
Thank you a lot for your contribution 🥇

@Thedarkmatter10 Thedarkmatter10 changed the title 🌱 refactor: remove duplication, add runtime fallbacks and unit tests. ✨ Improve version command output: add runtime fallbacks and unit tests. Jul 3, 2025
@Thedarkmatter10 Thedarkmatter10 force-pushed the version/refactor-add-tests branch 2 times, most recently from df6f0c9 to 5649294 Compare July 3, 2025 13:21
@Thedarkmatter10
Copy link
Author

Hi @Thedarkmatter10

See that the testdata job will be fixed with: #4905 Also, we must to have just one commit before merge out, could you please squash it?

By last since it will produce a change for end users it should end up in our release notes The title of PRs is our release notes ,and so, we cannot use 🌱

We need to use like ✨ and add a text that clarifies what was done such as :

Improve output of version command to...

Could you please update those things? Thank you a lot for your contribution 🥇

Hi @camilamacedo86 👋

I tried squashing the commits into one as suggested, but I ran into some issues with rebase and merge conflicts that I wasn't able to resolve cleanly. As a result, the PR still shows extra commits.

Apologies for the inconvenience caused 🙏 . I understand the importance of keeping the commit history clean and will make sure not to repeat this in future contributions.

Please let me know if you'd prefer that I close this PR and open a fresh one with a clean history, or if there's another way you'd like to proceed.
and also i renamed title of PR.

Thanks again for your guidance and patience! 😊

@camilamacedo86
Copy link
Member

/test pull-kubebuilder-e2e-k8s-1-32-0

Comment on lines +79 to +94
// versionString returns a human-friendly string version
func versionString() string {
v := getVersionInfo()
return fmt.Sprintf(`KubeBuilder Version: %s
Kubernetes Vendor: %s
Git Commit: %s
Build Date: %s
Go OS/Arch: %s/%s`,
v.KubeBuilderVersion,
v.KubernetesVendor,
v.GitCommit,
v.BuildDate,
v.GoOS,
v.GoArch,
)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@camilamacedo86 @Thedarkmatter10 could we move the output formatting to cli/version.go?

I think that separating the data gathering logic from the presentation logic could give us more flexibility to deal with output formatting, add flags, and leave room for other tools/commands to define how they want to display the version. The same goes for the JSON output. We could turn that into a flag in cli/version.go.

This separation was discussed briefly in a previous PR conversation (before I messed up and closed the PR).

WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that make sense we could do something like

if jsonOutput {
    printAsJSON(GetVersionInfo())
} else {
    printPretty(GetVersionInfo())
}

But I would accept it in a follow up PR as well
I think the goal of this one ( unless I misunderstood) would be add only the printPretty part

@camilamacedo86
Copy link
Member

Hi @Thedarkmatter10

This one is not passing all tests.
Can you please rebase with master and fix the lint issues?

@Thedarkmatter10 Thedarkmatter10 force-pushed the version/refactor-add-tests branch from 5649294 to a402ee3 Compare July 24, 2025 06:54
@Thedarkmatter10
Copy link
Author

Hi @Thedarkmatter10

This one is not passing all tests. Can you please rebase with master and fix the lint issues?

Hi @camilamacedo86 ,

I’ve completed the rebase successfully.

Regarding the multiple file changes that are showing up: these seem to be caused by running golangci-lint on my Windows machine, which has likely introduced differences in line endings (CRLF vs LF). This ends up marking a lot of files as changed even though there are no logical code modifications.

Since changing all these files would introduce noise in the PR, I’ve held off committing them. Would you be able to re-run golangci-lint on a Unix/Linux environment on your side to avoid the line-ending conflict? Or alternatively, let me know how you'd prefer to handle this I’m happy to follow any suggestion.

Thanks!

@camilamacedo86
Copy link
Member

camilamacedo86 commented Jul 24, 2025

Hi @Thedarkmatter10

Thank you for your effort in this one.
See the lint issue:

level=error msg="Running error: context loading failed: no go files to analyze: running go mod tidy may solve the problem"

Could you run go mod tidy
And make verify?

Also, this one should tirgger: https://github.com/kubernetes-sigs/kubebuilder/blob/master/.github/workflows/release-version-ci.yml . The path is wrong, we need to add cmd/ as well. Could you please update it to add the path?

By last we need to have all in the same commit, could you please squash?

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 25, 2025
@Thedarkmatter10 Thedarkmatter10 force-pushed the version/refactor-add-tests branch from af7db2f to c4a0d3e Compare July 25, 2025 11:58
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 25, 2025
@Thedarkmatter10
Copy link
Author

Hi @camilamacedo86,

I hope you're doing well.
I wanted to kindly check if there's anything else pending from my side to get this PR merged. Please let me know if any further changes are needed.

Thank you

@camilamacedo86
Copy link
Member

Hi @Thedarkmatter10,

Hope you're doing well!

Just wanted to kindly check if there’s anything else pending on my side to get this PR merged. Please let me know if any further changes are needed.

I saw you’ve resolved all CI issues and rebased—thank you! 🎉

Could you please squash the commits? We aim for 1 commit per PR = 1 problem = 1 solution. This helps keep our git history clean and avoids conflicts when reverting or cherry-picking changes.

Once that’s done, I’ll take a final look. Now that all tests are green, it should be quick!

"runtime/debug"
)

const unknown = "unknown"

// var needs to be used instead of const as ldflags is used to fill this
// information in the release process
// These are filled via ldflags during build
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep the previous comments?

var (
kubeBuilderVersion = unknown
kubernetesVendorVersion = "1.33.0"
goos = unknown
goarch = unknown
gitCommit = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD)

buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep the previous comments?

Comment on lines +38 to +39
// VersionInfo holds all CLI version-related information
type VersionInfo struct {
Copy link
Member

@camilamacedo86 camilamacedo86 Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// VersionInfo holds all CLI version-related information
type VersionInfo struct {
// version holds all CLI version-related information
type version struct {

Can we avoid externalising this one?
If we externalise it (e.g., by using v instead of V), it becomes accessible outside of Kubebuilder and effectively becomes part of its public API.

We intentionally do not want to expose this structure for use by other projects. Let's keep it internal to maintain tighter control and avoid unintended usage.

"github.com/stretchr/testify/assert"
)

func TestVersionStringIncludesExpectedFields(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Amazing 🚀

Comment on lines +55 to +60
if goos == unknown {
goos = runtime.GOOS
}
if goarch == unknown {
goarch = runtime.GOARCH
}
Copy link
Member

@camilamacedo86 camilamacedo86 Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for the suggestion! 🙌

However, I think we should not fallback to runtime.GOOS / runtime.GOARCH here.

if goos == unknown {
	goos = runtime.GOOS
}
if goarch == unknown {
	goarch = runtime.GOARCH
}

This will always reflect the build-time platform — not the actual target platform of the binary.
For example, in our case, all builds run on Ubuntu (see our GoReleaser config), so this will return:

GOOS = "linux"
GOARCH = "amd64"

—even for macOS binaries like darwin/amd64. This results in incorrect output when users run:

kubebuilder version

We already inject the correct values using -ldflags at build time, and if something goes wrong with that injection, it's better to leave the values as "unknown" to surface the issue, rather than silently reporting incorrect metadata.

Could we please revert it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, see : https://github.com/kubernetes-sigs/kubebuilder/pull/4516/files
It can either be used if kubebuilder is installed with go install module
(another behaviour that we need to consider)

Copy link
Member

@camilamacedo86 camilamacedo86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really appreciate your contribution here 🥇 — and sorry for the delay in reviewing it!

This change definitely makes the output nicer (thank you for that!) 🚀, but we have to be extra cautious because it touches parts that can affect things in more subtle ways — especially around how the CLI is released and used as a Go module or by other libraries.

Even small changes here can impact consumers or break the release process in ways that aren’t easily caught by tests. That’s why we need to be conservative when altering this part of the code.

Thanks again for the effort — it’s super valuable, and we’d love to find a safe path forward if we can!
I've added a few comments — the main concerns are:

  • These methods should remain private. They're internal to Kubebuilder, and exposing them would mean supporting them as part of our public API, which we don’t intend to do.

  • The fallback logic:

    if goos == unknown {
    	goos = runtime.GOOS
    }
    if goarch == unknown {
    	goarch = runtime.GOARCH
    }

    can introduce misleading output. Since our builds run on Ubuntu
    (GoReleaser config), this would always return:

    linux/amd64

    —even for macOS binaries, which can confuse users and scripts relying on kubebuilder version.

Would you be open to adjusting the implementation to:

  • Keep the fallback logic removed — rely on ldflags only
  • Limit the scope of the PR to just the necessary improvements
  • Keep internal methods unexported and avoid API surface changes

We really appreciate the effort and want to support your contribution!

@camilamacedo86 camilamacedo86 requested a review from Copilot August 3, 2025 19:16
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the version command logic to improve maintainability, testability, and robustness by exposing version helpers, adding runtime fallbacks, and providing comprehensive test coverage.

  • Exposed internal version structures and functions for programmatic access
  • Added runtime fallbacks for OS/Arch detection and Git commit validation
  • Introduced comprehensive unit tests to validate version command behavior

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
go.mod Adds testify dependency for unit testing
cmd/version_test.go Comprehensive unit tests for version command functionality
cmd/version.go Refactored version logic with exposed VersionInfo struct and improved formatting
cmd/cmd.go Function name correction from getKubebuilderVersion to getKubeBuilderVersion

// versionJSON returns version as JSON string
func versionJSON() string {
v := getVersionInfo()
b, _ := json.MarshalIndent(v, "", " ")
Copy link
Preview

Copilot AI Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error from json.MarshalIndent is being ignored. While this is unlikely to fail for a simple struct, it's better practice to handle the error or document why it's safe to ignore.

Copilot uses AI. Check for mistakes.

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Aug 9, 2025
@k8s-ci-robot
Copy link
Contributor

PR needs rebase.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants