package main
import (
"regexp"
"runtime/debug"
"strings"
)
// defaultVersion is the version of this source tree, and what a build that
// carries no better answer reports: a go build or go run from a checkout. It
// is bumped with each release, in the same commit the tag is cut from, so a
// build from that commit says the same thing however it was made.
const defaultVersion = "v0.6.1"
func init() {
version = resolveVersion(version, debug.ReadBuildInfo)
}
// resolveVersion picks the version to report, trying the sources from the
// most to the least deliberate:
//
// 1. stamped, which is whatever -ldflags "-X main.version=..." put there.
// goreleaser does this for every release archive, from the tag being
// built, so it is the one answer that cannot be stale.
// 2. The main module's version in the build info. go install
// github.com/johannSo/codey/cmd/codey@v0.7.0 records v0.7.0 there, and
// no flag is involved, so without this such an install would report
// whatever defaultVersion said at that commit — right only if someone
// remembered to bump it.
// 3. defaultVersion.
//
// The build info is passed in rather than read here so the order can be
// tested; a test binary's own build info says nothing useful.
func resolveVersion(stamped string, buildInfo func() (*debug.BuildInfo, bool)) string {
if v := strings.TrimSpace(stamped); v != "" {
// goreleaser's {{.Version}} is the tag without its v. The v goes
// back on so a release reads the way every other build does:
// "codey v0.7.0", not sometimes "codey 0.7.0".
if v[0] >= '0' && v[0] <= '9' {
v = "v" + v
}
return v
}
if info, ok := buildInfo(); ok && info != nil && isRelease(info.Main.Version) {
return info.Main.Version
}
return defaultVersion
}
// pseudoVersion matches the tail Go gives a module version that is not a tag:
// a fourteen-digit UTC timestamp and a twelve-character commit hash, as in
// v0.0.0-20261002101500-219352e3b1c4.
var pseudoVersion = regexp.MustCompile(`[-.]\d{14}-[0-9a-f]{12}$`)
// isRelease reports whether a build-info module version names a tag. Since Go
// 1.24 a plain go build in a git checkout stamps one too, derived from the
// nearest tag and the commit, and with no tag in reach that is
// v0.0.0-<time>-<hash>: true, but a worse answer than defaultVersion for
// someone building the tree they have checked out. So only a tag counts.
// "(devel)" is what a build with no version control information gets, and a
// "+dirty" suffix means the tree had uncommitted changes, which is not the
// tagged source either.
func isRelease(v string) bool {
if v == "" || v == "(devel)" || strings.Contains(v, "+") {
return false
}
return !pseudoVersion.MatchString(v)
}