From f4ad2b8443bf48bf246a4ef24b58ae4edd59e59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Thu, 13 Nov 2025 10:59:28 +0100 Subject: [PATCH] build: Don't unpack by default when pushing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automatically set `unpack=false` for registry exports unless explicitly overridden by the user. This applies to: - `registry` exporter type (converted to `image` exporter with `push=true`) - `--push` flag usage with image exporters Users can still explicitly set `unpack=true` if they need local image storage alongside registry push. Signed-off-by: Paweł Gronowski --- build/opt.go | 4 ++ build/opt_test.go | 75 ++++++++++++++++++++++++++++ commands/build.go | 17 +++++-- docs/reference/buildx_build.md | 2 +- docs/reference/buildx_dap_build.md | 2 +- docs/reference/buildx_debug_build.md | 2 +- 6 files changed, 94 insertions(+), 8 deletions(-) diff --git a/build/opt.go b/build/opt.go index 1c6d429b8716..8c3ab65d2732 100644 --- a/build/opt.go +++ b/build/opt.go @@ -835,6 +835,10 @@ func CreateExports(entries []*buildflags.ExportEntry) ([]client.ExportEntry, []s case "registry": out.Type = client.ExporterImage out.Attrs["push"] = "true" + // Skip unpacking when only pushing to registry (unless explicitly set) + if _, ok := out.Attrs["unpack"]; !ok { + out.Attrs["unpack"] = "false" + } } if supportDir { diff --git a/build/opt_test.go b/build/opt_test.go index c57660139a5a..fde5154ba328 100644 --- a/build/opt_test.go +++ b/build/opt_test.go @@ -38,3 +38,78 @@ func TestCacheOptions_DerivedVars(t *testing.T) { }, }, CreateCaches(cacheFrom)) } + +func TestCreateExports_RegistryUnpack(t *testing.T) { + tests := []struct { + name string + entries []*buildflags.ExportEntry + wantType string + wantPush string + wantUnpack string + }{ + { + name: "registry type sets unpack=false", + entries: []*buildflags.ExportEntry{ + { + Type: "registry", + Attrs: map[string]string{}, + }, + }, + wantType: "image", + wantPush: "true", + wantUnpack: "false", + }, + { + name: "registry type respects explicit unpack=true", + entries: []*buildflags.ExportEntry{ + { + Type: "registry", + Attrs: map[string]string{ + "unpack": "true", + }, + }, + }, + wantType: "image", + wantPush: "true", + wantUnpack: "true", + }, + { + name: "registry type respects explicit unpack=false", + entries: []*buildflags.ExportEntry{ + { + Type: "registry", + Attrs: map[string]string{ + "unpack": "false", + }, + }, + }, + wantType: "image", + wantPush: "true", + wantUnpack: "false", + }, + { + name: "image type without push does not set unpack", + entries: []*buildflags.ExportEntry{ + { + Type: "image", + Attrs: map[string]string{}, + }, + }, + wantType: "image", + wantPush: "", + wantUnpack: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + exports, _, err := CreateExports(tt.entries) + require.NoError(t, err) + require.Len(t, exports, 1) + + require.Equal(t, tt.wantType, exports[0].Type) + require.Equal(t, tt.wantPush, exports[0].Attrs["push"]) + require.Equal(t, tt.wantUnpack, exports[0].Attrs["unpack"]) + }) + } +} diff --git a/commands/build.go b/commands/build.go index 6a8cc52c1b14..3fbe2fc03668 100644 --- a/commands/build.go +++ b/commands/build.go @@ -541,7 +541,7 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions, debugger debuggerOpt flags.StringArrayVar(&options.platforms, "platform", platformsDefault, "Set target platform for build") - flags.BoolVar(&options.exportPush, "push", false, `Shorthand for "--output=type=registry"`) + flags.BoolVar(&options.exportPush, "push", false, `Shorthand for "--output=type=registry,unpack=false"`) flags.BoolVarP(&options.quiet, "quiet", "q", false, "Suppress the build output and print image ID on success") @@ -1047,15 +1047,22 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in *BuildOptions, inSt for i := range outputs { if outputs[i].Type == client.ExporterImage { outputs[i].Attrs["push"] = "true" + // Skip unpacking when only pushing to registry (unless explicitly set) + if _, ok := outputs[i].Attrs["unpack"]; !ok { + outputs[i].Attrs["unpack"] = "false" + } pushUsed = true } } if !pushUsed { + attrs := map[string]string{ + "push": "true", + } + // Skip unpacking when only pushing to registry + attrs["unpack"] = "false" outputs = append(outputs, client.ExportEntry{ - Type: client.ExporterImage, - Attrs: map[string]string{ - "push": "true", - }, + Type: client.ExporterImage, + Attrs: attrs, }) } } diff --git a/docs/reference/buildx_build.md b/docs/reference/buildx_build.md index a1f4dc41ed57..611731203b53 100644 --- a/docs/reference/buildx_build.md +++ b/docs/reference/buildx_build.md @@ -41,7 +41,7 @@ Start a build | [`--progress`](#progress) | `string` | `auto` | Set type of progress output (`auto`, `none`, `plain`, `quiet`, `rawjson`, `tty`). Use plain to show container output | | [`--provenance`](#provenance) | `string` | | Shorthand for `--attest=type=provenance` | | `--pull` | `bool` | | Always attempt to pull all referenced images | -| [`--push`](#push) | `bool` | | Shorthand for `--output=type=registry` | +| [`--push`](#push) | `bool` | | Shorthand for `--output=type=registry,unpack=false` | | `-q`, `--quiet` | `bool` | | Suppress the build output and print image ID on success | | [`--sbom`](#sbom) | `string` | | Shorthand for `--attest=type=sbom` | | [`--secret`](#secret) | `stringArray` | | Secret to expose to the build (format: `id=mysecret[,src=/local/secret]`) | diff --git a/docs/reference/buildx_dap_build.md b/docs/reference/buildx_dap_build.md index 1358d5e9dd0d..99821aefb9d9 100644 --- a/docs/reference/buildx_dap_build.md +++ b/docs/reference/buildx_dap_build.md @@ -33,7 +33,7 @@ Start a build | `--progress` | `string` | `auto` | Set type of progress output (`auto`, `none`, `plain`, `quiet`, `rawjson`, `tty`). Use plain to show container output | | `--provenance` | `string` | | Shorthand for `--attest=type=provenance` | | `--pull` | `bool` | | Always attempt to pull all referenced images | -| `--push` | `bool` | | Shorthand for `--output=type=registry` | +| `--push` | `bool` | | Shorthand for `--output=type=registry,unpack=false` | | `-q`, `--quiet` | `bool` | | Suppress the build output and print image ID on success | | `--sbom` | `string` | | Shorthand for `--attest=type=sbom` | | `--secret` | `stringArray` | | Secret to expose to the build (format: `id=mysecret[,src=/local/secret]`) | diff --git a/docs/reference/buildx_debug_build.md b/docs/reference/buildx_debug_build.md index ddde975df80f..e444d9470b9e 100644 --- a/docs/reference/buildx_debug_build.md +++ b/docs/reference/buildx_debug_build.md @@ -37,7 +37,7 @@ Start a build | `--progress` | `string` | `auto` | Set type of progress output (`auto`, `none`, `plain`, `quiet`, `rawjson`, `tty`). Use plain to show container output | | `--provenance` | `string` | | Shorthand for `--attest=type=provenance` | | `--pull` | `bool` | | Always attempt to pull all referenced images | -| `--push` | `bool` | | Shorthand for `--output=type=registry` | +| `--push` | `bool` | | Shorthand for `--output=type=registry,unpack=false` | | `-q`, `--quiet` | `bool` | | Suppress the build output and print image ID on success | | `--sbom` | `string` | | Shorthand for `--attest=type=sbom` | | `--secret` | `stringArray` | | Secret to expose to the build (format: `id=mysecret[,src=/local/secret]`) |