@@ -6,10 +6,11 @@ package resource
66import (
77 "context"
88 "fmt"
9-
109 "github.com/Masterminds/semver/v3"
1110 "github.com/pkg/errors"
1211 "oras.land/oras-go/v2/registry"
12+ "oras.land/oras-go/v2/registry/remote"
13+ "slices"
1314)
1415
1516type (
@@ -31,30 +32,73 @@ func Check(ctx context.Context, request CheckRequest) (*CheckResponse, error) {
3132 return nil , errors .Wrap (err , "failed to create repository client" )
3233 }
3334
34- // Fetching repository tags
35+ // Fetch repository tags
3536 allTags , err := registry .Tags (ctx , repo )
3637 if err != nil {
3738 return nil , errors .Wrap (err , "failed to fetch tags" )
3839 }
3940
40- // Sorting tags.
41- var latestTag * semver.Version
42- for _ , tag := range allTags {
43- v , err := semver .NewVersion (tag )
41+ // Sort tags by semver
42+ sortedSemvers , err := sortBySemver (allTags )
43+ if err != nil {
44+ return nil , err
45+ }
46+
47+ // chop the list at the index of the requested version, if there was one
48+ if request .Version != nil {
49+ requestedVersion , err := semver .NewVersion (request .Version .Tag )
4450 if err != nil {
45- return nil , errors .Wrap (err , fmt .Sprintf ("failed to parse semver in tag %q" , tag ))
51+ return nil , errors .Wrap (err , fmt .Sprintf ("failed to parse semver in requested version %q" , request .Version .Tag ))
52+ }
53+ for i , version := range sortedSemvers {
54+ if version .GreaterThanEqual (requestedVersion ) {
55+ sortedSemvers = sortedSemvers [i :]
56+ break
57+ }
4658 }
47- if latestTag == nil || v .GreaterThan (latestTag ) {
48- latestTag = v
59+ } else {
60+ // if no version was requested, return the latest 10 versions
61+ startIndex := len (sortedSemvers ) - 10
62+ if startIndex < 0 {
63+ startIndex = 0
4964 }
65+ sortedSemvers = sortedSemvers [startIndex :]
5066 }
51- if latestTag == nil {
67+
68+ if len (sortedSemvers ) == 0 {
5269 return nil , fmt .Errorf ("no latest tag found for source %s" , request .Source .String ())
5370 }
5471
55- digest , err := getDigestForTag (ctx , repo , latestTag . Original () )
72+ resolvedVersions , err := resolveImageDigests (ctx , sortedSemvers , repo )
5673 if err != nil {
57- return nil , errors .Wrap (err , fmt .Sprintf ("failed to fetch digest for latest tag %q (parsed as %s)" , latestTag .Original (), latestTag .String ()))
74+ return nil , err
75+ }
76+ return & resolvedVersions , nil
77+ }
78+
79+ func sortBySemver (allTags []string ) ([]semver.Version , error ) {
80+ allVersions := make ([]semver.Version , len (allTags ))
81+ for i , tag := range allTags {
82+ v , err := semver .NewVersion (tag )
83+ if err != nil {
84+ return nil , errors .Wrap (err , fmt .Sprintf ("failed to parse semver in tag %q" , tag ))
85+ }
86+ allVersions [i ] = * v
87+ }
88+ slices .SortStableFunc (allVersions , func (i , j semver.Version ) int {
89+ return i .Compare (& j )
90+ })
91+ return allVersions , nil
92+ }
93+
94+ func resolveImageDigests (ctx context.Context , sortedSemvers []semver.Version , repo * remote.Repository ) (CheckResponse , error ) {
95+ resolvedVersions := make (CheckResponse , len (sortedSemvers ))
96+ for i , version := range sortedSemvers {
97+ digest , err := getDigestForTag (ctx , repo , version .Original ())
98+ if err != nil {
99+ return nil , errors .Wrap (err , fmt .Sprintf ("failed to fetch digest for latest tag %q (parsed as %s)" , version .Original (), version .String ()))
100+ }
101+ resolvedVersions [i ] = Version {Tag : version .Original (), Digest : digest }
58102 }
59- return & CheckResponse {{ Tag : latestTag . Original (), Digest : digest }} , nil
103+ return resolvedVersions , nil
60104}
0 commit comments