Skip to content

add version command to kubestr#378

Open
adamMolner wants to merge 6 commits into
kastenhq:masterfrom
adamMolner:feat/add-version-command
Open

add version command to kubestr#378
adamMolner wants to merge 6 commits into
kastenhq:masterfrom
adamMolner:feat/add-version-command

Conversation

@adamMolner
Copy link
Copy Markdown

@adamMolner adamMolner commented Mar 14, 2026

addresses issue: #138

This PR adds a version command to kubestr.

It does two things:

  1. Adds a version variable to cmd/rootCmd.go that defaults to "dev" and gets overwritten at build time via -ldflags when goreleaser builds an official release
  2. For binaries built from source with go build ., falls back to reading the git commit hash that Go automatically bakes into the binary since Go 1.18 (see runtime/debug.BuildSetting) — this way dev builds still show something useful. A -dirty suffix is appended if there were uncommitted changes at build time, following the convention established by git describe --dirty

The behavior looks like this depending on how the binary was built:

# Official release binary (built by goreleaser)
$ kubestr version
v0.4.49

# Built from source at a clean commit
$ kubestr version
dev (0157133)

# Built from source with uncommitted changes
$ kubestr version
dev (0157133-dirty)

# Built outside a git repo (e.g. from a source tarball)
$ kubestr version
dev

Unfortunately there is no single approach that works for all cases since go build and go install behave differently with respect to version stamping. The hybrid approach here covers all realistic scenarios without requiring changes to the release pipeline beyond adding the -X ldflag.

Summary by CodeRabbit

  • New Features
    • Added a version command that prints the current build version.
    • Builds now embed a version string so the version command shows the injected release version; if absent, it falls back to a development label including a short VCS revision and a dirty marker when applicable.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 14, 2026

Warning

Rate limit exceeded

@adamMolner has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 36 minutes and 58 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c5224924-181e-497c-8a1b-4699c8b67633

📥 Commits

Reviewing files that changed from the base of the PR and between bd2083a and 76e6719.

📒 Files selected for processing (2)
  • .goreleaser.yml
  • cmd/rootCmd.go
📝 Walkthrough

Walkthrough

Adds build-time version injection via ldflags in the release config and a new CLI version command plus getVersion() runtime function that returns the injected version or a VCS-derived fallback (short commit or "dev").

Changes

Cohort / File(s) Summary
Build Configuration
./.goreleaser.yml
Adds ldflags to set github.com/kastenhq/kubestr/cmd.version to the {{.Version}} template during builds.
CLI & Runtime Versioning
cmd/rootCmd.go
Adds a package-level version variable, implements getVersion() to prefer the injected value and fall back to VCS info or "dev", and registers a version Cobra subcommand wired into init().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I stitched a tag into the final link,
A whispered commit when builds get sync.
Type version and you shall see,
Release, short-sha, or plain "dev" be —
Hop on, the changelog's brimming 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a version command to the kubestr CLI, which is the primary objective of this pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 36 minutes and 58 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/rootCmd.go`:
- Around line 160-166: Add an args validator and use Cobra's output on the
version command: update the versionCmd declaration to include Args: cobra.NoArgs
to reject extra operands, and replace the direct fmt.Println call in the Run
function with cmd.Println(GetVersion()) so output respects Cobra's configured
output stream; locate this change in the versionCmd definition and the Run
closure where GetVersion() is printed.
- Around line 577-601: The version logic currently ignores info.Main.Version
from debug.ReadBuildInfo(), causing binaries built via "go install
module@version" to show "dev"; update the function that calls
debug.ReadBuildInfo() to first check info.Main.Version (from the returned info
variable) and if it's non-empty and not the "(devel)" sentinel, return that
module version string immediately (before scanning info.Settings for
vcs.revision/vcs.modified); keep the existing VCS-based short SHA logic as a
fallback if info.Main.Version is empty, and still return "dev" only when neither
info.Main.Version nor VCS info are available.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d14fe7ae-b67f-4978-8297-f8df078c5c76

