From f51680f83cd1cd20a362910757325b1b3f4af686 Mon Sep 17 00:00:00 2001 From: Florian Walther Date: Sat, 3 Oct 2026 19:38:48 +0200 Subject: [PATCH] show version with branch and commit in help and -version - add -version flag (besides --version and -V) - help output includes the version - commit and branch are set via ldflags by goreleaser; plain go build falls back to the VCS revision embedded by Go Co-Authored-By: Claude Opus 5.5 --- .goreleaser.yaml | 2 +- README.md | 10 ++++++++ main.go | 59 +++++++++++++++++++++++++++++++++++++++++++----- main_test.go | 15 ++++++++++++ 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 9d2a454..b17f6d8 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -22,7 +22,7 @@ builds: flags: - -trimpath ldflags: - - -s -w -X main.version={{ .Version }} + - -s -w -X main.version={{ .Version }} -X main.commit={{ .ShortCommit }} -X main.branch={{ .Branch }} goos: - linux - darwin diff --git a/README.md b/README.md index f645170..bfdf2d1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ``` gosh - Go Shell +Version: 0.2.1 (branch: main, commit: 03e791c) Built-in commands: cd [dir] - Change directory (cd with no args goes to home) @@ -102,6 +103,15 @@ _gosh is not meant for production use, it is just a proof of concept._ go build ./ ``` +Die Version lässt sich mit `gosh -version` (oder `--version`, `-V`) abfragen und steht auch in der Ausgabe von `help`: + +``` +$ gosh -version +gosh 0.2.1 (branch: main, commit: 03e791c) +``` + +Version und Branch werden beim Bauen mit GoReleaser per `-ldflags` gesetzt. Bei einem einfachen `go build` steht dort `dev`, der Commit wird dann aus den von Go eingebetteten Git-Informationen gelesen (mit `-dirty`, falls es uncommittete Änderungen gab). + ## Release Binaries sowie `.deb`- und `.rpm`-Pakete werden mit [GoReleaser](https://goreleaser.com) gebaut (Konfiguration: `.goreleaser.yaml`). diff --git a/main.go b/main.go index 73bc158..4054309 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "os/signal" "os/user" "path/filepath" + "runtime/debug" "strings" "unicode" "unicode/utf8" @@ -19,8 +20,51 @@ import ( // ErrNoPath is returned when 'cd' was called without a second argument. var ErrNoPath = errors.New("path required") -// version is set at build time via -ldflags "-X main.version=..." -var version = "dev" +// Build information, set at build time via +// -ldflags "-X main.version=... -X main.commit=... -X main.branch=...". +var ( + version = "dev" + commit = "" + branch = "" +) + +// versionInfo returns the version including branch and commit, e.g. +// "0.2.1 (branch: main, commit: 03e791c)". Without ldflags (plain go build) +// the commit is taken from the VCS information that Go embeds in the binary. +func versionInfo() string { + c := commit + if c == "" { + if info, ok := debug.ReadBuildInfo(); ok { + var dirty bool + for _, s := range info.Settings { + switch s.Key { + case "vcs.revision": + c = s.Value + case "vcs.modified": + dirty = s.Value == "true" + } + } + if len(c) > 7 { + c = c[:7] + } + if c != "" && dirty { + c += "-dirty" + } + } + } + + var details []string + if branch != "" { + details = append(details, "branch: "+branch) + } + if c != "" { + details = append(details, "commit: "+c) + } + if len(details) == 0 { + return version + } + return version + " (" + strings.Join(details, ", ") + ")" +} // previousDir tracks the previous working directory for 'cd -' support var previousDir string @@ -568,9 +612,12 @@ func completeFilePath(line, prefix string) []string { } func main() { - if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "-V") { - fmt.Println("gosh", version) - return + if len(os.Args) > 1 { + switch os.Args[1] { + case "-version", "--version", "-V": + fmt.Println("gosh", versionInfo()) + return + } } // Ctrl+C sends SIGINT to the whole foreground process group. Catch it so @@ -727,7 +774,7 @@ func execInput(input string) error { os.Setenv(parts[0], parts[1]) return nil case "help": - fmt.Println(`gosh - Go Shell + fmt.Println("gosh - Go Shell\nVersion: " + versionInfo() + ` Built-in commands: cd [dir] - Change directory (cd with no args goes to home) diff --git a/main_test.go b/main_test.go index dee7ff4..d8a5ef9 100644 --- a/main_test.go +++ b/main_test.go @@ -648,6 +648,21 @@ func TestExecInput_ExportNoArgs(t *testing.T) { } } +func TestVersionInfo(t *testing.T) { + origVersion, origCommit, origBranch := version, commit, branch + defer func() { version, commit, branch = origVersion, origCommit, origBranch }() + + version, commit, branch = "1.2.3", "abc1234", "main" + if got := versionInfo(); got != "1.2.3 (branch: main, commit: abc1234)" { + t.Errorf("versionInfo() = %q", got) + } + + branch = "" + if got := versionInfo(); got != "1.2.3 (commit: abc1234)" { + t.Errorf("versionInfo() without branch = %q", got) + } +} + func TestExecInput_Help(t *testing.T) { // Just verify help doesn't return an error // We can't easily capture stdout in a unit test without a pipe