Move TagsGetter to oci package (#1702)

Signed-off-by: Sergio Castaño Arteaga <tegioz@icloud.com>
This commit is contained in:
Sergio C. Arteaga 2021-11-22 10:51:31 +01:00 committed by GitHub
parent f5f7fe99a2
commit a65a0b9753
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 71 additions and 77 deletions

View File

@ -52,3 +52,9 @@ type OCIPuller interface {
password string,
) (ocispec.Descriptor, []byte, error)
}
// OCITagsGetter is the interface that wraps the Tags method, used to get all
// the tags available for a given repository in a OCI registry.
type OCITagsGetter interface {
Tags(ctx context.Context, r *Repository) ([]string, error)
}

View File

@ -130,12 +130,6 @@ type HelmIndexLoader interface {
LoadIndex(r *Repository) (*helmrepo.IndexFile, string, error)
}
// OCITagsGetter is the interface that wraps the Tags method, used to get all
// the tags available for a given repository in a OCI registry.
type OCITagsGetter interface {
Tags(ctx context.Context, r *Repository) ([]string, error)
}
// OLMOCIExporter describes the methods an OLMOCIExporter implementation must
// must provide.
type OLMOCIExporter interface {

View File

@ -3,6 +3,7 @@ package oci
import (
"context"
"github.com/artifacthub/hub/internal/hub"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/mock"
)
@ -25,3 +26,15 @@ func (m *PullerMock) PullLayer(
data, _ := args.Get(1).([]byte)
return desc, data, args.Error(2)
}
// TagsGetterMock is a mock implementation of the hub.OCITagsGetter interface.
type TagsGetterMock struct {
mock.Mock
}
// Tags implements the OCITagsGetter interface.
func (m *TagsGetterMock) Tags(ctx context.Context, r *hub.Repository) ([]string, error) {
args := m.Called(ctx, r)
tags, _ := args.Get(0).([]string)
return tags, args.Error(1)
}

View File

@ -3,9 +3,15 @@ package oci
import (
"context"
"errors"
"sort"
"strings"
"github.com/Masterminds/semver"
"github.com/artifacthub/hub/internal/hub"
"github.com/containerd/containerd/remotes/docker"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/pkg/content"
ctxo "oras.land/oras-go/pkg/context"
@ -68,3 +74,42 @@ func (p *Puller) PullLayer(
}
return ocispec.Descriptor{}, nil, ErrLayerNotFound
}
// OCITagsGetter provides a mechanism to get all the version tags available for
// a given repository in a OCI registry. Tags that aren't valid semver versions
// will be filtered out.
type TagsGetter struct{}
// Tags returns a list with the tags available for the provided repository.
func (tg *TagsGetter) Tags(ctx context.Context, r *hub.Repository) ([]string, error) {
u := strings.TrimPrefix(r.URL, hub.RepositoryOCIPrefix)
ociRepo, err := name.NewRepository(u)
if err != nil {
return nil, err
}
options := []remote.Option{
remote.WithContext(ctx),
}
if r.AuthUser != "" || r.AuthPass != "" {
options = append(options, remote.WithAuth(&authn.Basic{
Username: r.AuthUser,
Password: r.AuthPass,
}))
}
tags, err := remote.List(ociRepo, options...)
if err != nil {
return nil, err
}
var tagsFiltered []string
for _, tag := range tags {
if _, err := semver.NewVersion(tag); err == nil {
tagsFiltered = append(tagsFiltered, tag)
}
}
sort.Slice(tagsFiltered, func(i, j int) bool {
vi, _ := semver.NewVersion(tagsFiltered[i])
vj, _ := semver.NewVersion(tagsFiltered[j])
return vj.LessThan(vi)
})
return tagsFiltered, nil
}

View File

@ -117,7 +117,7 @@ func NewManager(
cfg: cfg,
db: db,
il: &HelmIndexLoader{},
tg: &OCITagsGetter{},
tg: &oci.TagsGetter{},
op: &oci.Puller{},
az: az,
hc: hc,

View File

@ -1094,7 +1094,7 @@ func TestGetRemoteDigest(t *testing.T) {
t.Run("helm-oci: error getting tags", func(t *testing.T) {
t.Parallel()
tg := &OCITagsGetterMock{}
tg := &oci.TagsGetterMock{}
tg.On("Tags", ctx, helmOCI).Return(nil, tests.ErrFake)
m := NewManager(cfg, nil, nil, nil, WithOCITagsGetter(tg))
@ -1106,7 +1106,7 @@ func TestGetRemoteDigest(t *testing.T) {
t.Run("helm-oci: success", func(t *testing.T) {
t.Parallel()
tg := &OCITagsGetterMock{}
tg := &oci.TagsGetterMock{}
tg.On("Tags", ctx, helmOCI).Return([]string{"2.0.0", "1.0.0"}, nil)
m := NewManager(cfg, nil, nil, nil, WithOCITagsGetter(tg))

View File

@ -182,18 +182,6 @@ func (m *ManagerMock) UpdateDigest(ctx context.Context, repositoryID, digest str
return args.Error(0)
}
// OCITagsGetterMock is a mock implementation of the OCITagsGetter interface.
type OCITagsGetterMock struct {
mock.Mock
}
// Tags implements the OCITagsGetter interface.
func (m *OCITagsGetterMock) Tags(ctx context.Context, r *hub.Repository) ([]string, error) {
args := m.Called(ctx, r)
tags, _ := args.Get(0).([]string)
return tags, args.Error(1)
}
// OLMOCIExporterMock is a mock implementation of the OLMOCIExporter interface.
type OLMOCIExporterMock struct {
mock.Mock

View File

@ -1,52 +0,0 @@
package repo
import (
"context"
"sort"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/artifacthub/hub/internal/hub"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
)
// OCITagsGetter provides a mechanism to get all the version tags available for
// a given repository in a OCI registry. Tags that aren't valid semver versions
// will be filtered out.
type OCITagsGetter struct{}
// Tags returns a list with the tags available for the provided repository.
func (tg *OCITagsGetter) Tags(ctx context.Context, r *hub.Repository) ([]string, error) {
u := strings.TrimPrefix(r.URL, hub.RepositoryOCIPrefix)
ociRepo, err := name.NewRepository(u)
if err != nil {
return nil, err
}
options := []remote.Option{
remote.WithContext(ctx),
}
if r.AuthUser != "" || r.AuthPass != "" {
options = append(options, remote.WithAuth(&authn.Basic{
Username: r.AuthUser,
Password: r.AuthPass,
}))
}
tags, err := remote.List(ociRepo, options...)
if err != nil {
return nil, err
}
var tagsFiltered []string
for _, tag := range tags {
if _, err := semver.NewVersion(tag); err == nil {
tagsFiltered = append(tagsFiltered, tag)
}
}
sort.Slice(tagsFiltered, func(i, j int) bool {
vi, _ := semver.NewVersion(tagsFiltered[i])
vj, _ := semver.NewVersion(tagsFiltered[j])
return vj.LessThan(vi)
})
return tagsFiltered, nil
}

View File

@ -96,7 +96,7 @@ func NewTrackerSource(i *hub.TrackerSourceInput, opts ...func(s *TrackerSource))
s.il = &repo.HelmIndexLoader{}
}
if s.tg == nil {
s.tg = &repo.OCITagsGetter{}
s.tg = &oci.TagsGetter{}
}
return s
}

View File

@ -151,7 +151,7 @@ func TestTrackerSource(t *testing.T) {
},
Svc: sw.Svc,
}
tg := &repo.OCITagsGetterMock{}
tg := &oci.TagsGetterMock{}
tg.On("Tags", i.Svc.Ctx, i.Repository).Return(nil, tests.ErrFake)
// Run test and check expectations
@ -332,7 +332,7 @@ func TestTrackerSource(t *testing.T) {
},
Svc: sw.Svc,
}
tg := &repo.OCITagsGetterMock{}
tg := &oci.TagsGetterMock{}
tg.On("Tags", i.Svc.Ctx, i.Repository).Return([]string{"1.0.0"}, nil)
ref := strings.TrimPrefix(i.Repository.URL, hub.RepositoryOCIPrefix) + ":1.0.0"
sw.Op.On("PullLayer", mock.Anything, ref, ChartContentLayerMediaType, "", "").
@ -473,7 +473,7 @@ func TestTrackerSource(t *testing.T) {
},
Svc: sw.Svc,
}
tg := &repo.OCITagsGetterMock{}
tg := &oci.TagsGetterMock{}
tg.On("Tags", i.Svc.Ctx, i.Repository).Return([]string{"1.0.0"}, nil)
ref := strings.TrimPrefix(i.Repository.URL, hub.RepositoryOCIPrefix) + ":1.0.0"
data, _ := os.ReadFile("testdata/pkg1-1.0.0.tgz")