From 2c69fc3d4d910489c606f8e932c037f015182522 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 1 Jul 2025 10:35:39 +0200 Subject: [PATCH 01/16] pkg/compose: remove redundant uses of strslice.StrSlice The strslice.StrSlice type is a string-slice with a custom JSON Unmarshal function to provide backward-compatibility with older API requests (see [moby@17d6f00] and [moby@ea4a067]). Given that the type is assigned implicitly through the fields on HostConfig, we can just use a regular []string instead. [moby@17d6f00]: https://github.com/moby/moby/commit/17d6f00ec2b8b9636f0bb64c55a5b3855e8f4bae [moby@ea4a067]: https://github.com/moby/moby/commit/ea4a06740b6d4579f77507c1d7e0897a870fd72d Signed-off-by: Sebastiaan van Stijn --- pkg/compose/create.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pkg/compose/create.go b/pkg/compose/create.go index 8e30c02204c..e2fe3c6a6cb 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -36,7 +36,6 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" - "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/api/types/versions" volumetypes "github.com/docker/docker/api/types/volume" "github.com/docker/go-connections/nat" @@ -181,15 +180,12 @@ func (s *composeService) getCreateConfigs(ctx context.Context, return createConfigs{}, err } - var ( - runCmd strslice.StrSlice - entrypoint strslice.StrSlice - ) + var runCmd, entrypoint []string if service.Command != nil { - runCmd = strslice.StrSlice(service.Command) + runCmd = service.Command } if service.Entrypoint != nil { - entrypoint = strslice.StrSlice(service.Entrypoint) + entrypoint = service.Entrypoint } var ( @@ -286,8 +282,8 @@ func (s *composeService) getCreateConfigs(ctx context.Context, Annotations: service.Annotations, Binds: binds, Mounts: mounts, - CapAdd: strslice.StrSlice(service.CapAdd), - CapDrop: strslice.StrSlice(service.CapDrop), + CapAdd: service.CapAdd, + CapDrop: service.CapDrop, NetworkMode: networkMode, Init: service.Init, IpcMode: container.IpcMode(service.Ipc), From 6fa173124a5d1e9fe2768e79339880d8b653ea9d Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 16 Jun 2025 11:38:07 +0200 Subject: [PATCH 02/16] (reactoring) avoid a global variable by introducing logConsumer decorator Signed-off-by: Nicolas De Loof --- cmd/formatter/logs.go | 36 +++++++++++++++++----- cmd/formatter/shortcut.go | 45 ++++++++++++++-------------- internal/tracing/keyboard_metrics.go | 5 +--- pkg/compose/up.go | 29 +++++++++++------- pkg/compose/watch.go | 4 +-- 5 files changed, 73 insertions(+), 46 deletions(-) diff --git a/cmd/formatter/logs.go b/cmd/formatter/logs.go index a5abf028e42..db8fa885cc3 100644 --- a/cmd/formatter/logs.go +++ b/cmd/formatter/logs.go @@ -118,10 +118,6 @@ func (l *logConsumer) write(w io.Writer, container, message string) { if l.ctx.Err() != nil { return } - if KeyboardManager != nil { - KeyboardManager.ClearKeyboardInfo() - } - p := l.getPresenter(container) timestamp := time.Now().Format(jsonmessage.RFC3339NanoFixed) for _, line := range strings.Split(message, "\n") { @@ -131,10 +127,6 @@ func (l *logConsumer) write(w io.Writer, container, message string) { _, _ = fmt.Fprintf(w, "%s%s\n", p.prefix, line) } } - - if KeyboardManager != nil { - KeyboardManager.PrintKeyboardInfo() - } } func (l *logConsumer) Status(container, msg string) { @@ -168,3 +160,31 @@ func (p *presenter) setPrefix(width int) { } p.prefix = p.colors(fmt.Sprintf("%-"+strconv.Itoa(width)+"s | ", p.name)) } + +type logDecorator struct { + decorated api.LogConsumer + Before func() + After func() +} + +func (l logDecorator) Log(containerName, message string) { + l.Before() + l.decorated.Log(containerName, message) + l.After() +} + +func (l logDecorator) Err(containerName, message string) { + l.Before() + l.decorated.Err(containerName, message) + l.After() +} + +func (l logDecorator) Status(container, msg string) { + l.Before() + l.decorated.Status(container, msg) + l.After() +} + +func (l logDecorator) Register(container string) { + l.decorated.Register(container) +} diff --git a/cmd/formatter/shortcut.go b/cmd/formatter/shortcut.go index b16fda855bc..7776e5f1ea1 100644 --- a/cmd/formatter/shortcut.go +++ b/cmd/formatter/shortcut.go @@ -22,7 +22,6 @@ import ( "fmt" "math" "os" - "reflect" "syscall" "time" @@ -70,12 +69,12 @@ func (ke *KeyboardError) error() string { } type KeyboardWatch struct { - Watching bool - Watcher Toggle - IsConfigured bool + Watching bool + Watcher Feature } -type Toggle interface { +// Feature is an compose feature that can be started/stopped by a menu command +type Feature interface { Start(context.Context) error Stop() error } @@ -90,31 +89,26 @@ const ( type LogKeyboard struct { kError KeyboardError - Watch KeyboardWatch + Watch *KeyboardWatch IsDockerDesktopActive bool logLevel KEYBOARD_LOG_LEVEL signalChannel chan<- os.Signal } -// FIXME(ndeloof) we should avoid use of such a global reference. see use in logConsumer -var KeyboardManager *LogKeyboard - -func NewKeyboardManager(isDockerDesktopActive bool, sc chan<- os.Signal, w bool, watcher Toggle) *LogKeyboard { - KeyboardManager = &LogKeyboard{ - Watch: KeyboardWatch{ - Watching: w, - Watcher: watcher, - IsConfigured: !reflect.ValueOf(watcher).IsNil(), - }, +func NewKeyboardManager(isDockerDesktopActive bool, sc chan<- os.Signal) *LogKeyboard { + return &LogKeyboard{ IsDockerDesktopActive: isDockerDesktopActive, logLevel: INFO, signalChannel: sc, } - return KeyboardManager } -func (lk *LogKeyboard) ClearKeyboardInfo() { - lk.clearNavigationMenu() +func (lk *LogKeyboard) Decorate(l api.LogConsumer) api.LogConsumer { + return logDecorator{ + decorated: l, + Before: lk.clearNavigationMenu, + After: lk.PrintKeyboardInfo, + } } func (lk *LogKeyboard) PrintKeyboardInfo() { @@ -185,7 +179,7 @@ func (lk *LogKeyboard) navigationMenu() string { watchInfo = navColor(" ") } isEnabled := " Enable" - if lk.Watch.Watching { + if lk.Watch != nil && lk.Watch.Watching { isEnabled = " Disable" } watchInfo = watchInfo + shortcutKeyColor("w") + navColor(isEnabled+" Watch") @@ -268,7 +262,7 @@ func (lk *LogKeyboard) keyboardError(prefix string, err error) { } func (lk *LogKeyboard) ToggleWatch(ctx context.Context, options api.UpOptions) { - if !lk.Watch.IsConfigured { + if lk.Watch == nil { return } if lk.Watch.Watching { @@ -299,7 +293,7 @@ func (lk *LogKeyboard) HandleKeyEvents(ctx context.Context, event keyboard.KeyEv case 'v': lk.openDockerDesktop(ctx, project) case 'w': - if !lk.Watch.IsConfigured { + if lk.Watch == nil { // we try to open watch docs if DD is installed if lk.IsDockerDesktopActive { lk.openDDWatchDocs(ctx, project) @@ -333,6 +327,13 @@ func (lk *LogKeyboard) HandleKeyEvents(ctx context.Context, event keyboard.KeyEv } } +func (lk *LogKeyboard) EnableWatch(enabled bool, watcher Feature) { + lk.Watch = &KeyboardWatch{ + Watching: enabled, + Watcher: watcher, + } +} + func allocateSpace(lines int) { for i := 0; i < lines; i++ { ClearLine() diff --git a/internal/tracing/keyboard_metrics.go b/internal/tracing/keyboard_metrics.go index 4043de8b787..2e5120fbea7 100644 --- a/internal/tracing/keyboard_metrics.go +++ b/internal/tracing/keyboard_metrics.go @@ -22,15 +22,12 @@ import ( "go.opentelemetry.io/otel/attribute" ) -func KeyboardMetrics(ctx context.Context, enabled, isDockerDesktopActive, isWatchConfigured bool) { +func KeyboardMetrics(ctx context.Context, enabled, isDockerDesktopActive bool) { commandAvailable := []string{} if isDockerDesktopActive { commandAvailable = append(commandAvailable, "gui") commandAvailable = append(commandAvailable, "gui/composeview") } - if isWatchConfigured { - commandAvailable = append(commandAvailable, "watch") - } AddAttributeToSpan(ctx, attribute.Bool("navmenu.enabled", enabled), diff --git a/pkg/compose/up.go b/pkg/compose/up.go index 70ac9f917e3..93dc7e78e48 100644 --- a/pkg/compose/up.go +++ b/pkg/compose/up.go @@ -70,15 +70,12 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(signalChan) var isTerminated atomic.Bool - printer := newLogPrinter(options.Start.Attach) - watcher, err := NewWatcher(project, options, s.watch) - if err != nil && options.Start.Watch { - return err - } - - var navigationMenu *formatter.LogKeyboard - var kEvents <-chan keyboard.KeyEvent + var ( + logConsumer = options.Start.Attach + navigationMenu *formatter.LogKeyboard + kEvents <-chan keyboard.KeyEvent + ) if options.Start.NavigationMenu { kEvents, err = keyboard.GetKeys(100) if err != nil { @@ -87,11 +84,23 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options } else { defer keyboard.Close() //nolint:errcheck isDockerDesktopActive := s.isDesktopIntegrationActive() - tracing.KeyboardMetrics(ctx, options.Start.NavigationMenu, isDockerDesktopActive, watcher != nil) - navigationMenu = formatter.NewKeyboardManager(isDockerDesktopActive, signalChan, options.Start.Watch, watcher) + tracing.KeyboardMetrics(ctx, options.Start.NavigationMenu, isDockerDesktopActive) + navigationMenu = formatter.NewKeyboardManager(isDockerDesktopActive, signalChan) + logConsumer = navigationMenu.Decorate(logConsumer) } } + watcher, err := NewWatcher(project, options, s.watch, logConsumer) + if err != nil && options.Start.Watch { + return err + } + + if navigationMenu != nil && watcher != nil { + navigationMenu.EnableWatch(options.Start.Watch, watcher) + } + + printer := newLogPrinter(logConsumer) + doneCh := make(chan bool) eg.Go(func() error { first := true diff --git a/pkg/compose/watch.go b/pkg/compose/watch.go index 9f9b3a1e8d8..80ed42acd1c 100644 --- a/pkg/compose/watch.go +++ b/pkg/compose/watch.go @@ -55,7 +55,7 @@ type Watcher struct { errCh chan error } -func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc) (*Watcher, error) { +func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc, consumer api.LogConsumer) (*Watcher, error) { for i := range project.Services { service := project.Services[i] @@ -65,7 +65,7 @@ func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc) (*Wa return &Watcher{ project: project, options: api.WatchOptions{ - LogTo: options.Start.Attach, + LogTo: consumer, Build: build, }, watchFn: w, From 674e13fb6d435e9b076e073511e2bad6a26d8732 Mon Sep 17 00:00:00 2001 From: Guillaume Lours <705411+glours@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:38:40 +0200 Subject: [PATCH 03/16] bump golang to v1.23.10 Fix Vulnerability Report: GO-2025-3751 Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com> --- Dockerfile | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 038f7df9925..3f24b414ce5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG GO_VERSION=1.23.8 +ARG GO_VERSION=1.23.10 ARG XX_VERSION=1.6.1 ARG GOLANGCI_LINT_VERSION=v2.0.2 ARG ADDLICENSE_VERSION=v1.0.0 diff --git a/go.mod b/go.mod index e418cadb62f..5e2b37e8b58 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/docker/compose/v2 -go 1.23.8 +go 1.23.10 require ( github.com/AlecAivazis/survey/v2 v2.3.7 From 1570c6c07617712de859c439dd0c97ce9caa868c Mon Sep 17 00:00:00 2001 From: Guillaume Lours <705411+glours@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:42:59 +0200 Subject: [PATCH 04/16] bump go-viper/mapstructure to version v2.3.0 Fix https://github.com/advisories/GHSA-fv92-fjc5-jj9h Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5e2b37e8b58..01edae0d953 100644 --- a/go.mod +++ b/go.mod @@ -103,7 +103,7 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-viper/mapstructure/v2 v2.0.0 // indirect + github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect diff --git a/go.sum b/go.sum index 93f1314f2bb..2ffc41a6dcf 100644 --- a/go.sum +++ b/go.sum @@ -188,8 +188,8 @@ github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc= -github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= +github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From b046a5ef72698b8551542836e18ae11d99e1f2ab Mon Sep 17 00:00:00 2001 From: mountdisk Date: Mon, 30 Jun 2025 14:42:35 +0800 Subject: [PATCH 05/16] chore: fix some minor issues in the comments Signed-off-by: mountdisk --- internal/sync/tar.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/sync/tar.go b/internal/sync/tar.go index 64c65faf629..1abec82dbb7 100644 --- a/internal/sync/tar.go +++ b/internal/sync/tar.go @@ -229,7 +229,7 @@ func (a *ArchiveBuilder) writeEntry(entry archiveEntry) error { return nil } -// tarPath writes the given source path into tarWriter at the given dest (recursively for directories). +// entriesForPath writes the given source path into tarWriter at the given dest (recursively for directories). // e.g. tarring my_dir --> dest d: d/file_a, d/file_b // If source path does not exist, quietly skips it and returns no err func (a *ArchiveBuilder) entriesForPath(localPath, containerPath string) ([]archiveEntry, error) { From f42374bb18b696a0dc9777f70fd64a15fd1371b7 Mon Sep 17 00:00:00 2001 From: Guillaume Lours <705411+glours@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:12:20 +0200 Subject: [PATCH 06/16] add a Done event to model progress display Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com> --- pkg/compose/model.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/compose/model.go b/pkg/compose/model.go index 68e1d425c99..6bde75a70a5 100644 --- a/pkg/compose/model.go +++ b/pkg/compose/model.go @@ -83,20 +83,25 @@ func (s *composeService) ensureModels(ctx context.Context, project *types.Projec config.Name = name } eg.Go(func() error { + w := progress.ContextWriter(gctx) if !slices.Contains(availableModels, config.Model) { - err = s.pullModel(gctx, dockerModel, config, quietPull) + err = s.pullModel(gctx, dockerModel, config, quietPull, w) if err != nil { return err } } - return s.configureModel(gctx, dockerModel, config) + err = s.configureModel(gctx, dockerModel, config, w) + if err != nil { + return err + } + w.Event(progress.CreatedEvent(config.Name)) + return nil }) } return eg.Wait() } -func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plugin, model types.ModelConfig, quietPull bool) error { - w := progress.ContextWriter(ctx) +func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plugin, model types.ModelConfig, quietPull bool, w progress.Writer) error { w.Event(progress.Event{ ID: model.Name, Status: progress.Working, @@ -145,7 +150,12 @@ func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plu return err } -func (s *composeService) configureModel(ctx context.Context, dockerModel *manager.Plugin, config types.ModelConfig) error { +func (s *composeService) configureModel(ctx context.Context, dockerModel *manager.Plugin, config types.ModelConfig, w progress.Writer) error { + w.Event(progress.Event{ + ID: config.Name, + Status: progress.Working, + Text: "Configuring", + }) // configure [--context-size=] MODEL [-- ] args := []string{"configure"} if config.ContextSize > 0 { From 3b0601b6713dce253ddda54b56f0498a21af2926 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 09:37:19 +0000 Subject: [PATCH 07/16] build(deps): bump github.com/moby/buildkit from 0.23.1 to 0.23.2 Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.23.1 to 0.23.2. - [Release notes](https://github.com/moby/buildkit/releases) - [Commits](https://github.com/moby/buildkit/compare/v0.23.1...v0.23.2) --- updated-dependencies: - dependency-name: github.com/moby/buildkit dependency-version: 0.23.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 01edae0d953..2148936ccca 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/mattn/go-shellwords v1.0.12 github.com/mitchellh/go-ps v1.0.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/moby/buildkit v0.23.1 + github.com/moby/buildkit v0.23.2 github.com/moby/go-archive v0.1.0 github.com/moby/patternmatcher v0.6.0 github.com/moby/sys/atomicwriter v0.1.0 diff --git a/go.sum b/go.sum index 2ffc41a6dcf..e1fc4b0df45 100644 --- a/go.sum +++ b/go.sum @@ -317,8 +317,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/z github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/buildkit v0.23.1 h1:CZtFmPRF+IFG1C8QfPnktGO1Dzzt5JSwtQ5eDqIh+ag= -github.com/moby/buildkit v0.23.1/go.mod h1:keNXljNmKX1T0AtM0bMObc8OV6mA9cOuquVbPcRpU/Y= +github.com/moby/buildkit v0.23.2 h1:gt/dkfcpgTXKx+B9I310kV767hhVqTvEyxGgI3mqsGQ= +github.com/moby/buildkit v0.23.2/go.mod h1:iEjAfPQKIuO+8y6OcInInvzqTMiKMbb2RdJz1K/95a0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= From 8faf1eb808ac11d16a91d32c85ac58c066ac9ca7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 09:23:07 +0000 Subject: [PATCH 08/16] build(deps): bump github.com/docker/cli Bumps [github.com/docker/cli](https://github.com/docker/cli) from 28.3.0+incompatible to 28.3.1+incompatible. - [Commits](https://github.com/docker/cli/compare/v28.3.0...v28.3.1) --- updated-dependencies: - dependency-name: github.com/docker/cli dependency-version: 28.3.1+incompatible dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2148936ccca..f8e3e54c325 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/distribution/reference v0.6.0 github.com/docker/buildx v0.25.0 - github.com/docker/cli v28.3.0+incompatible + github.com/docker/cli v28.3.1+incompatible github.com/docker/cli-docs-tool v0.10.0 github.com/docker/docker v28.3.0+incompatible github.com/docker/go-connections v0.5.0 diff --git a/go.sum b/go.sum index e1fc4b0df45..d826d8e8570 100644 --- a/go.sum +++ b/go.sum @@ -129,8 +129,8 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docker/buildx v0.25.0 h1:qs5WxBo0wQKSXcQ+v6UhWaeM2Pu+95ZCymaimRzInaE= github.com/docker/buildx v0.25.0/go.mod h1:xJcOeBhz49tgqN174MMGuOU4bxNmgfaLnZn7Gm641EE= -github.com/docker/cli v28.3.0+incompatible h1:s+ttruVLhB5ayeuf2BciwDVxYdKi+RoUlxmwNHV3Vfo= -github.com/docker/cli v28.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v28.3.1+incompatible h1:ZUdwOLDEBoE3TE5rdC9IXGY5HPHksJK3M+hJEWhh2mc= +github.com/docker/cli v28.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli-docs-tool v0.10.0 h1:bOD6mKynPQgojQi3s2jgcUWGp/Ebqy1SeCr9VfKQLLU= github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09fzRHP4aX1qwp1U= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= From 60ee6adcd2ed505749e7710a85b3d752bfe6c6ff Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 2 Jul 2025 10:18:41 +0200 Subject: [PATCH 09/16] a single place for shell-out command setup Signed-off-by: Nicolas De Loof --- pkg/compose/build_bake.go | 39 ++----------------------- pkg/compose/model.go | 52 ++++++++++++++------------------- pkg/compose/plugins.go | 34 ++++------------------ pkg/compose/shellout.go | 61 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 94 deletions(-) create mode 100644 pkg/compose/shellout.go diff --git a/pkg/compose/build_bake.go b/pkg/compose/build_bake.go index 58626990d3f..95a02c6e940 100644 --- a/pkg/compose/build_bake.go +++ b/pkg/compose/build_bake.go @@ -34,7 +34,6 @@ import ( "github.com/compose-spec/compose-go/v2/types" "github.com/docker/cli/cli-plugins/manager" - "github.com/docker/cli/cli-plugins/socket" "github.com/docker/cli/cli/command" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/progress" @@ -45,8 +44,6 @@ import ( "github.com/moby/buildkit/util/progress/progressui" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/propagation" "golang.org/x/sync/errgroup" ) @@ -294,26 +291,12 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project logrus.Debugf("Executing bake with args: %v", args) cmd := exec.CommandContext(ctx, buildx.Path, args...) - // Remove DOCKER_CLI_PLUGIN... variable so buildx can detect it run standalone - cmd.Env = filter(project.Environment.Values(), manager.ReexecEnvvar) - // Use docker/cli mechanism to propagate termination signal to child process - server, err := socket.NewPluginServer(nil) - if err == nil { - defer server.Close() //nolint:errcheck - cmd.Env = replace(cmd.Env, socket.EnvKey, server.Addr().String()) + err = s.prepareShellOut(ctx, project, cmd) + if err != nil { + return nil, err } - cmd.Env = append(cmd.Env, - fmt.Sprintf("DOCKER_CONTEXT=%s", s.dockerCli.CurrentContext()), - fmt.Sprintf("DOCKER_HOST=%s", s.dockerCli.DockerEndpoint().Host), - ) - - // propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md - carrier := propagation.MapCarrier{} - otel.GetTextMapPropagator().Inject(ctx, &carrier) - cmd.Env = append(cmd.Env, types.Mapping(carrier).Values()...) - cmd.Stdout = s.stdout() cmd.Stdin = bytes.NewBuffer(b) pipe, err := cmd.StderrPipe() @@ -443,22 +426,6 @@ func toBakeSecrets(project *types.Project, secrets []types.ServiceSecretConfig) return s } -func filter(environ []string, variable string) []string { - prefix := variable + "=" - filtered := make([]string, 0, len(environ)) - for _, val := range environ { - if !strings.HasPrefix(val, prefix) { - filtered = append(filtered, val) - } - } - return filtered -} - -func replace(environ []string, variable, value string) []string { - filtered := filter(environ, variable) - return append(filtered, fmt.Sprintf("%s=%s", variable, value)) -} - func dockerFilePath(ctxName string, dockerfile string) string { if dockerfile == "" { return "" diff --git a/pkg/compose/model.go b/pkg/compose/model.go index 6bde75a70a5..4c88b1a85a4 100644 --- a/pkg/compose/model.go +++ b/pkg/compose/model.go @@ -21,7 +21,6 @@ import ( "context" "encoding/json" "fmt" - "os" "os/exec" "slices" "strconv" @@ -32,8 +31,6 @@ import ( "github.com/docker/cli/cli-plugins/manager" "github.com/docker/compose/v2/pkg/progress" "github.com/spf13/cobra" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/propagation" "golang.org/x/sync/errgroup" ) @@ -51,7 +48,11 @@ func (s *composeService) ensureModels(ctx context.Context, project *types.Projec } cmd := exec.CommandContext(ctx, dockerModel.Path, "ls", "--json") - s.setupChildProcess(ctx, cmd) + err = s.prepareShellOut(ctx, project, cmd) + if err != nil { + return err + } + output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("error checking available models: %w", err) @@ -85,23 +86,18 @@ func (s *composeService) ensureModels(ctx context.Context, project *types.Projec eg.Go(func() error { w := progress.ContextWriter(gctx) if !slices.Contains(availableModels, config.Model) { - err = s.pullModel(gctx, dockerModel, config, quietPull, w) + err = s.pullModel(gctx, dockerModel, project, config, quietPull, w) if err != nil { return err } } - err = s.configureModel(gctx, dockerModel, config, w) - if err != nil { - return err - } - w.Event(progress.CreatedEvent(config.Name)) - return nil + return s.configureModel(gctx, dockerModel, project, config, w) }) } return eg.Wait() } -func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plugin, model types.ModelConfig, quietPull bool, w progress.Writer) error { +func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plugin, project *types.Project, model types.ModelConfig, quietPull bool, w progress.Writer) error { w.Event(progress.Event{ ID: model.Name, Status: progress.Working, @@ -109,8 +105,10 @@ func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plu }) cmd := exec.CommandContext(ctx, dockerModel.Path, "pull", model.Model) - s.setupChildProcess(ctx, cmd) - + err := s.prepareShellOut(ctx, project, cmd) + if err != nil { + return err + } stream, err := cmd.StdoutPipe() if err != nil { return err @@ -150,7 +148,7 @@ func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plu return err } -func (s *composeService) configureModel(ctx context.Context, dockerModel *manager.Plugin, config types.ModelConfig, w progress.Writer) error { +func (s *composeService) configureModel(ctx context.Context, dockerModel *manager.Plugin, project *types.Project, config types.ModelConfig, w progress.Writer) error { w.Event(progress.Event{ ID: config.Name, Status: progress.Working, @@ -167,13 +165,20 @@ func (s *composeService) configureModel(ctx context.Context, dockerModel *manage args = append(args, config.RuntimeFlags...) } cmd := exec.CommandContext(ctx, dockerModel.Path, args...) - s.setupChildProcess(ctx, cmd) + err := s.prepareShellOut(ctx, project, cmd) + if err != nil { + return err + } return cmd.Run() } func (s *composeService) setModelVariables(ctx context.Context, dockerModel *manager.Plugin, project *types.Project) error { cmd := exec.CommandContext(ctx, dockerModel.Path, "status", "--json") - s.setupChildProcess(ctx, cmd) + err := s.prepareShellOut(ctx, project, cmd) + if err != nil { + return err + } + statusOut, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("error checking docker-model status: %w", err) @@ -211,19 +216,6 @@ func (s *composeService) setModelVariables(ctx context.Context, dockerModel *man return nil } -func (s *composeService) setupChildProcess(gctx context.Context, cmd *exec.Cmd) { - // exec provider command with same environment Compose is running - env := types.NewMapping(os.Environ()) - // but remove DOCKER_CLI_PLUGIN... variable so plugin can detect it run standalone - delete(env, manager.ReexecEnvvar) - // propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md - carrier := propagation.MapCarrier{} - otel.GetTextMapPropagator().Inject(gctx, &carrier) - env.Merge(types.Mapping(carrier)) - env["DOCKER_CONTEXT"] = s.dockerCli.CurrentContext() - cmd.Env = env.Values() -} - type Model struct { Id string `json:"id"` Tags []string `json:"tags"` diff --git a/pkg/compose/plugins.go b/pkg/compose/plugins.go index 7ddf0b1f2de..f49c18f990f 100644 --- a/pkg/compose/plugins.go +++ b/pkg/compose/plugins.go @@ -29,16 +29,12 @@ import ( "strings" "sync" - "github.com/docker/compose/v2/pkg/progress" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/propagation" - "github.com/compose-spec/compose-go/v2/types" "github.com/docker/cli/cli-plugins/manager" - "github.com/docker/cli/cli-plugins/socket" "github.com/docker/cli/cli/config" + "github.com/docker/compose/v2/pkg/progress" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) type JsonMessage struct { @@ -199,29 +195,11 @@ func (s *composeService) setupPluginCommand(ctx context.Context, project *types. args = append(args, service.Name) cmd := exec.CommandContext(ctx, path, args...) - // exec provider command with same environment Compose is running - env := types.NewMapping(os.Environ()) - // but remove DOCKER_CLI_PLUGIN... variable so plugin can detect it run standalone - delete(env, manager.ReexecEnvvar) - // and add the explicit environment variables set for service - for key, val := range service.Environment.RemoveEmpty().ToMapping() { - env[key] = val - } - cmd.Env = env.Values() - // Use docker/cli mechanism to propagate termination signal to child process - server, err := socket.NewPluginServer(nil) - if err == nil { - defer server.Close() //nolint:errcheck - cmd.Env = replace(cmd.Env, socket.EnvKey, server.Addr().String()) + err := s.prepareShellOut(ctx, project, cmd) + if err != nil { + return nil, err } - - cmd.Env = append(cmd.Env, fmt.Sprintf("DOCKER_CONTEXT=%s", s.dockerCli.CurrentContext())) - - // propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md - carrier := propagation.MapCarrier{} - otel.GetTextMapPropagator().Inject(ctx, &carrier) - cmd.Env = append(cmd.Env, types.Mapping(carrier).Values()...) return cmd, nil } diff --git a/pkg/compose/shellout.go b/pkg/compose/shellout.go new file mode 100644 index 00000000000..3f8947e61af --- /dev/null +++ b/pkg/compose/shellout.go @@ -0,0 +1,61 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package compose + +import ( + "context" + "os/exec" + + "github.com/compose-spec/compose-go/v2/types" + "github.com/docker/cli/cli-plugins/manager" + "github.com/docker/cli/cli/context/docker" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" +) + +// prepareShellOut prepare a shell-out command to be ran by Compose +func (s *composeService) prepareShellOut(gctx context.Context, project *types.Project, cmd *exec.Cmd) error { + // exec command with same environment Compose is running + env := types.NewMapping(project.Environment.Values()) + + // remove DOCKER_CLI_PLUGIN... variable so a docker-cli plugin will detect it run standalone + delete(env, manager.ReexecEnvvar) + + // propagate opentelemetry context to child process, see https://github.com/open-telemetry/oteps/blob/main/text/0258-env-context-baggage-carriers.md + carrier := propagation.MapCarrier{} + otel.GetTextMapPropagator().Inject(gctx, &carrier) + env.Merge(types.Mapping(carrier)) + + env["DOCKER_CONTEXT"] = s.dockerCli.CurrentContext() + + metadata, err := s.dockerCli.ContextStore().GetMetadata(s.dockerCli.CurrentContext()) + if err != nil { + return err + } + endpoint, err := docker.EndpointFromContext(metadata) + if err != nil { + return err + } + actualHost := s.dockerCli.DockerEndpoint().Host + if endpoint.Host != actualHost { + // We are running with `--host` or `DOCKER_HOST` which overrides selected context + env["DOCKER_HOST"] = actualHost + } + + cmd.Env = env.Values() + return nil +} From c626befee1596abcc74578cb10dd96ae1667f76f Mon Sep 17 00:00:00 2001 From: Guillaume Lours <705411+glours@users.noreply.github.com> Date: Thu, 3 Jul 2025 17:48:14 +0200 Subject: [PATCH 10/16] fix the way we're checking if the provider metadata are empty or not Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com> --- pkg/compose/plugins.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pkg/compose/plugins.go b/pkg/compose/plugins.go index f49c18f990f..6e5224af505 100644 --- a/pkg/compose/plugins.go +++ b/pkg/compose/plugins.go @@ -170,7 +170,7 @@ func (s *composeService) getPluginBinaryPath(provider string) (path string, err } func (s *composeService) setupPluginCommand(ctx context.Context, project *types.Project, service types.ServiceConfig, path, command string) (*exec.Cmd, error) { - cmdOptionsMetadata := s.getPluginMetadata(path, service.Provider.Type) + cmdOptionsMetadata := s.getPluginMetadata(path, service.Provider.Type, project) var currentCommandMetadata CommandMetadata switch command { case "up": @@ -178,8 +178,9 @@ func (s *composeService) setupPluginCommand(ctx context.Context, project *types. case "down": currentCommandMetadata = cmdOptionsMetadata.Down } - commandMetadataIsEmpty := len(currentCommandMetadata.Parameters) == 0 + provider := *service.Provider + commandMetadataIsEmpty := cmdOptionsMetadata.IsEmpty() if err := currentCommandMetadata.CheckRequiredParameters(provider); !commandMetadataIsEmpty && err != nil { return nil, err } @@ -203,8 +204,13 @@ func (s *composeService) setupPluginCommand(ctx context.Context, project *types. return cmd, nil } -func (s *composeService) getPluginMetadata(path, command string) ProviderMetadata { +func (s *composeService) getPluginMetadata(path, command string, project *types.Project) ProviderMetadata { cmd := exec.Command(path, "compose", "metadata") + err := s.prepareShellOut(context.Background(), project, cmd) + if err != nil { + logrus.Debugf("failed to prepare plugin metadata command: %v", err) + return ProviderMetadata{} + } stdout := &bytes.Buffer{} cmd.Stdout = stdout @@ -239,6 +245,10 @@ type ProviderMetadata struct { Down CommandMetadata `json:"down"` } +func (p ProviderMetadata) IsEmpty() bool { + return p.Description == "" && p.Up.Parameters == nil && p.Down.Parameters == nil +} + type CommandMetadata struct { Parameters []ParameterMetadata `json:"parameters"` } From 66524e77287e10b7b4bf82ca39b8cfffd84c526f Mon Sep 17 00:00:00 2001 From: MohammadHasan Akbari Date: Sun, 6 Jul 2025 15:41:55 +0000 Subject: [PATCH 11/16] feat: add --networks flag to config command Signed-off-by: MohammadHasan Akbari --- cmd/compose/config.go | 16 ++++++++++++++++ docs/reference/compose_config.md | 1 + docs/reference/docker_compose_config.yaml | 10 ++++++++++ 3 files changed, 27 insertions(+) diff --git a/cmd/compose/config.go b/cmd/compose/config.go index 3cb969108e9..35497829563 100644 --- a/cmd/compose/config.go +++ b/cmd/compose/config.go @@ -50,6 +50,7 @@ type configOptions struct { noResolveEnv bool services bool volumes bool + networks bool profiles bool images bool hash string @@ -111,6 +112,9 @@ func configCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command { if opts.volumes { return runVolumes(ctx, dockerCli, opts) } + if opts.networks { + return runNetworks(ctx, dockerCli, opts) + } if opts.hash != "" { return runHash(ctx, dockerCli, opts) } @@ -147,6 +151,7 @@ func configCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command { flags.BoolVar(&opts.services, "services", false, "Print the service names, one per line.") flags.BoolVar(&opts.volumes, "volumes", false, "Print the volume names, one per line.") + flags.BoolVar(&opts.networks, "networks", false, "Print the network names, one per line.") flags.BoolVar(&opts.profiles, "profiles", false, "Print the profile names, one per line.") flags.BoolVar(&opts.images, "images", false, "Print the image names, one per line.") flags.StringVar(&opts.hash, "hash", "", "Print the service config hash, one per line.") @@ -367,6 +372,17 @@ func runVolumes(ctx context.Context, dockerCli command.Cli, opts configOptions) return nil } +func runNetworks(ctx context.Context, dockerCli command.Cli, opts configOptions) error { + project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution) + if err != nil { + return err + } + for n := range project.Networks { + _, _ = fmt.Fprintln(dockerCli.Out(), n) + } + return nil +} + func runHash(ctx context.Context, dockerCli command.Cli, opts configOptions) error { var services []string if opts.hash != "*" { diff --git a/docs/reference/compose_config.md b/docs/reference/compose_config.md index 3ec2d4864af..854eafe2168 100644 --- a/docs/reference/compose_config.md +++ b/docs/reference/compose_config.md @@ -15,6 +15,7 @@ the canonical format. | `--hash` | `string` | | Print the service config hash, one per line. | | `--images` | `bool` | | Print the image names, one per line. | | `--lock-image-digests` | `bool` | | Produces an override file with image digests | +| `--networks` | `bool` | | Print the network names, one per line. | | `--no-consistency` | `bool` | | Don't check model consistency - warning: may produce invalid Compose output | | `--no-env-resolution` | `bool` | | Don't resolve service env files | | `--no-interpolate` | `bool` | | Don't interpolate environment variables | diff --git a/docs/reference/docker_compose_config.yaml b/docs/reference/docker_compose_config.yaml index 080fe6748e6..b95c58c279a 100644 --- a/docs/reference/docker_compose_config.yaml +++ b/docs/reference/docker_compose_config.yaml @@ -56,6 +56,16 @@ options: experimentalcli: false kubernetes: false swarm: false + - option: networks + value_type: bool + default_value: "false" + description: Print the network names, one per line. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false - option: no-consistency value_type: bool default_value: "false" From 0e0ed91a3961af9f83aa1a19de2776678952195f Mon Sep 17 00:00:00 2001 From: MohammadHasan Akbari Date: Mon, 7 Jul 2025 07:41:22 +0000 Subject: [PATCH 12/16] fix: lint errors Signed-off-by: MohammadHasan Akbari --- cmd/compose/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/compose/config.go b/cmd/compose/config.go index 35497829563..d4d6c01ec46 100644 --- a/cmd/compose/config.go +++ b/cmd/compose/config.go @@ -50,7 +50,7 @@ type configOptions struct { noResolveEnv bool services bool volumes bool - networks bool + networks bool profiles bool images bool hash string From 7cf7c6414f5681ba0dbd596e15d9c4d64ddda41c Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 7 Jul 2025 15:01:15 +0200 Subject: [PATCH 13/16] build resolves enabled service after project has been loaded Signed-off-by: Nicolas De Loof --- cmd/compose/build.go | 1 + pkg/e2e/build_test.go | 12 ++++++++++++ .../fixtures/build-test/profiles/Dockerfile | 19 +++++++++++++++++++ .../fixtures/build-test/profiles/compose.yaml | 12 ++++++++++++ .../build-test/profiles/test-secret.txt | 1 + 5 files changed, 45 insertions(+) create mode 100644 pkg/e2e/fixtures/build-test/profiles/Dockerfile create mode 100644 pkg/e2e/fixtures/build-test/profiles/compose.yaml create mode 100644 pkg/e2e/fixtures/build-test/profiles/test-secret.txt diff --git a/cmd/compose/build.go b/cmd/compose/build.go index f336893381a..e29a9d89e78 100644 --- a/cmd/compose/build.go +++ b/cmd/compose/build.go @@ -145,6 +145,7 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) } func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Service, opts buildOptions, services []string) error { + opts.All = true // do not drop resources as build may involve some dependencies by additional_contexts project, _, err := opts.ToProject(ctx, dockerCli, nil, cli.WithResolvedPaths(true), cli.WithoutEnvironmentResolution) if err != nil { return err diff --git a/pkg/e2e/build_test.go b/pkg/e2e/build_test.go index 0449a46e733..202e2d88d57 100644 --- a/pkg/e2e/build_test.go +++ b/pkg/e2e/build_test.go @@ -596,3 +596,15 @@ func TestBuildLongOutputLine(t *testing.T) { out = res.Combined() assert.Check(t, strings.Contains(out, "long-line Built")) } + +func TestBuildDependentImageWithProfile(t *testing.T) { + c := NewParallelCLI(t) + + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "-f", "fixtures/build-test/profiles/compose.yaml", "down", "--rmi=local") + }) + + res := c.RunDockerComposeCmd(t, "-f", "fixtures/build-test/profiles/compose.yaml", "build", "secret-build-test") + out := res.Combined() + assert.Check(t, strings.Contains(out, "secret-build-test Built")) +} diff --git a/pkg/e2e/fixtures/build-test/profiles/Dockerfile b/pkg/e2e/fixtures/build-test/profiles/Dockerfile new file mode 100644 index 00000000000..94eb80e9c7d --- /dev/null +++ b/pkg/e2e/fixtures/build-test/profiles/Dockerfile @@ -0,0 +1,19 @@ +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +FROM alpine +RUN --mount=type=secret,id=test-secret ls -la /run/secrets/; cp /run/secrets/test-secret /tmp + +CMD ["cat", "/tmp/test-secret"] \ No newline at end of file diff --git a/pkg/e2e/fixtures/build-test/profiles/compose.yaml b/pkg/e2e/fixtures/build-test/profiles/compose.yaml new file mode 100644 index 00000000000..877babc0e5f --- /dev/null +++ b/pkg/e2e/fixtures/build-test/profiles/compose.yaml @@ -0,0 +1,12 @@ +secrets: + test-secret: + file: test-secret.txt + +services: + secret-build-test: + profiles: ["test"] + build: + context: . + dockerfile: Dockerfile + secrets: + - test-secret \ No newline at end of file diff --git a/pkg/e2e/fixtures/build-test/profiles/test-secret.txt b/pkg/e2e/fixtures/build-test/profiles/test-secret.txt new file mode 100644 index 00000000000..78882121907 --- /dev/null +++ b/pkg/e2e/fixtures/build-test/profiles/test-secret.txt @@ -0,0 +1 @@ +SECRET \ No newline at end of file From 69f1430a49ee89967299fd4b65520366577b27ce Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 8 Jul 2025 09:55:09 +0200 Subject: [PATCH 14/16] resolve Dockerfile symlink but file name Signed-off-by: Nicolas De Loof --- pkg/compose/build_bake.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/compose/build_bake.go b/pkg/compose/build_bake.go index 95a02c6e940..d46874dff6f 100644 --- a/pkg/compose/build_bake.go +++ b/pkg/compose/build_bake.go @@ -436,9 +436,10 @@ func dockerFilePath(ctxName string, dockerfile string) string { if !filepath.IsAbs(dockerfile) { dockerfile = filepath.Join(ctxName, dockerfile) } - symlinks, err := filepath.EvalSymlinks(dockerfile) + dir := filepath.Dir(dockerfile) + symlinks, err := filepath.EvalSymlinks(dir) if err == nil { - return symlinks + return filepath.Join(symlinks, filepath.Base(dockerfile)) } return dockerfile } From 4bbc6c609fa2cd6dbb653d629e271e0d992de6dd Mon Sep 17 00:00:00 2001 From: Guillaume Lours <705411+glours@users.noreply.github.com> Date: Tue, 8 Jul 2025 10:57:08 +0200 Subject: [PATCH 15/16] add USER_AGENT variable to cmd when shellouting Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com> --- pkg/compose/shellout.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/compose/shellout.go b/pkg/compose/shellout.go index 3f8947e61af..4c23761dcb1 100644 --- a/pkg/compose/shellout.go +++ b/pkg/compose/shellout.go @@ -23,6 +23,7 @@ import ( "github.com/compose-spec/compose-go/v2/types" "github.com/docker/cli/cli-plugins/manager" "github.com/docker/cli/cli/context/docker" + "github.com/docker/compose/v2/internal" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" ) @@ -41,6 +42,7 @@ func (s *composeService) prepareShellOut(gctx context.Context, project *types.Pr env.Merge(types.Mapping(carrier)) env["DOCKER_CONTEXT"] = s.dockerCli.CurrentContext() + env["USER_AGENT"] = "compose/" + internal.Version metadata, err := s.dockerCli.ContextStore().GetMetadata(s.dockerCli.CurrentContext()) if err != nil { From 9e17a091be5abf792fcb4c4e35a80a7cc51cbe6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 09:06:07 +0000 Subject: [PATCH 16/16] build(deps): bump github.com/docker/docker Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.3.0+incompatible to 28.3.1+incompatible. - [Release notes](https://github.com/docker/docker/releases) - [Commits](https://github.com/docker/docker/compare/v28.3.0...v28.3.1) --- updated-dependencies: - dependency-name: github.com/docker/docker dependency-version: 28.3.1+incompatible dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f8e3e54c325..590d13d0d44 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/docker/buildx v0.25.0 github.com/docker/cli v28.3.1+incompatible github.com/docker/cli-docs-tool v0.10.0 - github.com/docker/docker v28.3.0+incompatible + github.com/docker/docker v28.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/docker/go-units v0.5.0 github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 diff --git a/go.sum b/go.sum index d826d8e8570..0b996d44970 100644 --- a/go.sum +++ b/go.sum @@ -136,8 +136,8 @@ github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09f github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v28.3.0+incompatible h1:ffS62aKWupCWdvcee7nBU9fhnmknOqDPaJAMtfK0ImQ= -github.com/docker/docker v28.3.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.3.1+incompatible h1:20+BmuA9FXlCX4ByQ0vYJcUEnOmRM6XljDnFWR+jCyY= +github.com/docker/docker v28.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=