Files
b2b/app/utils/version/version.go
2026-03-10 09:02:57 +01:00

137 lines
2.8 KiB
Go

package version
import (
"fmt"
"os"
"strings"
"time"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
)
// Version info populated at build time
var (
Version string // Git tag or commit hash
Commit string // Short commit hash
BuildDate string // Build timestamp
)
// Info returns version information
type Info struct {
Version string `json:"version"`
Commit string `json:"commit"`
BuildDate string `json:"build_date"`
}
// GetInfo returns version information
func GetInfo() Info {
v := Info{
Version: Version,
Commit: Commit,
BuildDate: BuildDate,
}
// If not set during build, try to get from git
if v.Version == "" || v.Version == "unknown" || v.Version == "(devel)" {
if gitVersion, gitCommit := getGitInfo(); gitVersion != "" {
v.Version = gitVersion
v.Commit = gitCommit
}
}
// If build date not set, use current time
if v.BuildDate == "" {
v.BuildDate = time.Now().Format(time.RFC3339)
}
return v
}
// getGitInfo returns the latest tag or short commit hash and the commit hash
func getGitInfo() (string, string) {
// Get the current working directory
dir, err := os.Getwd()
if err != nil {
return "", ""
}
// Open the git repository
repo, err := git.PlainOpen(dir)
if err != nil {
return "", ""
}
// Get the HEAD reference
head, err := repo.Head()
if err != nil {
return "", ""
}
commitHash := head.Hash().String()[:7]
// Get all tags
tagIter, err := repo.Tags()
if err != nil {
return commitHash, commitHash
}
// Get the commit for HEAD
commit, err := repo.CommitObject(head.Hash())
if err != nil {
return commitHash, commitHash
}
// Build ancestry map
ancestry := make(map[string]bool)
c := commit
for c != nil {
ancestry[c.Hash.String()] = true
c, _ = c.Parent(0)
}
// Find the most recent tag that's an ancestor of HEAD
var latestTag string
err = tagIter.ForEach(func(ref *plumbing.Reference) error {
// Get the target commit
targetHash := ref.Hash()
// Get the target commit
targetCommit, err := repo.CommitObject(targetHash)
if err != nil {
return nil
}
// Check if this tag is an ancestor of HEAD
checkCommit := targetCommit
for checkCommit != nil {
if ancestry[checkCommit.Hash.String()] {
// Extract tag name (remove refs/tags/ prefix)
tagName := strings.TrimPrefix(ref.Name().String(), "refs/tags/")
if latestTag == "" || tagName > latestTag {
latestTag = tagName
}
return nil
}
checkCommit, _ = checkCommit.Parent(0)
}
return nil
})
if err != nil {
return commitHash, commitHash
}
if latestTag != "" {
return latestTag, commitHash
}
return commitHash, commitHash
}
// String returns a formatted version string
func String() string {
info := GetInfo()
return fmt.Sprintf("Version: %s\nCommit: %s\nBuild Date: %s\n", info.Version, info.Commit, info.BuildDate)
}