Skip to content

Add ENGINE column driven by coordinator context - #13959

Open
nicksieger wants to merge 8 commits into
docker:mainfrom
nicksieger:ps-engine-column
Open

Add ENGINE column driven by coordinator context#13959
nicksieger wants to merge 8 commits into
docker:mainfrom
nicksieger:ps-engine-column

Conversation

@nicksieger

@nicksieger nicksieger commented Jul 21, 2026

Copy link
Copy Markdown
Member

What I did

Show an ENGINE column in compose ps default table output when the
current Docker context is coordinator-enabled, using the
com.docker.compose.engine label value per row. Column is omitted
otherwise. Expose {{.Engine}} for custom --format templates.

Supports future multi-engine coordinators and workloads.

NOTE: based on #13958, wait to rebase after merging.

Related issue

(not mandatory) A picture of a cute animal, if possible in relation to what you did

Detect the `com.docker.compose.project.config` context metadata key (bool
true or string "true"); when set, POST the full project config to the
coordinator at `/v{version}/compose/project` over the engine socket dialer
at the start of `compose up`, before any other Docker API call.

- version-gated behind new apiVersionComposeProjectConfig constant
- skipped in dry-run
- non-fatal: warn and continue on request or engine error

Signed-off-by: Nick Sieger <nick@nicksieger.com>
@nicksieger
nicksieger requested review from a team as code owners July 21, 2026 21:09
@nicksieger
nicksieger requested review from glours and ndeloof July 21, 2026 21:10

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

The ENGINE column feature is clean and correct. The implementation:

  • Correctly guards against nil Labels maps in the new Engine() method — no panic risk for containers without labels
  • Only shows the ENGINE column when at least one container carries the com.docker.compose.engine label
  • The hasEngine detection loop correctly reflects the filtered container set
  • Format string construction order (ENGINE before SIZE) is internally consistent
  • New test covers the happy-path scenario

No bugs were found in the added code.

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.70588% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/coordinator/coordinator.go 92.00% 2 Missing and 2 partials ⚠️
pkg/compose/up.go 62.50% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@glours glours left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasEngine scans the filtered container set (cmd/compose/ps.go), so column presence depends on which services you name. Say svc1 carries the com.docker.compose.engine label and svc2 doesn't:

  • compose ps → ENGINE column shown (svc2 gets an empty cell)
  • compose ps svc2no ENGINE column, even though svc2's row is identical to the one just shown
  • compose ps svc1 → shown again

Same rows, different schema. That breaks table-parsing and diverges from docker ps, where columns are never data-gated.

As this is a very specific display, could we gate it on the coordinator context (the same context-metadata detection as the project-config work, living under internal/) instead of the data? Presence then stays stable across ps / ps <subset>.

Nit: api.EngineLabel (com.docker.compose.engine) collides by name with desktop.EngineLabel (com.docker.desktop.address), can we consider a more specific name?

Relocate the coordinator-specific project-config push out of pkg/compose,
which is Compose's reusable surface, into a dedicated internal/coordinator
package mirroring internal/desktop. Detection, the engine-dialer HTTP
client, the versioned URL and outcome handling now live there; up.go keeps
a thin call-site.

Bound the push with an http.Client timeout so a coordinator that accepts
the connection but never responds cannot hang "compose up", preserving the
non-fatal warn-and-continue guarantee.

Signed-off-by: Nick Sieger <nick@nicksieger.com>
@glours
glours requested a review from docker-agent July 22, 2026 15:36

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

The ENGINE column feature is well-structured. The new internal/coordinator package correctly gates the feature on Docker context metadata, the label constant matches the documented name (com.docker.compose.engine), and error paths (HTTP timeouts, non-200 responses, missing coordinator) are handled. Test coverage is present for the new coordinator logic, the formatter, and compose ps.

No high- or medium-severity bugs were found in the changed code.

http.Transport is allocated per call and discarded; without
CloseIdleConnections its persistConn goroutines linger until
IdleConnTimeout. Tear them down eagerly in the deferred cleanup.

Signed-off-by: Nick Sieger <nick@nicksieger.com>

@glours glours left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, maybe will need some refactoring depending of pending comments on #13958

Comment thread cmd/formatter/container_test.go Outdated
assert.Assert(t, strings.Contains(out.String(), "moby"), out.String())
})

t.Run("engine column hidden when no label present", func(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
t.Run("engine column hidden when no label present", func(t *testing.T) {
t.Run("engine column hidden when coordinateur disabled", func(t *testing.T) {

nicksieger and others added 4 commits July 23, 2026 10:38
Co-authored-by: Guillaume Lours <705411+glours@users.noreply.github.com>
Signed-off-by: Nick Sieger <nick@nicksieger.com>
"compose up" with no service arguments and no profiles applied resolves
the whole project; naming services narrows it to a subset (+ dependency
closure), and an applied profile disables the services outside it.
Advertise which one the coordinator received via a new
X-Compose-Project-Complete header so it can merge partial pushes with
stored config instead of treating every push as authoritative.

- mark complete only when the service selection is empty and no profile
  is active; blank profile entries (compose-go's no-profile sentinel) are
  ignored via hasActiveProfiles
- set the header explicitly (true/false); absent means older client and
  must be read as "false" so no prune is ever triggered on its behalf

Signed-off-by: Nick Sieger <nick@nicksieger.com>
Use the metadata to indicate coordinator presense, not just capable of accepting
the push project config api.

Signed-off-by: Nick Sieger <nick@nicksieger.com>
Signed-off-by: Nick Sieger <nick@nicksieger.com>
@nicksieger nicksieger changed the title Add ENGINE column driven by com.docker.compose.engine label Add ENGINE column driven by coordinator context Jul 28, 2026
Show an ENGINE column in `compose ps` default table output when the
current Docker context is coordinator-enabled (detected via the
project-config context metadata, internal/coordinator.PushEnabled),
rather than gating on which listed containers carry the engine label.
Column presence is now stable across `ps` and `ps <subset>`; per-row
value comes from the com.docker.compose.engine label. Expose
{{.Engine}} for custom --format templates.

Rename api.EngineLabel to api.ContainerEngineLabel to avoid the
name collision with desktop.EngineLabel (com.docker.desktop.address).

Signed-off-by: Nick Sieger <nick@nicksieger.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants