Skip to content

Commit c090764

Browse files
committed
use golang.org/x/mod/semver
1 parent 3925240 commit c090764

6 files changed

Lines changed: 47 additions & 59 deletions

File tree

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/linkdata/gitsemver
22

3-
go 1.23
3+
go 1.24.0
4+
5+
require golang.org/x/mod v0.33.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
2+
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=

internal/gitsemver/gitsemver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func (vs *GitSemVer) examineTags(repo string) (err error) {
146146
// that is true if the tree hashes match and there are no uncommitted changes.
147147
func (vs *GitSemVer) GetTag(repo string) (tag string, match bool, err error) {
148148
if ciTag := strings.TrimSpace(vs.Env.Getenv("CI_COMMIT_TAG")); ciTag != "" {
149-
if reMatchSemver.MatchString(ciTag) {
149+
if isSemverTag(ciTag) {
150150
return ciTag, true, nil
151151
}
152152
}

internal/gitsemver/gitter.go

Lines changed: 3 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"os"
99
"os/exec"
1010
"path/filepath"
11-
"regexp"
1211
"runtime"
1312
"sort"
1413
"strconv"
@@ -160,69 +159,20 @@ func (dg DefaultGitter) CheckGitRepo(dir string) (repo string, err error) {
160159
return
161160
}
162161

163-
// Intentionally accepts partial numeric tags (v1, v1.2, v1.2.3),
164-
// with or without a leading "v".
165-
var reMatchSemver = regexp.MustCompile(`^v?[0-9]+(?:\.[0-9]+)?(?:\.[0-9]+)?$`)
166-
167-
func normalizeNumericString(s string) string {
168-
s = strings.TrimLeft(s, "0")
169-
if s == "" {
170-
return "0"
171-
}
172-
return s
173-
}
174-
175-
func compareNumericStrings(a, b string) int {
176-
a = normalizeNumericString(a)
177-
b = normalizeNumericString(b)
178-
if len(a) != len(b) {
179-
if len(a) > len(b) {
180-
return 1
181-
}
182-
return -1
183-
}
184-
if a == b {
185-
return 0
186-
}
187-
if a > b {
188-
return 1
189-
}
190-
return -1
191-
}
192-
193-
func semverPart(tag string, index int) string {
194-
core := strings.TrimPrefix(tag, "v")
195-
parts := strings.Split(core, ".")
196-
if index >= 0 && index < len(parts) {
197-
return parts[index]
198-
}
199-
return "0"
200-
}
201-
202-
func semverGreater(leftTag, rightTag string) bool {
203-
for idx := 0; idx < 3; idx++ {
204-
cmp := compareNumericStrings(semverPart(leftTag, idx), semverPart(rightTag, idx))
205-
if cmp != 0 {
206-
return cmp > 0
207-
}
208-
}
209-
return false
210-
}
211-
212162
// GetTags returns all tags, sorted by version descending.
213163
// The latest tag is the first in the list.
214164
func (dg DefaultGitter) GetTags(repo string) (tags []string, err error) {
215165
var b []byte
216166
if b, err = dg.Exec("-C", repo, "tag", "--sort=-v:refname", "--list", "v[0-9]*", "[0-9]*"); len(b) > 0 /* #nosec G204 */ {
217167
for _, tag := range strings.Split(string(b), "\n") {
218-
if tag = strings.TrimSpace(tag); tag != "" && reMatchSemver.MatchString(tag) {
168+
if tag = strings.TrimSpace(tag); tag != "" && isSemverTag(tag) {
219169
tags = append(tags, tag)
220170
}
221171
}
222172
// Git's multi-pattern listing can interleave v-prefixed and non-prefixed
223173
// tags in a way that is not globally version-sorted. Normalize here.
224174
sort.SliceStable(tags, func(i, j int) bool {
225-
return semverGreater(tags[i], tags[j])
175+
return semverTagGreater(tags[i], tags[j])
226176
})
227177
}
228178
return
@@ -310,7 +260,7 @@ func (dg DefaultGitter) GetClosestTag(repo, commit string) (tag string, err erro
310260
var b []byte
311261
if b, err = dg.Exec(args...); err == nil {
312262
candidate := strings.TrimSpace(string(b))
313-
if candidate == "" || reMatchSemver.MatchString(candidate) {
263+
if candidate == "" || isSemverTag(candidate) {
314264
tag = candidate
315265
return
316266
}

internal/gitsemver/semver.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package gitsemver
2+
3+
import (
4+
"strings"
5+
6+
xmodsemver "golang.org/x/mod/semver"
7+
)
8+
9+
// canonicalSemverTag converts relaxed git tag forms like "1", "1.2", "v1.2.3"
10+
// into strict canonical semver for validation/comparison.
11+
func canonicalSemverTag(tag string) (canonical string, ok bool) {
12+
if tag = strings.TrimSpace(tag); tag != "" {
13+
if !strings.HasPrefix(tag, "v") {
14+
tag = "v" + tag
15+
}
16+
// Git tags are intentionally limited to numeric MAJOR[.MINOR][.PATCH] forms.
17+
if xmodsemver.Prerelease(tag) == "" && xmodsemver.Build(tag) == "" {
18+
canonical = xmodsemver.Canonical(tag)
19+
}
20+
}
21+
ok = canonical != ""
22+
return
23+
}
24+
25+
func isSemverTag(tag string) bool {
26+
_, ok := canonicalSemverTag(tag)
27+
return ok
28+
}
29+
30+
func semverTagGreater(leftTag, rightTag string) bool {
31+
leftCanonical, _ := canonicalSemverTag(leftTag)
32+
rightCanonical, _ := canonicalSemverTag(rightTag)
33+
return xmodsemver.Compare(leftCanonical, rightCanonical) > 0
34+
}

internal/gitsemver/versioninfo.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ func (vi *VersionInfo) GoPackage(repo, pkgName string) (retv string, err error)
8787

8888
func (vi *VersionInfo) HasTag(tag string) bool {
8989
tagCore := strings.TrimPrefix(tag, "v")
90-
tagIsSemver := reMatchSemver.MatchString(tag)
90+
tagIsSemver := isSemverTag(tag)
9191
for _, gt := range vi.Tags {
9292
if gt.Tag == tag {
9393
return true
9494
}
9595
// Treat v-prefixed and non-prefixed semver tags as equivalent.
96-
if tagIsSemver && reMatchSemver.MatchString(gt.Tag) && strings.TrimPrefix(gt.Tag, "v") == tagCore {
96+
if tagIsSemver && isSemverTag(gt.Tag) && strings.TrimPrefix(gt.Tag, "v") == tagCore {
9797
return true
9898
}
9999
}
@@ -105,11 +105,11 @@ func (vi *VersionInfo) IncPatch() string {
105105
baseTag := vi.Tag
106106
// Ignore prerelease/build suffixes when incrementing the patch level.
107107
if idx := strings.IndexAny(baseTag, "-+"); idx > -1 {
108-
if core := baseTag[:idx]; reMatchSemver.MatchString(core) {
108+
if core := baseTag[:idx]; isSemverTag(core) {
109109
baseTag = core
110110
}
111111
}
112-
if !reMatchSemver.MatchString(baseTag) {
112+
if !isSemverTag(baseTag) {
113113
vi.SameTree = true
114114
return vi.Tag
115115
}

0 commit comments

Comments
 (0)