📥 Commits

Reviewing files that changed from the base of the PR and between 0157133 and a786287.

📒 Files selected for processing (2)
  • .goreleaser.yml
  • cmd/rootCmd.go

Comment thread cmd/rootCmd.go
Comment thread cmd/rootCmd.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
cmd/rootCmd.go (1)

578-602: ⚠️ Potential issue | 🟠 Major

GetVersion() still misses go install module@version builds.

At Line 578+, the logic only inspects info.Settings. For binaries installed via go install ...@vX.Y.Z, info.Main.Version is typically the authoritative value and VCS settings may be absent, so this can incorrectly return "dev".

Suggested fix
 	info, ok := debug.ReadBuildInfo()
 	if !ok {
 		// No build info available (e.g. built outside a git repo).
 		return "dev"
 	}
+	if v := info.Main.Version; v != "" && v != "(devel)" {
+		return v
+	}
 	var revision, modified string
 	for _, s := range info.Settings {
#!/bin/bash
# Verify current GetVersion logic does not check info.Main.Version before VCS fallback.
rg -n 'ReadBuildInfo|info\.Main\.Version|vcs\.revision|vcs\.modified' cmd/rootCmd.go -C2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/rootCmd.go` around lines 578 - 602, GetVersion currently only reads
info.Settings for vcs.revision/vcs.modified and returns "dev" when those are
absent; update GetVersion (the function using debug.ReadBuildInfo and
info.Settings) to first check info.Main.Version and if it is non-empty and not
"(devel)" return that version (so go install module@vX.Y.Z builds are
respected), otherwise fall back to the existing loop over info.Settings to
derive a short vcs.revision plus optional -dirty and then the final "dev"
fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@cmd/rootCmd.go`:
- Around line 578-602: GetVersion currently only reads info.Settings for
vcs.revision/vcs.modified and returns "dev" when those are absent; update
GetVersion (the function using debug.ReadBuildInfo and info.Settings) to first
check info.Main.Version and if it is non-empty and not "(devel)" return that
version (so go install module@vX.Y.Z builds are respected), otherwise fall back
to the existing loop over info.Settings to derive a short vcs.revision plus
optional -dirty and then the final "dev" fallback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: de806031-4736-4eb2-88c7-432153748f95

📥 Commits

Reviewing files that changed from the base of the PR and between a786287 and 102ba71.

📒 Files selected for processing (1)
  • cmd/rootCmd.go

Comment thread cmd/rootCmd.go Outdated
// If the version was injected at build time via ldflags by goreleaser, it returns that.
// Otherwise, it falls back to reading the git commit hash that Go automatically
// bakes into the binary since Go 1.18 (see runtime/debug.BuildSetting).
func GetVersion() string {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@adamMolner does this function need to be exported? or could it be "unexported"?

Suggested change
func GetVersion() string {
func getVersion() string {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Comment thread cmd/rootCmd.go Outdated
)

var (
version = "dev" // overridden at build time via ldflags
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This could be empty by default, since the fallback would be to get it from the runtime when it is not explicitly set.

Suggested change
version = "dev" // overridden at build time via ldflags
version string // overridden at build time via ldflags

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Comment thread cmd/rootCmd.go Outdated
func GetVersion() string {
// version is set at build time via ldflags by goreleaser (e.g. v0.4.49).
// If it was injected, return it.
if version != "dev" {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
if version != "dev" {
if version != "" {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Comment thread cmd/rootCmd.go Outdated
}
}
if revision != "" {
return fmt.Sprintf("dev (%s%s)", revision, modified)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

maybe modify the format so it does not contain spaces?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown

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

Adds a kubestr version CLI command and wires release builds to inject a version string via GoReleaser, with a development fallback that reads VCS build info (revision + dirty state) from Go’s embedded build metadata.

Changes:

  • Introduces a version subcommand that prints a computed version string.
  • Adds GetVersion() to return either an ldflags-injected release version or a dev version derived from embedded VCS metadata.
  • Updates GoReleaser build configuration to set cmd.version at link time.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
cmd/rootCmd.go Adds version command, version build variable, and GetVersion() fallback logic based on debug.ReadBuildInfo().
.goreleaser.yml Injects build-time version into cmd.version using -ldflags -X ....

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/rootCmd.go Outdated
versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version of kubestr",
Args: cobra.NoArgs,
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

versionCmd uses cobra.NoArgs while other commands in this file consistently use cobra.ExactArgs(0) for no-arg commands (e.g., fioCmd, csiCheckCmd, blockMountCmd). Consider switching to cobra.ExactArgs(0) for consistency across commands.

Suggested change
Args: cobra.NoArgs,
Args: cobra.ExactArgs(0),

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I originally had cobra.ExactArgs(0), but coderabbit said change it to NoArgs, but then copilot said change it back to match our conventions.

76e6719

Comment thread cmd/rootCmd.go
Comment on lines +570 to +574
// version is set at build time via ldflags by goreleaser (e.g. v0.4.49).
// If it was injected, return it.
if version != "dev" {
return version
}
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

GetVersion() returns version for any value other than "dev"; if the ldflag is accidentally set to an empty string, kubestr version will print a blank line. Consider treating empty string as unset (e.g., only returning version when it is non-empty and not "dev").

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in a comment above. #378 (comment)

Comment thread .goreleaser.yml Outdated
Comment on lines +11 to +12
ldflags:
- -X github.com/kastenhq/kubestr/cmd.version={{.Version}}
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

This injects {{.Version}} into cmd.version, but GoReleaser templates typically set .Version to the semver without a leading "v" (while .Tag includes it). If the intention is for kubestr version to print vX.Y.Z as shown in the PR description, consider injecting {{.Tag}} or prefixing v explicitly.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

e2aa891

The ldflag that injects the version string into the binary went from {{.Version}} to v{{ trimprefix .Version "v" }}. Goreleaser's .Version is the git tag with the leading v stripped (so v0.4.49 becomes 0.4.49), which meant kubestr version would print 0.4.49 for real releases — missing the v that's on the tag and release page. The new template strips any leading v and re-adds it, guaranteeing exactly one v prefix in all build modes (real release, snapshot, etc.) and avoiding the double-vv you'd get if you naively prepended v to a value that already had one.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
cmd/rootCmd.go (1)

160-166: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use Cobra’s output writer here.

fmt.Println() bypasses the command’s configured streams, so kubestr version is harder to test and won’t honor redirected output. Switch this to cmd.Println(getVersion()).

Suggested fix
 versionCmd = &cobra.Command{
 	Use:   "version",
 	Short: "Print the version of kubestr",
 	Args:  cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
-		fmt.Println(getVersion())
+		cmd.Println(getVersion())
 	},
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/rootCmd.go` around lines 160 - 166, The version command is printing via
fmt.Println which bypasses Cobra's output streams; update the Run function of
versionCmd to write using the command's output writer by replacing
fmt.Println(getVersion()) with cmd.Println(getVersion()) so the getVersion()
result goes through Cobra's configured streams (use the cmd parameter available
in the Run func).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@cmd/rootCmd.go`:
- Around line 160-166: The version command is printing via fmt.Println which
bypasses Cobra's output streams; update the Run function of versionCmd to write
using the command's output writer by replacing fmt.Println(getVersion()) with
cmd.Println(getVersion()) so the getVersion() result goes through Cobra's
configured streams (use the cmd parameter available in the Run func).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f37bea03-1e83-45e2-8f53-36eb104e5941

📥 Commits

Reviewing files that changed from the base of the PR and between 102ba71 and bd2083a.

📒 Files selected for processing (1)
  • cmd/rootCmd.go

@adamMolner adamMolner requested a review from julio-lopez May 1, 2026 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants