Files
Vintner/cmd/vintner/version.go
T
Cheviiot 94a19e6b43 Show git commit and build time in vintner version
Uses Go's automatic VCS build-info stamping (vcs.revision/vcs.time/
vcs.modified, embedded by `go build` since Go 1.18 - no -ldflags
changes needed, works the same for a CI release build and a plain
local `go build`). Knowing the exact commit a bug report's binary was
built from, not just the X.Y.Z tag, is the point - two builds of the
same tag could still differ.

Split the pure formatting logic (formatVersion) from the
debug.ReadBuildInfo() call so it's actually unit-testable: `go test`
binaries don't get VCS stamping the way `go build` ones do, so there
was no way to exercise the revision-formatting branch through
versionString() itself.
2026-07-25 11:37:02 +10:00

57 lines
1.8 KiB
Go

package main
import (
"fmt"
"runtime/debug"
)
// versionString renders "vintner <version>" plus, when available, the git
// commit and build time Go's toolchain embeds automatically (since Go
// 1.18, `go build` stamps vcs.revision/vcs.time/vcs.modified into the
// binary on its own - no -ldflags needed for this part, so it works the
// same whether the binary came from CI or a plain local `go build`).
// Knowing the exact commit a reported bug was built from, not just the
// X.Y.Z tag, is the point: two builds of the same tag could still differ
// if the tag was ever moved, or if someone built from an uncommitted tree.
//
// Note for anyone testing this: `go build` stamps vcs.* build settings,
// but `go test` binaries don't get them - there's no environment where a
// `go test` run can exercise the revision-formatting branch below, hence
// formatVersion is split out and tested directly instead.
func versionString() string {
revision, buildTime, dirty := "", "", false
if info, ok := debug.ReadBuildInfo(); ok {
for _, s := range info.Settings {
switch s.Key {
case "vcs.revision":
revision = s.Value
case "vcs.time":
buildTime = s.Value
case "vcs.modified":
dirty = s.Value == "true"
}
}
}
return formatVersion(version, revision, buildTime, dirty)
}
// formatVersion is the pure part of versionString: given a revision (full
// git SHA, may be empty), it's shortened to 12 chars and marked "-dirty" if
// the build tree had uncommitted changes.
func formatVersion(ver, revision, buildTime string, dirty bool) string {
v := "vintner " + ver
if revision == "" {
return v
}
if len(revision) > 12 {
revision = revision[:12]
}
if dirty {
revision += "-dirty"
}
if buildTime != "" {
return fmt.Sprintf("%s (%s, %s)", v, revision, buildTime)
}
return fmt.Sprintf("%s (%s)", v, revision)
}