Skip to content
This repository has been archived by the owner on Jun 13, 2021. It is now read-only.

Commit

Permalink
Support using bundles both by Named reference and raw ID
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
  • Loading branch information
ndeloof committed Oct 11, 2019
1 parent 6a9e04b commit 5b7f386
Show file tree
Hide file tree
Showing 16 changed files with 296 additions and 173 deletions.
56 changes: 46 additions & 10 deletions e2e/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,43 @@ func TestBuild(t *testing.T) {
cmd := info.configuredCmd

testDir := path.Join("testdata", "build")
cmd.Command = dockerCli.Command("app", "build", path.Join(testDir, "single"), "single:1.0.0")
cmd.Command = dockerCli.Command("app", "build", path.Join(testDir, "single"), "--tag", "single:1.0.0")
icmd.RunCmd(cmd).Assert(t, icmd.Success)

var cfg string
for _, s := range cmd.Env {
if strings.HasPrefix(s, "DOCKER_CONFIG=") {
cfg = s[14:]
}
}
if cfg == "" {
t.Fatalf("Failed to retrieve docker config folder")
cfg := getDockerConfigDir(t, cmd)

f := path.Join(cfg, "app", "bundles", "docker.io", "library", "single", "_tags", "1.0.0", "bundle.json")
data, err := ioutil.ReadFile(f)
assert.NilError(t, err)
var bndl bundle.Bundle
err = json.Unmarshal(data, &bndl)
assert.NilError(t, err)

built := []string{bndl.InvocationImages[0].Digest, bndl.Images["web"].Digest, bndl.Images["worker"].Digest}
for _, ref := range built {
cmd.Command = dockerCli.Command("inspect", ref)
icmd.RunCmd(cmd).Assert(t, icmd.Success)
}
})
}

func TestBuildWithoutTag(t *testing.T) {
runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
cmd := info.configuredCmd

testDir := path.Join("testdata", "build")
cmd.Command = dockerCli.Command("app", "build", path.Join(testDir, "single"))
icmd.RunCmd(cmd).Assert(t, icmd.Success)

f := path.Join(cfg, "app", "bundles", "docker.io", "library", "single", "_tags", "1.0.0.json")
cfg := getDockerConfigDir(t, cmd)

f := path.Join(cfg, "app", "bundles", "_ids")
infos, err := ioutil.ReadDir(f)
assert.NilError(t, err)
assert.Equal(t, len(infos), 1)
id := infos[0].Name()

f = path.Join(cfg, "app", "bundles", "_ids", id, "bundle.json")
data, err := ioutil.ReadFile(f)
assert.NilError(t, err)
var bndl bundle.Bundle
Expand All @@ -44,3 +67,16 @@ func TestBuild(t *testing.T) {
}
})
}

func getDockerConfigDir(t *testing.T, cmd icmd.Cmd) string {
var cfg string
for _, s := range cmd.Env {
if strings.HasPrefix(s, "DOCKER_CONFIG=") {
cfg = s[14:]
}
}
if cfg == "" {
t.Fatalf("Failed to retrieve docker config folder")
}
return cfg
}
6 changes: 3 additions & 3 deletions e2e/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestRenderFormatters(t *testing.T) {
cmd := info.configuredCmd

appPath := filepath.Join("testdata", "simple", "simple.dockerapp")
cmd.Command = dockerCli.Command("app", "build", appPath, "a-simple-tag")
cmd.Command = dockerCli.Command("app", "build", appPath, "--tag", "a-simple-tag")
icmd.RunCmd(cmd).Assert(t, icmd.Success)

cmd.Command = dockerCli.Command("app", "render", "--formatter", "json", appPath)
Expand Down Expand Up @@ -161,10 +161,10 @@ func TestInspectApp(t *testing.T) {
cmd.Dir = dir.Path()
icmd.RunCmd(cmd).Assert(t, icmd.Expected{
ExitCode: 1,
Err: "invalid reference format",
Err: "could not parse '' as a valid reference",
})

cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "simple-app:1.0.0")
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "--tag", "simple-app:1.0.0")
cmd.Dir = ""
icmd.RunCmd(cmd).Assert(t, icmd.Success)

Expand Down
14 changes: 7 additions & 7 deletions e2e/images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import (

func insertBundles(t *testing.T, cmd icmd.Cmd, info dindSwarmAndRegistryInfo) {
// Push an application so that we can later pull it by digest
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), info.registryAddress+"/c-myapp")
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), "--tag", info.registryAddress+"/c-myapp")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "b-simple-app")
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "--tag", "b-simple-app")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "a-simple-app")
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "--tag", "a-simple-app")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
}

Expand Down Expand Up @@ -86,7 +86,7 @@ func TestImageTag(t *testing.T) {
}

