From 3c076c613bcb0d6c5fab2d4e7e2f2fcc3cbf025e Mon Sep 17 00:00:00 2001 From: iam-karan-suresh Date: Thu, 23 Jul 2026 03:59:53 +0530 Subject: [PATCH] oci: refactor the oci from crane to remote Signed-off-by: iam-karan-suresh --- oci/client.go | 52 +++++++++++++++++++++++++++--------------- oci/delete.go | 6 ++--- oci/delete_test.go | 11 ++++++--- oci/diff.go | 11 ++++++--- oci/diff_test.go | 1 - oci/list.go | 22 ++++++++++-------- oci/list_test.go | 12 ++++++---- oci/login.go | 4 ++-- oci/login_test.go | 9 +++++--- oci/pull.go | 9 ++++++-- oci/pull_test.go | 7 ++++-- oci/push.go | 4 ++-- oci/push_pull_test.go | 37 ++++++++++++++++++++++++------ oci/retry_transport.go | 7 +++--- oci/tag.go | 10 +++++--- oci/tag_test.go | 11 ++++++--- 16 files changed, 143 insertions(+), 70 deletions(-) diff --git a/oci/client.go b/oci/client.go index 0a9625132..3701c4171 100644 --- a/oci/client.go +++ b/oci/client.go @@ -18,20 +18,21 @@ package oci import ( "context" + "net/http" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" ) // Client holds the options for accessing remote OCI registries. type Client struct { - options []crane.Option + options []remote.Option } -// NewClient returns an OCI client configured with the given crane options. -func NewClient(opts []crane.Option) *Client { - options := []crane.Option{ - crane.WithUserAgent(UserAgent), +// NewClient returns an OCI client configured with the given remote options. +func NewClient(opts []remote.Option) *Client { + options := []remote.Option{ + remote.WithUserAgent(UserAgent), } options = append(options, opts...) @@ -39,26 +40,39 @@ func NewClient(opts []crane.Option) *Client { } // DefaultOptions returns an empty list of client options. -func DefaultOptions() []crane.Option { - return []crane.Option{} +func DefaultOptions() []remote.Option { + return []remote.Option{} } -// GetOptions returns the list of crane.Option used by this Client. -func (c *Client) GetOptions() []crane.Option { +// GetOptions returns the list of remote.Option used by this Client. +func (c *Client) GetOptions() []remote.Option { return c.options } -// optionsWithContext returns the crane options for the given context. -func (c *Client) optionsWithContext(ctx context.Context) []crane.Option { - options := []crane.Option{ - crane.WithContext(ctx), +// optionsWithContext returns the remote options for the given context. +func (c *Client) optionsWithContext(ctx context.Context) []remote.Option { + options := []remote.Option{ + remote.WithContext(ctx), } return append(options, c.options...) } -// WithRetryBackOff returns a function for setting the given backoff on crane.Option. -func WithRetryBackOff(backoff remote.Backoff) crane.Option { - return func(options *crane.Options) { - options.Remote = append(options.Remote, remote.WithRetryBackoff(backoff)) - } +// WithRetryBackOff returns a function for setting the given backoff on +// remote.Option. +func WithRetryBackOff(backoff remote.Backoff) remote.Option { + return remote.WithRetryBackoff(backoff) +} + +// WithTransport returns a remote.Option that sets the HTTP transport. +func WithTransport(t http.RoundTripper) remote.Option { + return remote.WithTransport(t) +} + +// defaultRetryTransport wraps an http.RoundTripper with retry logic +// suitable for use with the remote package. +func defaultRetryTransport(inner http.RoundTripper) http.RoundTripper { + return transport.NewRetry(inner, + transport.WithRetryPredicate(defaultRetryPredicate), + transport.WithRetryStatusCodes(retryableStatusCodes...), + ) } diff --git a/oci/delete.go b/oci/delete.go index 60370b660..bc4ef6973 100644 --- a/oci/delete.go +++ b/oci/delete.go @@ -20,17 +20,17 @@ import ( "context" "fmt" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" ) // Delete deletes a particular image from an OCI repository // If the url has no tag, the latest image is deleted func (c *Client) Delete(ctx context.Context, url string) error { - _, err := name.ParseReference(url) + ref, err := name.ParseReference(url) if err != nil { return fmt.Errorf("invalid URL: %w", err) } - return crane.Delete(url, c.optionsWithContext(ctx)...) + return remote.Delete(ref, c.optionsWithContext(ctx)...) } diff --git a/oci/delete_test.go b/oci/delete_test.go index e1c140517..1a7ad342a 100644 --- a/oci/delete_test.go +++ b/oci/delete_test.go @@ -22,10 +22,11 @@ import ( "testing" "time" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" gcrv1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/random" + "github.com/google/go-containerregistry/pkg/v1/remote" . "github.com/onsi/gomega" ) @@ -49,7 +50,9 @@ func TestDelete(t *testing.T) { img, err := random.Image(1024, 1) g.Expect(err).ToNot(HaveOccurred()) img = mutate.Annotations(img, m.ToAnnotations()).(gcrv1.Image) - err = crane.Push(img, dst, c.options...) + ref, err := name.ParseReference(dst) + g.Expect(err).ToNot(HaveOccurred()) + err = remote.Write(ref, img, c.options...) g.Expect(err).ToNot(HaveOccurred()) } @@ -83,7 +86,9 @@ func TestDelete(t *testing.T) { g.Expect(err).To(BeNil()) for _, tag := range tt.checkTags { - _, err = crane.Pull(fmt.Sprintf("%s/%s:%s", dockerReg, repo, tag)) + ref, err := name.ParseReference(fmt.Sprintf("%s/%s:%s", dockerReg, repo, tag)) + g.Expect(err).ToNot(HaveOccurred()) + _, err = remote.Get(ref) g.Expect(err).ToNot(BeNil()) g.Expect(err.Error()).To(ContainSubstring("manifest unknown")) } diff --git a/oci/diff.go b/oci/diff.go index 1bc5d9ac2..6bd2b9581 100644 --- a/oci/diff.go +++ b/oci/diff.go @@ -25,14 +25,14 @@ import ( "os" "path/filepath" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" ) // Diff compares the files included in an OCI image with the local files in the given path // and returns an error if the contents is different func (c *Client) Diff(ctx context.Context, url, dir string, ignorePaths []string) error { - _, err := name.ParseReference(url) + ref, err := name.ParseReference(url) if err != nil { return fmt.Errorf("invalid URL: %w", err) } @@ -65,11 +65,16 @@ func (c *Client) Diff(ctx context.Context, url, dir string, ignorePaths []string return fmt.Errorf("calculating artifact hash failed: %w", err) } - img, err := crane.Pull(url, c.optionsWithContext(ctx)...) + desc, err := remote.Get(ref, c.optionsWithContext(ctx)...) if err != nil { return err } + img, err := desc.Image() + if err != nil { + return fmt.Errorf("parsing image failed: %w", err) + } + layers, err := img.Layers() if err != nil { return fmt.Errorf("failed to list layers: %w", err) diff --git a/oci/diff_test.go b/oci/diff_test.go index cf5a615bb..2a91b38ff 100644 --- a/oci/diff_test.go +++ b/oci/diff_test.go @@ -23,7 +23,6 @@ import ( "path/filepath" "testing" - _ "github.com/google/go-containerregistry/pkg/crane" . "github.com/onsi/gomega" ) diff --git a/oci/list.go b/oci/list.go index 75c91817e..20b4d4019 100644 --- a/oci/list.go +++ b/oci/list.go @@ -25,8 +25,9 @@ import ( "strings" "github.com/Masterminds/semver/v3" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" gcrv1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/fluxcd/pkg/version" ) @@ -45,7 +46,13 @@ type ListOptions struct { // List fetches the tags and their manifests for a given OCI repository. func (c *Client) List(ctx context.Context, url string, opts ListOptions) ([]Metadata, error) { metas := make([]Metadata, 0) - tags, err := crane.ListTags(url, c.options...) + + repo, err := name.NewRepository(url) + if err != nil { + return nil, fmt.Errorf("parsing repository failed: %w", err) + } + + tags, err := remote.List(repo, c.optionsWithContext(ctx)...) if err != nil { return nil, fmt.Errorf("listing tags failed: %w", err) } @@ -94,12 +101,13 @@ func (c *Client) List(ctx context.Context, url string, opts ListOptions) ([]Meta URL: fmt.Sprintf("%s:%s", url, tag), } - manifestJSON, err := crane.Manifest(meta.URL, c.optionsWithContext(ctx)...) + tagRef := repo.Tag(tag) + desc, err := remote.Get(tagRef, c.optionsWithContext(ctx)...) if err != nil { return nil, fmt.Errorf("fetching manifest failed: %w", err) } - manifest, err := gcrv1.ParseManifest(bytes.NewReader(manifestJSON)) + manifest, err := gcrv1.ParseManifest(bytes.NewReader(desc.Manifest)) if err != nil { return nil, fmt.Errorf("parsing manifest failed: %w", err) } @@ -109,11 +117,7 @@ func (c *Client) List(ctx context.Context, url string, opts ListOptions) ([]Meta meta.Source = manifestMetadata.Source meta.Created = manifestMetadata.Created - digest, err := crane.Digest(meta.URL, c.optionsWithContext(ctx)...) - if err != nil { - return nil, fmt.Errorf("fetching digest failed: %w", err) - } - meta.Digest = digest + meta.Digest = desc.Digest.String() metas = append(metas, meta) } diff --git a/oci/list_test.go b/oci/list_test.go index 42e6b29da..904c7de45 100644 --- a/oci/list_test.go +++ b/oci/list_test.go @@ -22,11 +22,11 @@ import ( "testing" "time" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" gcrv1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/random" + "github.com/google/go-containerregistry/pkg/v1/remote" . "github.com/onsi/gomega" ) @@ -61,7 +61,9 @@ func Test_List(t *testing.T) { img, err := random.Image(1024, 1) g.Expect(err).ToNot(HaveOccurred()) img = mutate.Annotations(img, m.ToAnnotations()).(gcrv1.Image) - err = crane.Push(img, dst, c.options...) + ref, err := name.ParseReference(dst) + g.Expect(err).ToNot(HaveOccurred()) + err = remote.Write(ref, img, c.options...) g.Expect(err).ToNot(HaveOccurred()) } @@ -135,9 +137,11 @@ func Test_List(t *testing.T) { g.Expect(meta.ToAnnotations()).To(Equal(m.ToAnnotations())) - digest, err := crane.Digest(meta.URL, c.options...) + digestRef, err := name.ParseReference(fmt.Sprintf("%s/%s:%s", dockerReg, repo, tag.TagStr())) + g.Expect(err).ToNot(HaveOccurred()) + desc, err := remote.Get(digestRef, c.options...) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(meta.Digest).To(Equal(digest)) + g.Expect(meta.Digest).To(Equal(desc.Digest.String())) } }) } diff --git a/oci/login.go b/oci/login.go index a601004c5..0a78b6e41 100644 --- a/oci/login.go +++ b/oci/login.go @@ -21,7 +21,7 @@ import ( "strings" "github.com/google/go-containerregistry/pkg/authn" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/v1/remote" ) // LoginWithCredentials configures the client with static credentials, accepts a single token @@ -32,7 +32,7 @@ func (c *Client) LoginWithCredentials(credentials string) error { return err } - c.options = append(c.options, crane.WithAuth(auth)) + c.options = append(c.options, remote.WithAuth(auth)) return nil } diff --git a/oci/login_test.go b/oci/login_test.go index 6bb7acedc..092a2afca 100644 --- a/oci/login_test.go +++ b/oci/login_test.go @@ -24,7 +24,8 @@ import ( "strings" "testing" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" . "github.com/onsi/gomega" ) @@ -72,10 +73,12 @@ func Test_Login(t *testing.T) { }, } - c.options = append(c.options, crane.WithTransport(&transportFunc)) + c.options = append(c.options, remote.WithTransport(&transportFunc)) - err = crane.Delete(fmt.Sprintf("%s/%s:%s", dockerReg, "test", "test"), c.optionsWithContext(ctx)...) + ref, err := name.ParseReference(fmt.Sprintf("%s/%s:%s", dockerReg, "test", "test")) g.Expect(err).ToNot(HaveOccurred()) + + _ = remote.Delete(ref, c.optionsWithContext(ctx)...) g.Expect(transportFunc.request).ToNot(BeNil()) g.Expect(transportFunc.request.Header.Get("Authorization")).To(Equal(tt.expectedAuth)) }) diff --git a/oci/pull.go b/oci/pull.go index 1674b74fd..15d233a36 100644 --- a/oci/pull.go +++ b/oci/pull.go @@ -24,9 +24,9 @@ import ( "io" "os" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" gcrv1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/fluxcd/pkg/tar" ) @@ -75,11 +75,16 @@ func (c *Client) Pull(ctx context.Context, url, outPath string, opts ...PullOpti return nil, fmt.Errorf("invalid URL: %w", err) } - img, err := crane.Pull(url, c.optionsWithContext(ctx)...) + desc, err := remote.Get(ref, c.optionsWithContext(ctx)...) if err != nil { return nil, err } + img, err := desc.Image() + if err != nil { + return nil, fmt.Errorf("parsing image failed: %w", err) + } + digest, err := img.Digest() if err != nil { return nil, fmt.Errorf("parsing digest failed: %w", err) diff --git a/oci/pull_test.go b/oci/pull_test.go index ee76a6f86..dcf34fa12 100644 --- a/oci/pull_test.go +++ b/oci/pull_test.go @@ -22,9 +22,10 @@ import ( "path/filepath" "testing" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/google/go-containerregistry/pkg/v1/types" . "github.com/onsi/gomega" @@ -53,7 +54,9 @@ func Test_PullAnyTarball(t *testing.T) { img, err = mutate.Append(img, mutate.Addendum{Layer: layer}) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(crane.Push(img, dst, c.optionsWithContext(ctx)...)).ToNot(HaveOccurred()) + ref, err := name.ParseReference(dst) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(remote.Write(ref, img, c.optionsWithContext(ctx)...)).ToNot(HaveOccurred()) extractTo := filepath.Join(t.TempDir(), "artifact") m, err := c.Pull(ctx, dst, extractTo) diff --git a/oci/push.go b/oci/push.go index 9f15583f7..5ebc76981 100644 --- a/oci/push.go +++ b/oci/push.go @@ -23,11 +23,11 @@ import ( "path/filepath" "time" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" gcrv1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/static" "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/google/go-containerregistry/pkg/v1/types" @@ -146,7 +146,7 @@ func (c *Client) Push(ctx context.Context, url, sourcePath string, opts ...PushO return "", fmt.Errorf("appeding content to artifact failed: %w", err) } - if err := crane.Push(img, url, c.optionsWithContext(ctx)...); err != nil { + if err := remote.Write(ref, img, c.optionsWithContext(ctx)...); err != nil { return "", fmt.Errorf("pushing artifact failed: %w", err) } diff --git a/oci/push_pull_test.go b/oci/push_pull_test.go index d0d15b745..0d2c5f594 100644 --- a/oci/push_pull_test.go +++ b/oci/push_pull_test.go @@ -28,9 +28,10 @@ import ( "testing" "time" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/static" "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/google/go-containerregistry/pkg/v1/types" @@ -159,7 +160,11 @@ func Test_Push_Pull(t *testing.T) { return err } - err = crane.Push(img, url, c.optionsWithContext(ctx)...) + ref, err := name.ParseReference(url) + if err != nil { + return err + } + err = remote.Write(ref, img, c.optionsWithContext(ctx)...) if err != nil { return err } @@ -196,7 +201,11 @@ func Test_Push_Pull(t *testing.T) { } dst := fmt.Sprintf("%s/%s:%s", dockerReg, repo, "not-flux") - err = crane.Push(img, dst, c.optionsWithContext(ctx)...) + ref, err := name.ParseReference(dst) + if err != nil { + return err + } + err = remote.Write(ref, img, c.optionsWithContext(ctx)...) if err != nil { return err } @@ -236,12 +245,18 @@ func Test_Push_Pull(t *testing.T) { g.Expect(err).To(Not(HaveOccurred())) // Verify that the artifact and its tag is present in the registry - tags, err := crane.ListTags(fmt.Sprintf("%s/%s", dockerReg, repo)) + repoRef, err := name.NewRepository(fmt.Sprintf("%s/%s", dockerReg, repo)) + g.Expect(err).ToNot(HaveOccurred()) + tags, err := remote.List(repoRef, c.optionsWithContext(ctx)...) g.Expect(err).ToNot(HaveOccurred()) g.Expect(tags).To(ContainElement(tt.tag)) // Pull the artifact from registry - image, err := crane.Pull(fmt.Sprintf("%s/%s:%s", dockerReg, repo, tt.tag)) + imgRef, err := name.ParseReference(fmt.Sprintf("%s/%s:%s", dockerReg, repo, tt.tag)) + g.Expect(err).ToNot(HaveOccurred()) + desc, err := remote.Get(imgRef, c.optionsWithContext(ctx)...) + g.Expect(err).ToNot(HaveOccurred()) + image, err := desc.Image() g.Expect(err).ToNot(HaveOccurred()) // Extract the manifest from the pulled artifact @@ -345,7 +360,11 @@ func Test_PushCreatedAnnotationOverridesConfigCreated(t *testing.T) { _, err := c.Push(ctx, url, "testdata/artifact", WithPushMetadata(metadata)) g.Expect(err).ToNot(HaveOccurred()) - image, err := crane.Pull(url) + imgRef, err := name.ParseReference(url) + g.Expect(err).ToNot(HaveOccurred()) + desc, err := remote.Get(imgRef) + g.Expect(err).ToNot(HaveOccurred()) + image, err := desc.Image() g.Expect(err).ToNot(HaveOccurred()) manifest, err := image.Manifest() @@ -375,7 +394,11 @@ func Test_PushEmptyCreatedAnnotationUsesDefaultCreated(t *testing.T) { _, err := c.Push(ctx, url, "testdata/artifact", WithPushMetadata(metadata)) g.Expect(err).ToNot(HaveOccurred()) - image, err := crane.Pull(url) + imgRef, err := name.ParseReference(url) + g.Expect(err).ToNot(HaveOccurred()) + desc, err := remote.Get(imgRef) + g.Expect(err).ToNot(HaveOccurred()) + image, err := desc.Image() g.Expect(err).ToNot(HaveOccurred()) manifest, err := image.Manifest() diff --git a/oci/retry_transport.go b/oci/retry_transport.go index 1e381dd7e..00762bbf2 100644 --- a/oci/retry_transport.go +++ b/oci/retry_transport.go @@ -26,14 +26,13 @@ import ( "syscall" "github.com/google/go-containerregistry/pkg/authn" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/logs" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote/transport" ) -// WithRetryTransport returns a crane.Option for setting transport that uses the backoff for retries +// WithRetryTransport returns a remote.Option for setting transport that uses the backoff for retries // // Most parts(including the functions below) are copied from https://github.com/google/go-containerregistry/blob/v0.14.0/pkg/v1/remote/options.go#L152 // so we have the same transport used in the library but with a different retry backoff. @@ -42,7 +41,7 @@ func WithRetryTransport(ctx context.Context, auth authn.Authenticator, backoff remote.Backoff, scopes []string, - insecure bool) (crane.Option, error) { + insecure bool) (remote.Option, error) { httpTransport := remote.DefaultTransport.(*http.Transport).Clone() if insecure { if httpTransport.TLSClientConfig == nil { @@ -73,7 +72,7 @@ func WithRetryTransport(ctx context.Context, if err != nil { return nil, err } - return crane.WithTransport(t), nil + return remote.WithTransport(t), nil } var defaultRetryPredicate = func(err error) bool { diff --git a/oci/tag.go b/oci/tag.go index 8595f756d..4aec52759 100644 --- a/oci/tag.go +++ b/oci/tag.go @@ -20,8 +20,8 @@ import ( "context" "fmt" - "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" ) // Tag creates a new tag for the given artifact using the same OCI repository as the origin. @@ -31,11 +31,15 @@ func (c *Client) Tag(ctx context.Context, url, tag string) (string, error) { return "", fmt.Errorf("invalid URL: %w", err) } - if err := crane.Tag(url, tag, c.optionsWithContext(ctx)...); err != nil { - return "", err + desc, err := remote.Get(ref, c.optionsWithContext(ctx)...) + if err != nil { + return "", fmt.Errorf("fetching image failed: %w", err) } dst := ref.Context().Tag(tag) + if err := remote.Tag(dst, desc, c.optionsWithContext(ctx)...); err != nil { + return "", err + } return dst.Name(), nil } diff --git a/oci/tag_test.go b/oci/tag_test.go index 4215ba207..d1d48c250 100644 --- a/oci/tag_test.go +++ b/oci/tag_test.go @@ -21,8 +21,9 @@ import ( "fmt" "testing" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/random" + "github.com/google/go-containerregistry/pkg/v1/remote" . "github.com/onsi/gomega" ) @@ -34,13 +35,17 @@ func Test_Tag(t *testing.T) { url := fmt.Sprintf("%s/%s:v0.0.1", dockerReg, testRepo) img, err := random.Image(1024, 1) g.Expect(err).ToNot(HaveOccurred()) - err = crane.Push(img, url, c.options...) + ref, err := name.ParseReference(url) + g.Expect(err).ToNot(HaveOccurred()) + err = remote.Write(ref, img, c.options...) g.Expect(err).ToNot(HaveOccurred()) _, err = c.Tag(ctx, url, "v0.0.2") g.Expect(err).ToNot(HaveOccurred()) - tags, err := crane.ListTags(fmt.Sprintf("%s/%s", dockerReg, testRepo)) + repoRef, err := name.NewRepository(fmt.Sprintf("%s/%s", dockerReg, testRepo)) + g.Expect(err).ToNot(HaveOccurred()) + tags, err := remote.List(repoRef) g.Expect(err).ToNot(HaveOccurred()) g.Expect(len(tags)).To(BeEquivalentTo(2)) g.Expect(tags).To(BeEquivalentTo([]string{"v0.0.1", "v0.0.2"}))