common/version/version.go

167 lines
3.2 KiB
Go

package version
import (
"fmt"
"log/slog"
"runtime"
"runtime/debug"
"strings"
"github.com/prometheus/client_golang/prometheus"
"github.com/spf13/cobra"
"golang.org/x/mod/semver"
)
// VERSION has the current software version (set in the build process)
var VERSION string
var buildTime string
var gitVersion string
var gitModified bool
var info Info
type Info struct {
Version string `json:",omitempty"`
GitRev string `json:",omitempty"`
GitRevShort string `json:",omitempty"`
BuildTime string `json:",omitempty"`
}
func init() {
info.BuildTime = buildTime
info.GitRev = gitVersion
if len(VERSION) == 0 {
VERSION = "dev-snapshot"
} else {
if !strings.HasPrefix(VERSION, "v") {
VERSION = "v" + VERSION
}
if !semver.IsValid(VERSION) {
slog.Default().Warn("invalid version number", "version", VERSION)
}
}
if bi, ok := debug.ReadBuildInfo(); ok {
for _, h := range bi.Settings {
// logger.Setup().Info("build info", "k", h.Key, "v", h.Value)
switch h.Key {
case "vcs.time":
if len(buildTime) == 0 {
buildTime = h.Value
}
info.BuildTime = h.Value
case "vcs.revision":
// https://blog.carlmjohnson.net/post/2023/golang-git-hash-how-to/
// todo: use BuildInfo.Main.Version if revision is empty
info.GitRev = h.Value
// if gitVersion != h.Value {
// logger.Setup().Warn("gitVersion and info.GitRev differs", "gitVersion", gitVersion, "gitRev", info.GitRev)
// }
gitVersion = h.Value
case "vcs.modified":
if h.Value == "true" {
gitModified = true
}
}
}
}
info.GitRevShort = info.GitRev
if len(info.GitRevShort) > 7 {
info.GitRevShort = info.GitRevShort[:7]
}
info.Version = VERSION
Version()
}
func VersionCmd(name string) *cobra.Command {
versionCmd := &cobra.Command{
Use: "version",
Short: "Print version and build information",
Run: func(cmd *cobra.Command, args []string) {
ver := Version()
fmt.Printf("%s %s\n", name, ver)
},
}
return versionCmd
}
func RegisterMetric(name string, registry prometheus.Registerer) {
if len(name) > 0 {
name = strings.ReplaceAll(name, "-", "_")
name = name + "_build_info"
} else {
name = "build_info"
}
buildInfo := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: name,
Help: "Build information",
},
[]string{
"version",
"buildtime",
"gittime",
"git",
},
)
registry.MustRegister(buildInfo)
info := VersionInfo()
buildInfo.WithLabelValues(
fmt.Sprintf("%s/%s",
info.Version, info.GitRevShort,
),
buildTime,
info.BuildTime,
info.GitRev,
).Set(1)
}
var v string
func VersionInfo() Info {
return info
}
func Version() string {
if len(v) > 0 {
return v
}
extra := []string{}
if len(buildTime) > 0 {
extra = append(extra, buildTime)
}
extra = append(extra, runtime.Version())
v := VERSION
if len(gitVersion) > 0 {
g := gitVersion
if len(g) > 7 {
g = g[0:7]
}
v += "/" + g
if gitModified {
v += "-M"
}
}
v = fmt.Sprintf("%s (%s)", v, strings.Join(extra, ", "))
return v
}
func CheckVersion(version, minimumVersion string) bool {
if version == "dev-snapshot" {
return true
}
if semver.Compare(version, minimumVersion) < 0 {
// log.Debug("version too old", "v", cl.Version.Version)
return false
}
return true
}