// given a first available image
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "a-simple-app")
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "simple", "simple.dockerapp"), "--tag", "a-simple-app")
icmd.RunCmd(cmd).Assert(t, icmd.Success)

singleImageExpectation := `APP IMAGE APP NAME
Expand All @@ -112,14 +112,14 @@ a-simple-app:latest simple
dockerAppImageTag("a-simple-app$2", "b-simple-app")
icmd.RunCmd(cmd).Assert(t, icmd.Expected{
ExitCode: 1,
Err: `could not parse 'a-simple-app$2' as a valid reference: invalid reference format`,
Err: `could not parse 'a-simple-app$2' as a valid reference`,
})

// with invalid target reference
dockerAppImageTag("a-simple-app", "b@simple-app")
icmd.RunCmd(cmd).Assert(t, icmd.Expected{
ExitCode: 1,
Err: `could not parse 'b@simple-app' as a valid reference: invalid reference format`,
Err: `could not parse 'b@simple-app' as a valid reference`,
})

// with unexisting source image
Expand Down Expand Up @@ -175,7 +175,7 @@ c-simple-app:latest simple
`)

// given a new application
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), "push-pull")
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), "--tag", "push-pull")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
a-simple-app:0.1 simple
Expand Down
4 changes: 2 additions & 2 deletions e2e/pushpull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func TestPushInstallBundle(t *testing.T) {
ref := info.registryAddress + "/test/push-bundle"

// render the app to a bundle, we use the app from the push pull test above.
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), "a-simple-app:1.0.0")
cmd.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), "--tag", "a-simple-app:1.0.0")
icmd.RunCmd(cmd).Assert(t, icmd.Success)

