| 1 | package git |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | |
| 6 | "golang.org/x/mod/module" |
| 7 | "golang.org/x/mod/semver" |
| 8 | ) |
| 9 | |
| 10 | // ResolvedVersion holds the canonical version string and the git revision to use. |
| 11 | type ResolvedVersion struct { |
| 12 | Version string // canonical semver (tag or pseudo-version) |
| 13 | GitRev string // git revision to pass to git commands (tag name or full hash) |
| 14 | } |
| 15 | |
| 16 | // ResolveVersion determines the canonical version and git revision for a version query. |
| 17 | // It handles: |
| 18 | // - Tagged versions: v1.0.0 -> use as-is |
| 19 | // - Pseudo-versions: v0.0.0-20240101120000-abcdef123456 -> extract commit hash |
| 20 | // - Raw commits/branches: abcdef123456 or main -> resolve to pseudo-version |
| 21 | func ResolveVersion(repoPath, query string) (*ResolvedVersion, error) { |
| 22 | // Case 1: tagged semver version (not a pseudo-version). |
| 23 | if semver.IsValid(query) && !module.IsPseudoVersion(query) { |
| 24 | return &ResolvedVersion{Version: query, GitRev: query}, nil |
| 25 | } |
| 26 | |
| 27 | // Case 2: pseudo-version — extract the commit hash. |
| 28 | if module.IsPseudoVersion(query) { |
| 29 | rev, err := module.PseudoVersionRev(query) |
| 30 | if err != nil { |
| 31 | return nil, err |
| 32 | } |
| 33 | |
| 34 | return &ResolvedVersion{Version: query, GitRev: rev}, nil |
| 35 | } |
| 36 | |
| 37 | // Case 3: raw ref (commit hash, branch name, etc.) — build a pseudo-version. |
| 38 | hash, commitTime, err := CommitInfo(repoPath, query) |
| 39 | if err != nil { |
| 40 | return nil, fmt.Errorf("resolve ref %q: %w", query, err) |
| 41 | } |
| 42 | |
| 43 | shortHash := hash[:12] |
| 44 | older := LatestTag(repoPath, hash) |
| 45 | |
| 46 | pv := module.PseudoVersion("v0", older, commitTime, shortHash) |
| 47 | |
| 48 | return &ResolvedVersion{Version: pv, GitRev: hash}, nil |
| 49 | } |
| 50 | |