From 634a7d2a7b593f3202afd1aad70debf72cdb3000 Mon Sep 17 00:00:00 2001
From: maxcleme <maxime.clement@docker.com>
Date: Fri, 6 Jan 2023 17:30:55 +0100
Subject: [PATCH] Support for docker compose build --push when using multiple
 platforms

Signed-off-by: maxcleme <maxime.clement@docker.com>
---
 cmd/compose/build.go                     |  3 +++
 docs/reference/compose_build.md          |  1 +
 docs/reference/docker_compose_build.yaml | 10 ++++++++++
 pkg/api/api.go                           |  2 ++
 pkg/compose/build.go                     |  7 +++++--
 pkg/compose/build_classic.go             |  6 ++++++
 6 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/cmd/compose/build.go b/cmd/compose/build.go
index 28650e52c..d17d34ef6 100644
--- a/cmd/compose/build.go
+++ b/cmd/compose/build.go
@@ -38,6 +38,7 @@ type buildOptions struct {
 	composeOptions
 	quiet    bool
 	pull     bool
+	push     bool
 	progress string
 	args     []string
 	noCache  bool
@@ -57,6 +58,7 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions,
 
 	return api.BuildOptions{
 		Pull:     opts.pull,
+		Push:     opts.push,
 		Progress: opts.progress,
 		Args:     types.NewMappingWithEquals(opts.args),
 		NoCache:  opts.noCache,
@@ -108,6 +110,7 @@ func buildCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *
 		}),
 		ValidArgsFunction: completeServiceNames(p),
 	}
+	cmd.Flags().BoolVar(&opts.push, "push", false, "Push service images.")
 	cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
 	cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.")
 	cmd.Flags().StringVar(&opts.progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
diff --git a/docs/reference/compose_build.md b/docs/reference/compose_build.md
index 4437a133e..e631c25da 100644
--- a/docs/reference/compose_build.md
+++ b/docs/reference/compose_build.md
@@ -11,6 +11,7 @@ Build or rebuild services
 | `--no-cache`    |               |         | Do not use cache when building the image                                                                    |
 | `--progress`    | `string`      | `auto`  | Set type of progress output (auto, tty, plain, quiet)                                                       |
 | `--pull`        |               |         | Always attempt to pull a newer version of the image.                                                        |
+| `--push`        |               |         | Push service images.                                                                                        |
 | `-q`, `--quiet` |               |         | Don't print anything to STDOUT                                                                              |
 | `--ssh`         | `string`      |         | Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) |
 
diff --git a/docs/reference/docker_compose_build.yaml b/docs/reference/docker_compose_build.yaml
index efb0149b1..11049c99e 100644
--- a/docs/reference/docker_compose_build.yaml
+++ b/docs/reference/docker_compose_build.yaml
@@ -106,6 +106,16 @@ options:
       experimentalcli: false
       kubernetes: false
       swarm: false
+    - option: push
+      value_type: bool
+      default_value: "false"
+      description: Push service images.
+      deprecated: false
+      hidden: false
+      experimental: false
+      experimentalcli: false
+      kubernetes: false
+      swarm: false
     - option: quiet
       shorthand: q
       value_type: bool
diff --git a/pkg/api/api.go b/pkg/api/api.go
index 11f798b27..892fbe5bf 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -91,6 +91,8 @@ type WatchOptions struct {
 type BuildOptions struct {
 	// Pull always attempt to pull a newer version of the image
 	Pull bool
+	// Push pushes service images
+	Push bool
 	// Progress set type of progress output ("auto", "plain", "tty")
 	Progress string
 	// Args set build-time args
diff --git a/pkg/compose/build.go b/pkg/compose/build.go
index 06209197d..1543852be 100644
--- a/pkg/compose/build.go
+++ b/pkg/compose/build.go
@@ -86,12 +86,15 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
 			Type: "docker",
 			Attrs: map[string]string{
 				"load": "true",
+				"push": fmt.Sprint(options.Push),
 			},
 		}}
 		if len(buildOptions.Platforms) > 1 {
 			buildOptions.Exports = []bclient.ExportEntry{{
-				Type:  "image",
-				Attrs: map[string]string{},
+				Type: "image",
+				Attrs: map[string]string{
+					"push": fmt.Sprint(options.Push),
+				},
 			}}
 		}
 		opts := map[string]build.Options{imageName: buildOptions}
diff --git a/pkg/compose/build_classic.go b/pkg/compose/build_classic.go
index 6c9a8b63d..c2548400d 100644
--- a/pkg/compose/build_classic.go
+++ b/pkg/compose/build_classic.go
@@ -59,6 +59,12 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
 			errs = multierror.Append(errs, err).ErrorOrNil()
 		}
 		nameDigests[imageName] = digest
+		if errs != nil {
+			return nil
+		}
+		if len(o.Exports) != 0 && o.Exports[0].Attrs["push"] == "true" {
+			return s.push(ctx, project, api.PushOptions{})
+		}
 		return nil
 	})
 	if err != nil {