Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 7c4126b

Browse files
committed
Enable push of images from cnab-to-oci
Signed-off-by: Yves Brissaud <yves.brissaud@docker.com>
1 parent afe63d7 commit 7c4126b

2 files changed

Lines changed: 13 additions & 219 deletions

File tree

internal/commands/push.go

Lines changed: 13 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"context"
66
"fmt"
77
"io"
8-
"io/ioutil"
98
"os"
109
"strings"
1110

@@ -14,16 +13,11 @@ import (
1413
"github.com/docker/app/internal"
1514
"github.com/docker/app/internal/cnab"
1615
"github.com/docker/app/internal/log"
17-
"github.com/docker/app/internal/packager"
18-
"github.com/docker/app/types/metadata"
1916
"github.com/docker/cli/cli"
2017
"github.com/docker/cli/cli/command"
2118
"github.com/docker/cnab-to-oci/remotes"
2219
"github.com/docker/distribution/reference"
23-
"github.com/docker/docker/api/types"
24-
"github.com/docker/docker/pkg/jsonmessage"
2520
"github.com/docker/docker/pkg/term"
26-
"github.com/docker/docker/registry"
2721
"github.com/morikuni/aec"
2822
ocischemav1 "github.com/opencontainers/image-spec/specs-go/v1"
2923
"github.com/pkg/errors"
@@ -78,23 +72,15 @@ func runPush(dockerCli command.Cli, name string, opts pushOptions) error {
7872
if err != nil {
7973
return err
8074
}
81-
// Retag invocation image if needed
82-
retag, err := shouldRetagInvocationImage(metadata.FromBundle(bndl), bndl, opts.tag, ref)
75+
76+
cnabRef, err := reference.ParseNormalizedNamed(ref)
8377
if err != nil {
8478
return err
8579
}
86-
if retag.shouldRetag {
87-
logrus.Debugf(`Retagging invocation image "%q"`, retag.invocationImageRef.String())
88-
if err := retagInvocationImage(dockerCli, bndl, retag.invocationImageRef.String()); err != nil {
89-
return err
90-
}
91-
}
92-
// Push the invocation image
93-
if err := pushInvocationImage(dockerCli, retag); err != nil {
94-
return err
95-
}
80+
cnabRef = reference.TagNameOnly(cnabRef)
81+
9682
// Push the bundle
97-
return pushBundle(dockerCli, opts, bndl, retag)
83+
return pushBundle(dockerCli, opts, bndl, cnabRef)
9884
}
9985

10086
func resolveReferenceAndBundle(dockerCli command.Cli, name string) (*bundle.Bundle, string, error) {
@@ -113,30 +99,7 @@ func resolveReferenceAndBundle(dockerCli command.Cli, name string) (*bundle.Bund
11399
return bndl, ref, err
114100
}
115101

116-
func pushInvocationImage(dockerCli command.Cli, retag retagResult) error {
117-
logrus.Debugf("Pushing the invocation image %q", retag.invocationImageRef)
118-
repoInfo, err := registry.ParseRepositoryInfo(retag.invocationImageRef)
119-
if err != nil {
120-
return err
121-
}
122-
encodedAuth, err := command.EncodeAuthToBase64(command.ResolveAuthConfig(context.Background(), dockerCli, repoInfo.Index))
123-
if err != nil {
124-
return err
125-
}
126-
reader, err := dockerCli.Client().ImagePush(context.Background(), retag.invocationImageRef.String(), types.ImagePushOptions{
127-
RegistryAuth: encodedAuth,
128-
})
129-
if err != nil {
130-
return errors.Wrapf(err, "starting push of %q", retag.invocationImageRef.String())
131-
}
132-
defer reader.Close()
133-
if err := jsonmessage.DisplayJSONMessagesStream(reader, ioutil.Discard, 0, false, nil); err != nil {
134-
return errors.Wrapf(err, "pushing to %q", retag.invocationImageRef.String())
135-
}
136-
return nil
137-
}
138-
139-
func pushBundle(dockerCli command.Cli, opts pushOptions, bndl *bundle.Bundle, retag retagResult) error {
102+
func pushBundle(dockerCli command.Cli, opts pushOptions, bndl *bundle.Bundle, cnabRef reference.Named) error {
140103
insecureRegistries, err := internal.InsecureRegistriesFromEngine(dockerCli)
141104
if err != nil {
142105
return errors.Wrap(err, "could not retrieve insecure registries")
@@ -149,22 +112,23 @@ func pushBundle(dockerCli command.Cli, opts pushOptions, bndl *bundle.Bundle, re
149112
fixupOptions := []remotes.FixupOption{
150113
remotes.WithEventCallback(display.onEvent),
151114
remotes.WithAutoBundleUpdate(),
115+
remotes.WithPushImages(dockerCli.Client(), dockerCli.Out()),
152116
}
153117
if platforms := platformFilter(opts); len(platforms) > 0 {
154118
fixupOptions = append(fixupOptions, remotes.WithComponentImagePlatforms(platforms))
155119
}
156120
// bundle fixup
157-
relocationMap, err := remotes.FixupBundle(context.Background(), bndl, retag.cnabRef, resolver, fixupOptions...)
121+
relocationMap, err := remotes.FixupBundle(context.Background(), bndl, cnabRef, resolver, fixupOptions...)
158122
if err != nil {
159-
return errors.Wrapf(err, "fixing up %q for push", retag.cnabRef)
123+
return errors.Wrapf(err, "fixing up %q for push", cnabRef)
160124
}
161125
// push bundle manifest
162-
logrus.Debugf("Pushing the bundle %q", retag.cnabRef)
163-
descriptor, err := remotes.Push(log.WithLogContext(context.Background()), bndl, relocationMap, retag.cnabRef, resolver, true, withAppAnnotations)
126+
logrus.Debugf("Pushing the bundle %q", cnabRef)
127+
descriptor, err := remotes.Push(log.WithLogContext(context.Background()), bndl, relocationMap, cnabRef, resolver, true, withAppAnnotations)
164128
if err != nil {
165-
return errors.Wrapf(err, "pushing to %q", retag.cnabRef)
129+
return errors.Wrapf(err, "pushing to %q", cnabRef)
166130
}
167-
fmt.Fprintf(os.Stdout, "Successfully pushed bundle to %s. Digest is %s.\n", retag.cnabRef.String(), descriptor.Digest)
131+
fmt.Fprintf(os.Stdout, "Successfully pushed bundle to %s. Digest is %s.\n", cnabRef, descriptor.Digest)
168132
return nil
169133
}
170134

@@ -184,57 +148,6 @@ func platformFilter(opts pushOptions) []string {
184148
return opts.platforms
185149
}
186150

187-
func retagInvocationImage(dockerCli command.Cli, bndl *bundle.Bundle, newName string) error {
188-
err := dockerCli.Client().ImageTag(context.Background(), bndl.InvocationImages[0].Image, newName)
189-
if err != nil {
190-
return err
191-
}
192-
bndl.InvocationImages[0].Image = newName
193-
return nil
194-
}
195-
196-
type retagResult struct {
197-
shouldRetag bool
198-
cnabRef reference.Named
199-
invocationImageRef reference.Named
200-
}
201-
202-
func shouldRetagInvocationImage(meta metadata.AppMetadata, bndl *bundle.Bundle, tagOverride, bundleRef string) (retagResult, error) {
203-
// Use the bundle reference as a tag override
204-
if tagOverride == "" && bundleRef != "" {
205-
tagOverride = bundleRef
206-
}
207-
imgName := tagOverride
208-
var err error
209-
if imgName == "" {
210-
imgName, err = packager.MakeCNABImageName(meta.Name, meta.Version, "")
211-
if err != nil {
212-
return retagResult{}, err
213-
}
214-
}
215-
cnabRef, err := reference.ParseNormalizedNamed(imgName)
216-
if err != nil {
217-
return retagResult{}, errors.Wrap(err, imgName)
218-
}
219-
if _, digested := cnabRef.(reference.Digested); digested {
220-
return retagResult{}, errors.Errorf("%s: can't push to a digested reference", cnabRef)
221-
}
222-
cnabRef = reference.TagNameOnly(cnabRef)
223-
expectedInvocationImageRef, err := reference.ParseNormalizedNamed(reference.TagNameOnly(cnabRef).String() + "-invoc")
224-
if err != nil {
225-
return retagResult{}, errors.Wrap(err, reference.TagNameOnly(cnabRef).String()+"-invoc")
226-
}
227-
currentInvocationImageRef, err := reference.ParseNormalizedNamed(bndl.InvocationImages[0].Image)
228-
if err != nil {
229-
return retagResult{}, errors.Wrap(err, bndl.InvocationImages[0].Image)
230-
}
231-
return retagResult{
232-
cnabRef: cnabRef,
233-
invocationImageRef: expectedInvocationImageRef,
234-
shouldRetag: expectedInvocationImageRef.String() != currentInvocationImageRef.String(),
235-
}, nil
236-
}
237-
238151
type fixupDisplay interface {
239152
onEvent(remotes.FixupEvent)
240153
}

internal/commands/push_test.go

Lines changed: 0 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -3,128 +3,9 @@ package commands
33
import (
44
"testing"
55

6-
"github.com/deislabs/cnab-go/bundle"
7-
"github.com/docker/app/types/metadata"
8-
"github.com/docker/distribution/reference"
96
"gotest.tools/assert"
107
)
118

12-
type retagTestCase struct {
13-
name string
14-
metaName string
15-
metaVersion string
16-
invocationImageName string
17-
tag string
18-
bundleRef string
19-
expectedImageRef reference.Named
20-
expectedCnabRef reference.Named
21-
shouldRetag bool
22-
errorMessage string
23-
}
24-
25-
func (c *retagTestCase) buildPackageMetaAndBundle() (metadata.AppMetadata, *bundle.Bundle) {
26-
return metadata.AppMetadata{Name: c.metaName, Version: c.metaVersion},
27-
&bundle.Bundle{
28-
InvocationImages: []bundle.InvocationImage{
29-
{BaseImage: bundle.BaseImage{Image: c.invocationImageName}},
30-
},
31-
}
32-
}
33-
34-
func parseRefOrDie(t *testing.T, name string) reference.Named {
35-
t.Helper()
36-
ref, err := reference.ParseNormalizedNamed(name)
37-
assert.NilError(t, err)
38-
return ref
39-
}
40-
41-
func TestInvocationImageRetag(t *testing.T) {
42-
cases := []retagTestCase{
43-
{
44-
name: "no-tag-override-should-not-retag",
45-
metaName: "app",
46-
metaVersion: "0.1.0",
47-
invocationImageName: "app:0.1.0-invoc",
48-
tag: "",
49-
expectedImageRef: parseRefOrDie(t, "app:0.1.0-invoc"),
50-
expectedCnabRef: parseRefOrDie(t, "app:0.1.0"),
51-
shouldRetag: false,
52-
},
53-
{
54-
name: "name-override-should-retag",
55-
metaName: "app",
56-
metaVersion: "0.1.0",
57-
invocationImageName: "app:0.1.0-invoc",
58-
tag: "some-app",
59-
expectedImageRef: parseRefOrDie(t, "some-app:latest-invoc"),
60-
expectedCnabRef: parseRefOrDie(t, "some-app:latest"),
61-
shouldRetag: true,
62-
},
63-
{
64-
name: "tag-override-should-retag",
65-
metaName: "app",
66-
metaVersion: "0.1.0",
67-
invocationImageName: "app:0.1.0-invoc",
68-
tag: "some-app:test",
69-
expectedImageRef: parseRefOrDie(t, "some-app:test-invoc"),
70-
expectedCnabRef: parseRefOrDie(t, "some-app:test"),
71-
shouldRetag: true,
72-
},
73-
{
74-
name: "bundle-ref-should-retag",
75-
metaName: "app",
76-
metaVersion: "0.1.0",
77-
invocationImageName: "app:0.1.0-invoc",
78-
bundleRef: "some-app:test",
79-
expectedImageRef: parseRefOrDie(t, "some-app:test-invoc"),
80-
expectedCnabRef: parseRefOrDie(t, "some-app:test"),
81-
shouldRetag: true,
82-
},
83-
{
84-
name: "tag-overrides-bundle-ref",
85-
metaName: "app",
86-
metaVersion: "0.1.0",
87-
invocationImageName: "app:0.1.0-invoc",
88-
tag: "some-app:test",
89-
bundleRef: "other-app:other-test",
90-
expectedImageRef: parseRefOrDie(t, "some-app:test-invoc"),
91-
expectedCnabRef: parseRefOrDie(t, "some-app:test"),
92-
shouldRetag: true,
93-
},
94-
{
95-
name: "parsing-error",
96-
metaName: "app",
97-
metaVersion: "0.1.0",
98-
invocationImageName: "app:0.1.0-invoc",
99-
tag: "some-App:test",
100-
errorMessage: "some-App:test: invalid reference format: repository name must be lowercase",
101-
},
102-
{
103-
name: "error-no-digest",
104-
metaName: "app",
105-
metaVersion: "0.1.0",
106-
invocationImageName: "app:0.1.0-invoc",
107-
tag: "some-app@sha256:424d908f6801f786c68341b5d9083858f784142eb7a521a1512e0407e3ac8e75",
108-
errorMessage: "some-app@sha256:424d908f6801f786c68341b5d9083858f784142eb7a521a1512e0407e3ac8e75: can't push to a digested reference",
109-
},
110-
}
111-
112-
for _, c := range cases {
113-
t.Run(c.name, func(t *testing.T) {
114-
p, b := c.buildPackageMetaAndBundle()
115-
retag, err := shouldRetagInvocationImage(p, b, c.tag, c.bundleRef)
116-
if c.errorMessage == "" {
117-
assert.NilError(t, err)
118-
assert.Equal(t, retag.shouldRetag, c.shouldRetag)
119-
assert.Equal(t, retag.invocationImageRef.String(), c.expectedImageRef.String())
120-
assert.Equal(t, retag.cnabRef.String(), c.expectedCnabRef.String())
121-
} else {
122-
assert.ErrorContains(t, err, c.errorMessage)
123-
}
124-
})
125-
}
126-
}
127-
1289
func TestPlatformFilter(t *testing.T) {
12910
cases := []struct {
13011
name string

0 commit comments

Comments
 (0)