Tags sorting support (#645)

Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2022-07-17 13:47:37 +02:00
committed by GitHub
parent 8fba9b158e
commit 857e462090
21 changed files with 524 additions and 95 deletions

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
View 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
}

View File

@@ -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)
})
}
}