1
0
Fork 0
mirror of https://github.com/imjasonh/version synced 2026-07-06 22:12:27 +00:00

embed main version too

Signed-off-by: Jason Hall <jason@chainguard.dev>
This commit is contained in:
Jason Hall 2025-04-08 13:23:42 -04:00
parent cc70df27de
commit 993c9c191e
Failed to extract signature
3 changed files with 25 additions and 11 deletions

View file

@ -70,12 +70,14 @@ As an aside, `k8s.io/client-go` had a [fun bug](https://github.com/kubernetes/ku
_But you don't need to do any of this nonsense at all, so stop!_ _But you don't need to do any of this nonsense at all, so stop!_
**Since Go 1.12, back in 2019**, the Go compiler has embedded this information for you, without you needing to know what an `ldflag` is. You can just call [`debug.ReadBuildInfo`](https://pkg.go.dev/runtime/debug#ReadBuildInfo) and it'll pop right out, along with a bunch of other stuff. **Since Go 1.12, back in 2019**, the Go compiler has embedded this information for you, without you needing to know what an `ldflag` is. You can just call [`debug.ReadBuildInfo`](https://pkg.go.dev/runtime/debug#ReadBuildInfo) and it'll pop right out, along with a bunch of other stuff. In Go 1.24 (Feb 2025), more VCS information was made available.
(The embedded information does not include information about the Git tag, presumably because there could be many of them, and they can easily move after the binary is built, so it's really the commit and its time that you care about.)
The `vcs.revision` and `vcs.time` are exactly the same as `git rev-parse HEAD` and "the date of that commit". So stop mucking with `ldflags`, and _especially_ stop embedding a non-reproducible time. You're working too hard. The `vcs.revision` and `vcs.time` are exactly the same as `git rev-parse HEAD` and "the date of that commit". So stop mucking with `ldflags`, and _especially_ stop embedding a non-reproducible time. You're working too hard.
This package demonstrates embedding `vcs.revision`, `vcs.time` and `vcs.clean` (whether there are non-committed changes), and encapsulates it in `version.Get`. This package demonstrates embedding `vcs.revision`, `vcs.time` and `vcs.clean` (whether there are non-committed changes), and the main package version, and encapsulates it in `version.Get`.
If you `go run ./cmd/example` there will be no embedded version info. If you `go build` and then run it, you'll get version info. If you `go install github.com/imjasonh/version/cmd/example@latest` you'll get the specific tag, for the latest semver tag.
---
If you want to change anything about the behavior, copy the code and go for it. I wrapped it in a [`sync.OnceFunc`](https://pkg.go.dev/sync#OnceFunc) so it didn't have to read the info each time, in case you call it multiple times. You're welcome. If you want to change anything about the behavior, copy the code and go for it. I wrapped it in a [`sync.OnceFunc`](https://pkg.go.dev/sync#OnceFunc) so it didn't have to read the info each time, in case you call it multiple times. You're welcome.

11
cmd/example/main.go Normal file
View file

@ -0,0 +1,11 @@
package main
import (
"fmt"
"github.com/imjasonh/version"
)
func main() {
fmt.Println(version.Get())
}

View file

@ -8,21 +8,22 @@ import (
) )
type Version struct { type Version struct {
Revision string Revision, Version, Time string
Time string Dirty bool
Dirty bool
} }
var ver = Version{ var ver = Version{
Revision: "unknown", Revision: "unknown",
Version: "unknown",
Time: "unknown", Time: "unknown",
Dirty: false, Dirty: false,
} }
func (v Version) String() string { func (v Version) String() string {
return fmt.Sprintf(`Revision: %s return fmt.Sprintf(`Revision: %s
Version: %s
BuildTime: %s BuildTime: %s
Dirty: %t`, v.Revision, v.Time, v.Dirty) Dirty: %t`, v.Revision, v.Version, v.Time, v.Dirty)
} }
func Get() Version { func Get() Version {
@ -32,10 +33,10 @@ func Get() Version {
slog.Warn("version: no build info detected") slog.Warn("version: no build info detected")
return return
} }
if bi.Main.Version != "" && bi.Main.Version != "(devel)" {
ver.Version = bi.Main.Version
}
for _, setting := range bi.Settings { for _, setting := range bi.Settings {
if setting.Value == "" {
continue
}
switch setting.Key { switch setting.Key {
case "vcs.revision": case "vcs.revision":
ver.Revision = setting.Value ver.Revision = setting.Value