// push it and install to check it is available
Expand Down Expand Up @@ -243,7 +243,7 @@ func TestPushInstallBundle(t *testing.T) {
cmdIsolatedStore.Env = append(cmdIsolatedStore.Env, "DOCKER_CONTEXT=swarm-context")

// bundle the app again but this time with a tag to store it into the bundle store
cmdIsolatedStore.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), ref2)
cmdIsolatedStore.Command = dockerCli.Command("app", "build", filepath.Join("testdata", "push-pull", "push-pull.dockerapp"), "--tag", ref2)
icmd.RunCmd(cmdIsolatedStore).Assert(t, icmd.Success)
// Push the app without tagging it explicitly
cmdIsolatedStore.Command = dockerCli.Command("app", "push", ref2)
Expand Down
32 changes: 9 additions & 23 deletions internal/commands/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,14 @@ type buildOptions struct {
func Cmd(dockerCli command.Cli) *cobra.Command {
var opts buildOptions
cmd := &cobra.Command{
Use: "build [APP_NAME] [APP_IMAGE]",
Use: "build [APP_NAME] [OPTIONS]",
Short: "Build service images for the application",
Example: `$ docker app build myapp.dockerapp my/app:1.0.0`,
Args: cli.ExactArgs(2),
Example: `$ docker app build myapp.dockerapp --tag my/app:1.0.0`,
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.tag = args[1]
tag, err := runBuild(dockerCli, args[0], opts)
ref, err := runBuild(dockerCli, args[0], opts)
if err == nil {
fmt.Printf("Successfully build %s\n", tag.String())
fmt.Printf("Successfully build %s\n", ref.String())
}
return err
},
Expand All @@ -56,23 +55,19 @@ func Cmd(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.BoolVar(&opts.noCache, "no-cache", false, "Do not use cache when building the image")
flags.StringVar(&opts.progress, "progress", "auto", "Set type of progress output (auto, plain, tty). Use plain to show container output")
flags.StringVarP(&opts.tag, "tag", "t", "", "Application image and optionally a tag in the 'image:tag' format")
flags.BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image")

return cmd
}

func runBuild(dockerCli command.Cli, application string, opt buildOptions) (reference.Named, error) {
func runBuild(dockerCli command.Cli, application string, opt buildOptions) (reference.Reference, error) {
err := checkMinimalEngineVersion(dockerCli)
if err != nil {
return nil, err
}

if opt.tag == "" {
// FIXME temporary, until we get support for Digest in bundleStore and other commands
return nil, fmt.Errorf("A tag is required to run docker app build")
}

var ref reference.Named
var ref reference.Reference
ref, err = packager.GetNamedTagged(opt.tag)
if err != nil {
return nil, err
Expand Down Expand Up @@ -128,16 +123,7 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
return nil, err
}

if ref == nil {
if ref, err = computeDigest(bundle); err != nil {
return nil, err
}
}

if err = packager.PersistInBundleStore(ref, bundle); err != nil {
return nil, err
}
return ref, nil
return packager.PersistInBundleStore(ref, bundle)
}

func checkMinimalEngineVersion(dockerCli command.Cli) error {
Expand Down
43 changes: 0 additions & 43 deletions internal/commands/build/digest.go

This file was deleted.

26 changes: 13 additions & 13 deletions internal/commands/cnab.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/deislabs/cnab-go/driver"
dockerDriver "github.com/deislabs/cnab-go/driver/docker"
"github.com/docker/app/internal"
"github.com/docker/app/internal/commands/image"
"github.com/docker/app/internal/log"
"github.com/docker/app/internal/packager"
appstore "github.com/docker/app/internal/store"
Expand Down Expand Up @@ -283,25 +284,24 @@ func resolveBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, name
return nil, "", fmt.Errorf("could not resolve bundle %q", name)
}

func getBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, name string) (*bundle.Bundle, reference.Named, error) {
ref, err := reference.ParseNormalizedNamed(name)
func getBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, name string) (*bundle.Bundle, reference.Reference, error) {
ref, err := image.StringToRef(name)
if err != nil {
return nil, nil, errors.Wrap(err, name)
return nil, nil, err
}
tagRef := reference.TagNameOnly(ref)

bndl, err := bundleStore.Read(tagRef)
bndl, err := bundleStore.Read(ref)
if err != nil {
fmt.Fprintf(dockerCli.Err(), "Unable to find application image %q locally\n", reference.FamiliarString(tagRef))
fmt.Fprintf(dockerCli.Err(), "Unable to find application image %q locally\n", reference.FamiliarString(ref))

bndl, err = pullBundle(dockerCli, bundleStore, tagRef)
if err != nil {
return nil, nil, err
if named, ok := ref.(reference.Named); ok {
bndl, err = pullBundle(dockerCli, bundleStore, named)
if err != nil {
return nil, nil, err
}
}
return bndl, tagRef, nil
}

return bndl, tagRef, nil
return bndl, ref, nil
}

func pullBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, tagRef reference.Named) (*bundle.Bundle, error) {
Expand All @@ -314,7 +314,7 @@ func pullBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, tagRef
if err != nil {
return nil, err
}
if err := bundleStore.Store(tagRef, bndl); err != nil {
if _, err := bundleStore.Store(tagRef, bndl); err != nil {
return nil, err
}
return bndl, nil
Expand Down
4 changes: 2 additions & 2 deletions internal/commands/image/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func runList(dockerCli command.Cli, bundleStore store.BundleStore) error {
return printImages(dockerCli, pkgs)
}

func getPackages(bundleStore store.BundleStore, references []reference.Named) ([]pkg, error) {
func getPackages(bundleStore store.BundleStore, references []reference.Reference) ([]pkg, error) {
packages := make([]pkg, len(references))
for i, ref := range references {
b, err := bundleStore.Read(ref)
Expand Down Expand Up @@ -112,6 +112,6 @@ var (
)

type pkg struct {
ref reference.Named
ref reference.Reference
bundle *bundle.Bundle
}
7 changes: 3 additions & 4 deletions internal/commands/image/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,15 @@ $ docker app image rm docker.io/library/myapp@sha256:beef...`,
}

func runRm(bundleStore store.BundleStore, app string) error {
ref, err := reference.ParseNormalizedNamed(app)
ref, err := StringToRef(app)
if err != nil {
return err
}

tagged := reference.TagNameOnly(ref)
if err := bundleStore.Remove(tagged); err != nil {
if err := bundleStore.Remove(ref); err != nil {
return err
}

fmt.Println("Deleted: " + reference.FamiliarString(tagged))
fmt.Println("Deleted: " + reference.FamiliarString(ref))
return nil
}
18 changes: 8 additions & 10 deletions internal/commands/image/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func runTag(bundleStore store.BundleStore, srcAppImage, destAppImage string) err
}

func readBundle(name string, bundleStore store.BundleStore) (*bundle.Bundle, error) {
cnabRef, err := stringToRef(name)
cnabRef, err := StringToRef(name)
if err != nil {
return nil, err
}
Expand All @@ -57,19 +57,17 @@ func readBundle(name string, bundleStore store.BundleStore) (*bundle.Bundle, err
}

func storeBundle(bundle *bundle.Bundle, name string, bundleStore store.BundleStore) error {
cnabRef, err := stringToRef(name)
cnabRef, err := StringToRef(name)
if err != nil {
return err
}

return bundleStore.Store(cnabRef, bundle)
_, err = bundleStore.Store(cnabRef, bundle)
return err
}

func stringToRef(name string) (reference.Named, error) {
cnabRef, err := reference.ParseNormalizedNamed(name)
if err != nil {
return nil, fmt.Errorf("could not parse '%s' as a valid reference: %v", name, err)
func StringToRef(s string) (reference.Reference, error) {
if named, err := reference.ParseNormalizedNamed(s); err == nil {
return reference.TagNameOnly(named), nil
}

return reference.TagNameOnly(cnabRef), nil
return store.FromString(s)
}

0 comments on commit 5b7f386

Please sign in to comment.