sq/cli/buildinfo/buildinfo.go
Neil O'Toole 0f9b5e2a75
"sq version" now honors format.datetime option (#330)
* sq version now honors config option format.date

* CHANGELOG update

* sq version now honors config option format.date
2023-11-19 20:28:09 -07:00

119 lines
2.8 KiB
Go

// Package buildinfo hosts build info variables populated via ldflags.
//
// For testing, you can override the build version
// using envar SQ_BUILD_VERSION (panics if not a valid semver).
package buildinfo
import (
"fmt"
"log/slog"
"os"
"strings"
"time"
"golang.org/x/mod/semver"
"github.com/neilotoole/sq/libsq/core/lg/lga"
"github.com/neilotoole/sq/libsq/core/timez"
)
// DefaultVersion is the default value for Version if not
// set via ldflags.
const DefaultVersion = "v0.0.0-dev"
var (
// Version is the build version. If not set at build time via
// ldflags, Version takes the value of DefaultVersion.
Version = DefaultVersion
// Commit is the commit hash.
Commit string
// Timestamp is the timestamp of when the cli was built.
Timestamp string
)
// BuildInfo encapsulates Version, Commit and Timestamp.
type BuildInfo struct {
Version string `json:"version" yaml:"version"`
Commit string `json:"commit,omitempty" yaml:"commit,omitempty"`
Timestamp time.Time `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`
}
// String returns a string representation of BuildInfo.
func (bi BuildInfo) String() string {
s := bi.Version
if bi.Commit != "" {
s += " " + bi.Commit
}
if !bi.Timestamp.IsZero() {
s += " " + bi.Timestamp.Format(timez.RFC3339Z)
}
return s
}
// LogValue implements slog.LogValuer.
func (bi BuildInfo) LogValue() slog.Value {
gv := slog.GroupValue(
slog.String(lga.Version, bi.Version),
slog.String(lga.Commit, bi.Commit),
slog.Time(lga.Timestamp, bi.Timestamp))
return gv
}
// Get returns BuildInfo. If buildinfo.Timestamp cannot be parsed,
// the returned BuildInfo.Timestamp will be the zero value.
func Get() BuildInfo {
var t time.Time
if Timestamp != "" {
got, err := timez.ParseTimestampUTC(Timestamp)
if err == nil {
t = got
}
}
return BuildInfo{
Version: Version,
Commit: Commit,
Timestamp: t,
}
}
func init() { //nolint:gochecknoinits
if strings.HasSuffix(Version, "~dev") {
Version = strings.Replace(Version, "~dev", "-dev", 1)
}
if Version != "" && !semver.IsValid(Version) {
// We want to panic here because it is a pipeline/build failure
// to have an invalid non-empty Version.
panic(fmt.Sprintf("Invalid BuildInfo.Version value: %s", Version))
}
if Timestamp != "" {
// Make sure Timestamp is normalized
t := timez.TimestampToRFC3339(Timestamp)
if t != "" {
Timestamp = t
}
}
if v, ok := os.LookupEnv(EnvOverrideVersion); ok {
if !semver.IsValid(v) {
panic(fmt.Sprintf("Invalid semver value from %s: %s", EnvOverrideVersion, v))
}
Version = v
}
}
// EnvOverrideVersion is used for testing build version, e.g. for
// config upgrades.
const EnvOverrideVersion = `SQ_BUILD_VERSION`
// IsDefaultVersion returns true if Version is empty or DefaultVersion.
func IsDefaultVersion() bool {
return Version == "" || Version == DefaultVersion
}