Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ Then run it from inside any git repository:
git_pruner
```

To print the build's commit and date (from Go's automatic VCS stamping):
To print the build's version (git tag), commit, and date (from Go's automatic VCS
stamping):

```sh
git_pruner version # also --version, -v
Expand Down
35 changes: 24 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,35 @@ import (
tea "github.com/charmbracelet/bubbletea"
)

// Build metadata. buildTime and gitCommit can be injected at link time via
// -ldflags "-X main.buildTime=... -X main.gitCommit=..." (or -X main.buildDate=...);
// when unset, buildInfo falls back to the VCS data the Go toolchain embeds.
// Build metadata. version, buildTime and gitCommit can be injected at link time via
// -ldflags "-X main.version=... -X main.buildTime=... -X main.gitCommit=..." (or
// -X main.buildDate=...); when unset, buildInfo falls back to the VCS data the Go
// toolchain embeds.
var (
version string
buildTime string
buildDate string
gitCommit string
)

// buildInfo returns the commit the binary was built from and when it was
// compiled, preferring -ldflags values and falling back to Go's embedded VCS info.
func buildInfo() (commit, date string) {
// buildInfo returns the version (git tag), the commit the binary was built from,
// and when it was compiled, preferring -ldflags values and falling back to Go's
// embedded VCS info.
func buildInfo() (ver, commit, date string) {
ver = version
commit = gitCommit
date = buildTime
if date == "" {
date = buildDate
}
dirty := false
if info, ok := debug.ReadBuildInfo(); ok {
// go build stamps this from git tags: "v0.1.0" on a tagged commit, a
// "v0.1.1-0.<time>-<hash>" pseudo-version on later commits, "+dirty" with
// uncommitted changes, and "(devel)" when it has no VCS info.
if ver == "" && info.Main.Version != "(devel)" {
ver = info.Main.Version
}
for _, s := range info.Settings {
switch s.Key {
case "vcs.revision":
Expand All @@ -42,6 +52,9 @@ func buildInfo() (commit, date string) {
}
}
}
if ver == "" {
ver = "unknown"
}
if commit == "" {
commit = "unknown"
}
Expand All @@ -54,18 +67,18 @@ func buildInfo() (commit, date string) {
if dirty {
commit += " (dirty)"
}
return commit, date
return ver, commit, date
}

// versionString reports the build's commit, date, and Go version. Fields fall
// back to "unknown" when build info is unavailable (e.g. `go run`).
// versionString reports the build's version, commit, date, and Go version.
// Fields fall back to "unknown" when build info is unavailable (e.g. `go run`).
func versionString() string {
commit, date := buildInfo()
ver, commit, date := buildInfo()
goVer := "unknown"
if info, ok := debug.ReadBuildInfo(); ok {
goVer = info.GoVersion
}
return fmt.Sprintf("git_pruner\n commit: %s\n date: %s\n go: %s", commit, date, goVer)
return fmt.Sprintf("git_pruner\n version: %s\n commit: %s\n date: %s\n go: %s", ver, commit, date, goVer)
}

func main() {
Expand Down
14 changes: 9 additions & 5 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2201,7 +2201,7 @@ func TestUnicodeNameAndEmptySubject(t *testing.T) {
// The version string is well-formed even when VCS build info is absent.
func TestVersionString(t *testing.T) {
s := versionString()
for _, want := range []string{"git_pruner", "commit:", "date:", "go:"} {
for _, want := range []string{"git_pruner", "version:", "commit:", "date:", "go:"} {
if !strings.Contains(s, want) {
t.Fatalf("version output missing %q:\n%s", want, s)
}
Expand All @@ -2211,24 +2211,28 @@ func TestVersionString(t *testing.T) {
func TestHelpViewIncludesBuildMetadata(t *testing.T) {
m := model{width: 80, height: 24}
v := m.helpView()
for _, want := range []string{"git_pruner — help", "build date:", "commit:"} {
for _, want := range []string{"git_pruner — help", "version:", "build date:", "commit:"} {
if !strings.Contains(v, want) {
t.Fatalf("help view missing %q:\n%s", want, v)
}
}
}

func TestBuildInfoLdflagsOverride(t *testing.T) {
origCommit, origDate, origTime := gitCommit, buildDate, buildTime
origVer, origCommit, origDate, origTime := version, gitCommit, buildDate, buildTime
defer func() {
gitCommit, buildDate, buildTime = origCommit, origDate, origTime
version, gitCommit, buildDate, buildTime = origVer, origCommit, origDate, origTime
}()

version = "v9.9.9"
gitCommit = "abcdef123456"
buildDate = "2026-09-01"
buildTime = ""

commit, date := buildInfo()
ver, commit, date := buildInfo()
if ver != "v9.9.9" {
t.Fatalf("expected version v9.9.9, got %q", ver)
}
if commit != "abcdef1" {
t.Fatalf("expected truncated commit abcdef1, got %q", commit)
}
Expand Down
5 changes: 3 additions & 2 deletions view.go
Original file line number Diff line number Diff line change
Expand Up @@ -558,8 +558,9 @@ func (m model) helpView() string {
"Protect more branches with: git config --add pruner.protect 'release/*'"))
b.WriteString("\n\n")

commit, date := buildInfo()
b.WriteString(dimStyle.Render(fmt.Sprintf("build date: %s · commit: %s", date, commit)))
ver, commit, date := buildInfo()
// Own line: a pseudo-version past the tag runs over 40 characters.
b.WriteString(dimStyle.Render(fmt.Sprintf("version: %s\nbuild date: %s · commit: %s", ver, date, commit)))
b.WriteString("\n\n")

b.WriteString(dimStyle.Render("press any key to return"))
Expand Down
Loading