Skip to content

Commit 798c439

Browse files
committed
semver compare
1 parent 037e4c9 commit 798c439

2 files changed

Lines changed: 62 additions & 16 deletions

File tree

internal/gitsemver/gitter.go

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,49 @@ func (dg DefaultGitter) CheckGitRepo(dir string) (repo string, err error) {
159159
// with or without a leading "v".
160160
var reMatchSemver = regexp.MustCompile(`^v?[0-9]+(?:\.[0-9]+)?(?:\.[0-9]+)?$`)
161161

162-
func semverKey(tag string) [3]int {
163-
var key [3]int
162+
func normalizeNumericString(s string) string {
163+
s = strings.TrimLeft(s, "0")
164+
if s == "" {
165+
return "0"
166+
}
167+
return s
168+
}
169+
170+
func compareNumericStrings(a, b string) int {
171+
a = normalizeNumericString(a)
172+
b = normalizeNumericString(b)
173+
if len(a) != len(b) {
174+
if len(a) > len(b) {
175+
return 1
176+
}
177+
return -1
178+
}
179+
if a == b {
180+
return 0
181+
}
182+
if a > b {
183+
return 1
184+
}
185+
return -1
186+
}
187+
188+
func semverPart(tag string, index int) string {
164189
core := strings.TrimPrefix(tag, "v")
165190
parts := strings.Split(core, ".")
166-
for i := 0; i < len(parts) && i < len(key); i++ {
167-
n, err := strconv.Atoi(parts[i])
168-
if err != nil {
169-
break
191+
if index >= 0 && index < len(parts) {
192+
return parts[index]
193+
}
194+
return "0"
195+
}
196+
197+
func semverGreater(leftTag, rightTag string) bool {
198+
for idx := 0; idx < 3; idx++ {
199+
cmp := compareNumericStrings(semverPart(leftTag, idx), semverPart(rightTag, idx))
200+
if cmp != 0 {
201+
return cmp > 0
170202
}
171-
key[i] = n
172203
}
173-
return key
204+
return false
174205
}
175206

176207
// GetTags returns all tags, sorted by version descending.
@@ -186,14 +217,7 @@ func (dg DefaultGitter) GetTags(repo string) (tags []string, err error) {
186217
// Git's multi-pattern listing can interleave v-prefixed and non-prefixed
187218
// tags in a way that is not globally version-sorted. Normalize here.
188219
sort.SliceStable(tags, func(i, j int) bool {
189-
left := semverKey(tags[i])
190-
right := semverKey(tags[j])
191-
for idx := range left {
192-
if left[idx] != right[idx] {
193-
return left[idx] > right[idx]
194-
}
195-
}
196-
return false
220+
return semverGreater(tags[i], tags[j])
197221
})
198222
}
199223
return

internal/gitsemver/gitter_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,28 @@ func Test_DefaultGitter_GetTags_SortsMixedPrefixSemverDescending(t *testing.T) {
225225
}
226226
}
227227

228+
func Test_DefaultGitter_GetTags_SortsHugeNumericComponents(t *testing.T) {
229+
repo := t.TempDir()
230+
runGit(t, repo, nil, "init", "-q")
231+
runGit(t, repo, nil, "config", "user.email", "test@example.com")
232+
runGit(t, repo, nil, "config", "user.name", "Test")
233+
commitAt(t, repo, "a.txt", "a\n", "c1", "2020-01-01T00:00:00Z")
234+
runGit(t, repo, nil, "tag", "v999999999999999999999.0.0")
235+
runGit(t, repo, nil, "tag", "v2.0.0")
236+
237+
dg, err := gitsemver.NewDefaultGitter("git", nil)
238+
if err != nil {
239+
t.Fatal(err)
240+
}
241+
tags, err := dg.GetTags(repo)
242+
if err != nil {
243+
t.Fatal(err)
244+
}
245+
if slices.Compare(tags, []string{"v999999999999999999999.0.0", "v2.0.0"}) != 0 {
246+
t.Fatalf("unexpected tags: %v", tags)
247+
}
248+
}
249+
228250
func Test_DefaultGitter_GetCurrentTreeHash(t *testing.T) {
229251
dg, err := gitsemver.NewDefaultGitter("git", nil)
230252
if err != nil {

0 commit comments

Comments
 (0)