mirror of
https://github.com/crazy-max/diun.git
synced 2025-12-21 13:23:09 +01:00
Tags sorting support (#645)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
@@ -126,6 +126,7 @@ func TestParseImage(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
tt := tt
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
img, err := registry.ParseImage(tt.parseOpts)
|
||||
if err != nil {
|
||||
@@ -239,6 +240,7 @@ func TestHubLink(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
tt := tt
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
img, err := registry.ParseImage(tt.parseOpts)
|
||||
if err != nil {
|
||||
|
||||
@@ -52,6 +52,7 @@ func TestParseReference(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
tt := tt
|
||||
t.Run(tt.input, func(t *testing.T) {
|
||||
ref, err := registry.ParseReference(tt.input)
|
||||
if tt.wantErr {
|
||||
|
||||
@@ -18,6 +18,7 @@ type Tags struct {
|
||||
type TagsOptions struct {
|
||||
Image Image
|
||||
Max int
|
||||
Sort SortTag
|
||||
Include []string
|
||||
Exclude []string
|
||||
}
|
||||
@@ -43,6 +44,9 @@ func (c *Client) Tags(opts TagsOptions) (*Tags, error) {
|
||||
Total: len(tags),
|
||||
}
|
||||
|
||||
// Sort tags
|
||||
tags = SortTags(tags, opts.Sort)
|
||||
|
||||
// Filter
|
||||
for _, tag := range tags {
|
||||
if !utl.IsIncluded(tag, opts.Include) {
|
||||
@@ -55,12 +59,6 @@ func (c *Client) Tags(opts TagsOptions) (*Tags, error) {
|
||||
res.List = append(res.List, tag)
|
||||
}
|
||||
|
||||
// Reverse order (latest tags first)
|
||||
for i := len(res.List)/2 - 1; i >= 0; i-- {
|
||||
opp := len(res.List) - 1 - i
|
||||
res.List[i], res.List[opp] = res.List[opp], res.List[i]
|
||||
}
|
||||
|
||||
if opts.Max > 0 && len(res.List) >= opts.Max {
|
||||
res.List = res.List[:opts.Max]
|
||||
}
|
||||
|
||||
79
pkg/registry/tags_sort.go
Normal file
79
pkg/registry/tags_sort.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
// SortTags sorts tags list
|
||||
func SortTags(tags []string, sortTag SortTag) []string {
|
||||
switch sortTag {
|
||||
case SortTagReverse:
|
||||
for i := len(tags)/2 - 1; i >= 0; i-- {
|
||||
opp := len(tags) - 1 - i
|
||||
tags[i], tags[opp] = tags[opp], tags[i]
|
||||
}
|
||||
return tags
|
||||
case SortTagLexicographical:
|
||||
sort.Strings(tags)
|
||||
return tags
|
||||
case SortTagSemver:
|
||||
semverIsh := func(s string) string {
|
||||
if semver.IsValid(s) {
|
||||
return s
|
||||
}
|
||||
if vt := fmt.Sprintf("v%s", s); semver.IsValid(vt) {
|
||||
return vt
|
||||
}
|
||||
return ""
|
||||
}
|
||||
sort.Slice(tags, func(i, j int) bool {
|
||||
if c := semver.Compare(semverIsh(tags[i]), semverIsh(tags[j])); c > 0 {
|
||||
return true
|
||||
} else if c < 0 {
|
||||
return false
|
||||
}
|
||||
return strings.Count(tags[i], ".") > strings.Count(tags[j], ".")
|
||||
})
|
||||
return tags
|
||||
default:
|
||||
return tags
|
||||
}
|
||||
}
|
||||
|
||||
// SortTag holds sort tag type
|
||||
type SortTag string
|
||||
|
||||
// SortTag constants
|
||||
const (
|
||||
SortTagDefault = SortTag("default")
|
||||
SortTagReverse = SortTag("reverse")
|
||||
SortTagLexicographical = SortTag("lexicographical")
|
||||
SortTagSemver = SortTag("semver")
|
||||
)
|
||||
|
||||
// SortTagTypes is the list of available sort tag types
|
||||
var SortTagTypes = []SortTag{
|
||||
SortTagDefault,
|
||||
SortTagReverse,
|
||||
SortTagLexicographical,
|
||||
SortTagSemver,
|
||||
}
|
||||
|
||||
// Valid checks sort tag type is valid
|
||||
func (st *SortTag) Valid() bool {
|
||||
return st.OneOf(SortTagTypes)
|
||||
}
|
||||
|
||||
// OneOf checks if sort type is one of the values in the list
|
||||
func (st *SortTag) OneOf(stl []SortTag) bool {
|
||||
for _, n := range stl {
|
||||
if n == *st {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -27,3 +27,207 @@ func TestTags(t *testing.T) {
|
||||
assert.True(t, tags.Total > 0)
|
||||
assert.True(t, len(tags.List) > 0)
|
||||
}
|
||||
|
||||
func TestTagsSort(t *testing.T) {
|
||||
repotags := []string{
|
||||
"0.1.0",
|
||||
"0.4.0",
|
||||
"3.0.0-beta.1",
|
||||
"3.0.0-beta.3",
|
||||
"3.0.0-beta.4",
|
||||
"4",
|
||||
"4.0.0",
|
||||
"4.0.0-beta.1",
|
||||
"4.1.0",
|
||||
"4.1.1",
|
||||
"4.10.0",
|
||||
"4.11.0",
|
||||
"4.12.0",
|
||||
"4.13.0",
|
||||
"4.14.0",
|
||||
"4.19.0",
|
||||
"4.2.0",
|
||||
"4.20",
|
||||
"4.20.0",
|
||||
"4.20.1",
|
||||
"4.21",
|
||||
"4.21.0",
|
||||
"4.3.0",
|
||||
"4.3.1",
|
||||
"4.4.0",
|
||||
"4.6.1",
|
||||
"4.7.0",
|
||||
"4.8.0",
|
||||
"4.8.1",
|
||||
"4.9.0",
|
||||
"edge",
|
||||
"latest",
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
sortTag registry.SortTag
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "sort default",
|
||||
sortTag: registry.SortTagDefault,
|
||||
expected: []string{
|
||||
"0.1.0",
|
||||
"0.4.0",
|
||||
"3.0.0-beta.1",
|
||||
"3.0.0-beta.3",
|
||||
"3.0.0-beta.4",
|
||||
"4",
|
||||
"4.0.0",
|
||||
"4.0.0-beta.1",
|
||||
"4.1.0",
|
||||
"4.1.1",
|
||||
"4.10.0",
|
||||
"4.11.0",
|
||||
"4.12.0",
|
||||
"4.13.0",
|
||||
"4.14.0",
|
||||
"4.19.0",
|
||||
"4.2.0",
|
||||
"4.20",
|
||||
"4.20.0",
|
||||
"4.20.1",
|
||||
"4.21",
|
||||
"4.21.0",
|
||||
"4.3.0",
|
||||
"4.3.1",
|
||||
"4.4.0",
|
||||
"4.6.1",
|
||||
"4.7.0",
|
||||
"4.8.0",
|
||||
"4.8.1",
|
||||
"4.9.0",
|
||||
"edge",
|
||||
"latest",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sort lexicographical",
|
||||
sortTag: registry.SortTagLexicographical,
|
||||
expected: []string{
|
||||
"0.1.0",
|
||||
"0.4.0",
|
||||
"3.0.0-beta.1",
|
||||
"3.0.0-beta.3",
|
||||
"3.0.0-beta.4",
|
||||
"4",
|
||||
"4.0.0",
|
||||
"4.0.0-beta.1",
|
||||
"4.1.0",
|
||||
"4.1.1",
|
||||
"4.10.0",
|
||||
"4.11.0",
|
||||
"4.12.0",
|
||||
"4.13.0",
|
||||
"4.14.0",
|
||||
"4.19.0",
|
||||
"4.2.0",
|
||||
"4.20",
|
||||
"4.20.0",
|
||||
"4.20.1",
|
||||
"4.21",
|
||||
"4.21.0",
|
||||
"4.3.0",
|
||||
"4.3.1",
|
||||
"4.4.0",
|
||||
"4.6.1",
|
||||
"4.7.0",
|
||||
"4.8.0",
|
||||
"4.8.1",
|
||||
"4.9.0",
|
||||
"edge",
|
||||
"latest",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sort reverse",
|
||||
sortTag: registry.SortTagReverse,
|
||||
expected: []string{
|
||||
"latest",
|
||||
"edge",
|
||||
"4.9.0",
|
||||
"4.8.1",
|
||||
"4.8.0",
|
||||
"4.7.0",
|
||||
"4.6.1",
|
||||
"4.4.0",
|
||||
"4.3.1",
|
||||
"4.3.0",
|
||||
"4.21.0",
|
||||
"4.21",
|
||||
"4.20.1",
|
||||
"4.20.0",
|
||||
"4.20",
|
||||
"4.2.0",
|
||||
"4.19.0",
|
||||
"4.14.0",
|
||||
"4.13.0",
|
||||
"4.12.0",
|
||||
"4.11.0",
|
||||
"4.10.0",
|
||||
"4.1.1",
|
||||
"4.1.0",
|
||||
"4.0.0-beta.1",
|
||||
"4.0.0",
|
||||
"4",
|
||||
"3.0.0-beta.4",
|
||||
"3.0.0-beta.3",
|
||||
"3.0.0-beta.1",
|
||||
"0.4.0",
|
||||
"0.1.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sort semver",
|
||||
sortTag: registry.SortTagSemver,
|
||||
expected: []string{
|
||||
"4.21.0",
|
||||
"4.21",
|
||||
"4.20.1",
|
||||
"4.20.0",
|
||||
"4.20",
|
||||
"4.19.0",
|
||||
"4.14.0",
|
||||
"4.13.0",
|
||||
"4.12.0",
|
||||
"4.11.0",
|
||||
"4.10.0",
|
||||
"4.9.0",
|
||||
"4.8.1",
|
||||
"4.8.0",
|
||||
"4.7.0",
|
||||
"4.6.1",
|
||||
"4.4.0",
|
||||
"4.3.1",
|
||||
"4.3.0",
|
||||
"4.2.0",
|
||||
"4.1.1",
|
||||
"4.1.0",
|
||||
"4.0.0",
|
||||
"4",
|
||||
"4.0.0-beta.1",
|
||||
"3.0.0-beta.4",
|
||||
"3.0.0-beta.3",
|
||||
"3.0.0-beta.1",
|
||||
"0.4.0",
|
||||
"0.1.0",
|
||||
"edge",
|
||||
"latest",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tags := registry.SortTags(repotags, tt.sortTag)
|
||||
assert.Equal(t, tt.expected, tags)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user