Commit graph

200 commits

Author SHA1 Message Date
Guillaume Lours
674010661a feat(hooks): retain failed pre_start containers for post-mortem
A failing pre_start hook container is now retained (AutoRemove: false)
so operators can run 'docker logs <id>' and 'docker ps -a' to diagnose
the failure. On success the container is removed explicitly, mirroring
the old AutoRemove behaviour including anonymous volumes.

Before each pre_start run, stale hook containers from a previous failed
run are detected via project+service+HookLabel filters and force-removed
so they do not accumulate.

Changes:
- pkg/api/labels.go: add HookLabel (com.docker.compose.hook)
- pkg/compose/filters.go: add hookFilter helper
- pkg/compose/pre_start.go:
  - AutoRemove: false in createPreStartContainer
  - HookLabel added to container labels
  - runPreStartHook: explicit ContainerRemove on success; retain on failure
  - removeOrphanPreStartContainers: new helper called in runPreStart
- Tests: update all existing pre_start tests for the new flow; add
  feature tests (success removes, failure retains, orphan cleanup) and
  coverage-gap tests (lowestNumberedContainer, waitPreStart cancel,
  preStartResultErr, streamPreStartLogs error paths, old-API network
  paths, ExecCreate/Attach/Inspect errors, hookExitError branches)

Coverage after: hook.go 100%, pre_start.go most functions 100%
(was 89% and 64% respectively per Codecov delta).

Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
2026-08-20 18:57:02 +02:00
Nicolas De Loof
5671532583 api: RunOptions documents its partial embedding and its double life as ExecOptions
RunOptions embeds CreateOptions, which suggests every creation option
applies to the one-off's dependencies; in reality only Build,
IgnoreOrphans, RemoveOrphans and QuietPull are propagated
(startDependencies builds a fresh CreateOptions from exactly those
four). Setting Recreate or Inherit on a RunOptions was a silent no-op.
The same struct also serves Exec, which honors only the exec-relevant
subset of its ~20 fields.

Both facts are now stated on the type, the embedding and the
Exec-only Index field.

Part of #14074 (B: pkg/api promises things the implementation does not
honor).

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2026-08-20 12:32:25 +02:00
Nicolas De Loof
62eb97e8e5 api: StartOptions says which half of it Start actually reads
StartOptions fuses two contracts: the fields s.start honors (Project,
AttachTo-as-project-source, Wait, WaitTimeout) and the fields only Up's
foreground session reads (Attach, OnExit, ExitCodeFrom, Watch,
NavigationMenu). Passing the latter to Start compiled, returned no
error, and did nothing.

Each session field is now marked 'honored by Up's foreground session
only; ignored by Start'. Two implicit behaviors become explicit along
the way: Attach doubles as the detached/interactive mode switch (nil
means Up returns once containers are started), and AttachTo has two
unrelated meanings (project reconstruction source for Start, log
scoping for Up).

Part of #14074 (B: pkg/api promises things the implementation does not
honor).

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2026-08-20 12:32:25 +02:00
Nicolas De Loof
00ce78a055 api: state the scoping invariant Services fields never had
Three structs carry a Services field with three different meanings:
ProjectLoadOptions.Services narrows the loaded project (the only real
filter), CreateOptions.Services only selects which recreation policy
applies to which service while the WHOLE project converges, and
StartOptions.Services only scopes Up's log monitor and is ignored by
Start. Nothing said so: an SDK consumer calling
Create(project, CreateOptions{Services: []string{"web"}}) reasonably
expected to create web alone, and got the full project.

The interface doc now states the underlying invariant — methods act on
the whole project they receive; scoping is done by narrowing the
project, and downstream Services fields are intent markers, not
filters — and each of the three fields documents its actual effect.

Part of #14074 (B: pkg/api promises things the implementation does not
honor).

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2026-08-20 12:32:25 +02:00
Nicolas De Loof
3ee4b5c793 api: ScaleOptions carries the replica counts it always pretended to
The Compose interface promised 'Scale manages numbers of container
instances running per service', but ScaleOptions had no replica count:
callers had to know they must mutate project.Services[x] via SetScale
before calling, and ScaleOptions.Services only tuned the recreation
policy. An SDK consumer following the interface doc got a no-op
convergence of the whole project.

ScaleOptions gains Replicas (service -> count); the backend applies it
to the model itself before converging, and derives the targeted
services from its keys when Services is not set. The CLI now does what
a CLI should: parse SERVICE=REPLICAS tuples and hand them to the
backend, instead of pre-mutating the model. Passing a pre-mutated
project with an empty Replicas map still behaves as before, so
existing SDK callers are unaffected.

Part of #14074 (B: pkg/api promises things the implementation does not
honor).

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2026-08-20 10:16:06 +02:00
Nick Sieger
870908cc8f feat(ps): add ENGINE column gated on label presence
Show an ENGINE column in `compose ps` default table output when the
com.docker.compose.engine label is present. 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>
2026-08-17 10:34:46 +02:00
Ricardo Branco
1615bf352f fix(build): resolve image volumes to a mountable name, not a manifest digest
With the containerd image store, ImageSummary.ID holds the digest of the
platform-specific manifest so ServiceHash stays stable across attested
rebuilds (see contentDigest). resolveImageVolumes reused that same value
as the `type: image` mount Source, but the daemon only resolves a mount
Source by name/tag or top-level image ID, not by manifest digest — so
`compose up` failed with "No such image" whenever the volume's source
image was already present locally (always for a built image; on a
second run for a pulled one).

Keep Source as the resolved image name, and track the digest separately
via a new com.docker.compose.image-volume-digest label so mustRecreate
can still detect a rebuilt/updated source image independently of Source.

Fixes #14005

Signed-off-by: Ricardo Branco <rbranco@suse.de>
Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
2026-08-13 12:03:29 +02:00
Nicolas De Loof
1cc5120af8 Dedup pre_start hook images against service and each other
Address review feedback on pre_start hook image resolution:

1. GetDependentImages now skips a hook image equal to the service image
   (resolved via GetImageNameOrDefault), so `config --images` no longer
   prints a duplicate line and pullRequiredImages no longer schedules a
   redundant pull for it.

2. pullRequiredImages (up/create path) now dedups dependent images by
   reference via a `scheduled` set, so several hooks/services sharing the
   same missing image don't schedule concurrent redundant pulls. The hook
   pass moved to a helper (addPreStartHookPulls) to keep complexity in check.

3. The `pull` command no longer skips hook images under `pull_policy: build`.
   A hook image is a registry image that can't be built, so only `never`
   justifies skipping it — making `pull` consistent with the `up` path.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2026-07-30 10:40:06 +02:00
Nicolas De Loof
c9266e6297 Resolve pre_start hook images alongside service images
pre_start hooks run as ephemeral init containers with their own image
(ServiceHook.Image), but that image was ignored by image resolution:
`config --images` didn't list it, `pull` didn't fetch it, and `up` failed
at runtime with "No such image" when it wasn't already present locally.

Add a GetDependentImages helper that returns a service's pre_start hook
images, and use it wherever service images are collected/pulled:
getLocalImagesDigests, pullRequiredImages (up path), the pull command, and
`config --images`. Hook images inherit the parent service pull policy.

post_start/pre_stop hooks run via ExecCreate inside the service container
and never use hook.Image, so they are intentionally out of scope.

Digest resolution/locking (--resolve-image-digests / --lock-image-digests)
is not covered: compose-go's WithImagesResolved only resolves service.Image
(needs an upstream change), and the --lock-image-digests override merges
pre_start by concatenation, which would duplicate hooks.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2026-07-30 10:40:06 +02:00
blackflytech
ff711700cd Fix grammar in Attestations field comment
Signed-off-by: blackflytech <blackflytech@outlook.com>
2026-07-06 10:36:46 +02:00
Guillaume Lours
9eb8966705 fix: provider output handling and watch rebuild re-invocation
Provider info and error messages containing newlines broke the TTY
progress display (timer drifting to a new line, broken cursor
movement). Extract only the first line for progress events via
firstLine(). Full messages remain available through the provider's
own debug message type.

Skip provider services during watch rebuild convergence by adding a
SkipProviders flag to CreateOptions, set only by the watch rebuild
path. This prevents unnecessary re-invocation of providers on every
file change while preserving normal provider execution for all other
commands (up, create, run, scale).

Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
2026-04-14 11:43:48 +02:00
Sebastiaan van Stijn
bfb5511d0d go.mod: bump github.com/moby/moby/api v1.53.0, moby/client v0.2.2
Also update TestDefaultNetworkSettings:
Test that the network with the highest priority is returned as
"primary" network, and other networks as extra networks.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-02-11 12:32:37 +01:00
Guillaume Lours
6599f8ad84 add 'configured' event at the end of model configuration phase
Currently when using models, the final message is 'confugiring' which could let users think the DMR configuration is still pending

Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>

# Conflicts:
#	pkg/api/event.go
2025-12-15 10:14:21 +01:00
Nicolas De Loof
02008a0097 Restored image layer download progress details on pull.
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-12-12 14:22:02 +01:00
Nicolas De Loof
c0345e4f45 restore support for COMPOSE_COMPATIBILITY
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-12-07 18:42:04 +01:00
Sebastiaan van Stijn
dc66e6bad1 golangci-lint: use gci formatter instead of goimports
Most files already grouped imports into "stdlib -> other -> local",
but some files didn't. The gci formatter is similar to goimports, but
has better options to make sure imports are grouped in the expected
order (and to make sure no additional groups are present).

This formatter has a 'fix' function, so code can be re-formatted auto-
matically;

    golangci-lint run -v --fix

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-01 12:21:50 +01:00
Nicolas De Loof
d7e5f20eb6 images command should display image Created time or N/A if not available
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-11-13 09:40:56 +01:00
Nicolas De Loof
2b4543935c next release will be major version v5.x
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-11-13 09:32:43 +01:00
Nicolas De Loof
45def51117 make DRYRUN_PREFIX a display attribute, move DryRunClient out of pkg/api
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-11-12 11:17:28 +01:00
Nicolas De Loof
aff5c115d6 move progress UI components into cmd
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-11-12 11:17:28 +01:00
Jonty
dc90c4e44d Grammatical fix
Signed-off-by: Jonty <jontyleslie@gmail.com>
2025-11-10 11:34:18 +01:00
Jonty
91e1753d80 Grammatical fix
Signed-off-by: Jonty <jontyleslie@gmail.com>
2025-11-10 11:34:18 +01:00
Jonty
9db27a65c6 Making the American/British spellings consistent to the error messages
Signed-off-by: Jonty <jontyleslie@gmail.com>
2025-11-10 11:34:18 +01:00
Nicolas De Loof
7eb5adeef6 introduce --insecure-registry, reserved for testing purpose
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-11-06 16:17:21 +01:00
Nicolas De Loof
fc2a7d13fa from Compose CLI, we know the streams used to configure LogConsumer
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-11-04 10:25:14 +01:00
Guillaume Lours
d74274bc04 Add LoadProject method to Compose SDK API
This commit adds a new LoadProject method to the Compose service API,
allowing SDK users to programmatically load Compose projects with full
control over the loading process.

Changes:

1. New API method (pkg/api/api.go):
   - LoadProject(ctx, ProjectLoadOptions) (*types.Project, error)
   - ProjectLoadOptions struct with all loader configuration
   - LoadListener callback for event notifications (metrics, etc.)
   - ProjectOptionsFns field for compose-go loader options

2. Implementation (pkg/compose/loader.go):
   - createRemoteLoaders: Git and OCI remote loader setup
   - buildProjectOptions: Translates ProjectLoadOptions to compose-go options
   - postProcessProject: Service filtering, labels, resource pruning

3. Unit test (pkg/compose/loader_test.go):
   - Tests basic project loading functionality
   - Verifies ProjectOptionsFns with cli.WithoutEnvironmentResolution

4. Mock update (pkg/mocks/mock_docker_compose_api.go):
   - Added LoadProject to mock interface

Key design decisions:
- LoadListener pattern keeps metrics collection in CLI, not SDK
- ProjectOptionsFns exposes compose-go options directly (e.g., cli.WithInterpolation(false))
- Post-processing in SDK: labels, service filtering, resource pruning
- Environment resolution NOT in SDK (command responsibility)
- Compatibility mode handling (api.Separator)

Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2025-11-03 08:58:30 +01:00
Guillaume Lours
3658a063bb add AlwaysOkPrompt to replace 'AlwaysYes' current implementation'
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2025-11-03 08:01:59 +01:00
Guillaume Lours
8274be8d08 configure Compose service with io.Reader and io.Writer
remove usage of internal IO interfaces

Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2025-10-27 18:54:10 +01:00
Guillaume Lours
86e91e010d Add streamOverrideWrapper to intercepts command.Cli stream methods and transparently returns custom streams when provided via options
Add new GetConfiguredStreams function to Compose API definition

Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2025-10-27 16:17:50 +01:00
Guillaume Lours
e1678c5c43 Introduce abstractions to support SDK usage without requiring Docker CLI
This commit prepares the Compose service for SDK usage by abstracting away
the hard dependency on command.Cli. The Docker CLI remains the standard path
for the CLI tool, but SDK users can now provide custom implementations of
streams and context information.

Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2025-10-27 16:17:50 +01:00
Nicolas De Loof
7f668bd7fe Setup Compose service using functional parameters
This commit introduces WithMaxConcurrency and WithDryRun to replace direct mutators on composeService
commands and flags are translated into a set of functional parameters which are eventually applied
as a ComposeService is created just before being actually used by a command

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-10-24 18:24:21 +02:00
Nicolas De Loof
9b4fcce034 introduce WithPrompt to configure compose backend to use a plugable UI component for user interaction
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-10-22 16:14:55 +02:00
Nicolas De Loof
07602f2070 publish Compose application as compose.yaml + images
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-10-03 10:59:57 +02:00
Sebastiaan van Stijn
4761fd88b0 pkg/compose: build: remove permissions warning on Windows
This warning was added in [moby@4a8b3ca] to print a warning when building
Linux images from a Windows client. Window's filesystem does not have an
"executable" bit, which mean that, for example, copying a shell script
to an image during build would lose the executable bit. So for Windows
clients, the executable bit would be set on all files, unconditionally.

Originally this was detected in the client, which had direct access to
the API response headers, but when refactoring the client to use a common
library in [moby@535c4c9], this was refactored into a `ImageBuildResponse`
wrapper, deconstructing the API response into an `io.Reader` and a string
field containing only the `OSType` header.

This was the only use and only purpose of the `OSType` field, and now that
BuildKit is the default builder for Linux images, this warning didn't get
printed unless BuildKit was explicitly disabled.

This patch removes the warning, so that we can potentially remove the
field, or the `ImageBuildResponse` type altogether.

[moby@4a8b3ca]: 4a8b3cad60
[moby@535c4c9]: 535c4c9a59

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-09-24 10:26:05 +02:00
Nicolas De Loof
a473341058 volume ls command can run without a project
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-09-10 09:41:47 +02:00
Sebastiaan van Stijn
f1efbb8322 use enum-consts for State and Health
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-08-29 08:18:16 +02:00
Kian Eliasi
6078b4d99d Fix: use image created time when last tag time is not present
Signed-off-by: Kian Eliasi <kian.elbo@gmail.com>
2025-08-27 09:03:58 +02:00
keitosuwahara
adbd61e5d6 fixed lint error
Signed-off-by: keitosuwahara <keitosuwahara0816@gmail.com>
2025-07-27 19:36:40 +02:00
keitosuwahara
e37ac04329 deleted useless comment
Signed-off-by: keitosuwahara <keitosuwahara0816@gmail.com>
2025-07-27 19:36:40 +02:00
keitosuwahara
cab2c2a44e Refactoring of redundant condition checks
Signed-off-by: keitosuwahara <keitosuwahara0816@gmail.com>
2025-07-27 19:36:40 +02:00
keitosuwahara
1b12c867c5 add Streams Comment
Signed-off-by: keitosuwahara <keitosuwahara0816@gmail.com>
2025-07-27 14:57:43 +02:00
Nicolas De Loof
fd954f266c show build progress during watch rebuild
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-07-23 13:57:46 +02:00
Nicolas De Loof
8f91793fb5 introduce build.provenance and sbom support
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-07-21 17:07:41 +02:00
Nicolas De Loof
1c37f1abb6 use logs API with Since to collect the very first logs after restart
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-07-16 17:24:11 +02:00
Nicolas De Loof
485b6200ee (refactoring) introduce monitor to manage containers events and application termination
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-07-16 17:24:11 +02:00
MohammadHasan Akbari
35efa97b7d feat: add since & until flags to events command
Signed-off-by: MohammadHasan Akbari <jarqvi.jarqvi@gmail.com>
Co-authored-by: Amin Ehterami <A.Ehterami@proton.me>
2025-07-09 10:08:33 +02:00
Leonardo Peregrino
3a7982fe45 add service filter to volumes command
Signed-off-by: Leonardo Peregrino <55335068+leoperegrino@users.noreply.github.com>
2025-06-30 19:38:27 +02:00
Leonardo Peregrino
5430caa172 add volumes command
Signed-off-by: Leonardo Peregrino <55335068+leoperegrino@users.noreply.github.com>
2025-06-30 19:38:27 +02:00
Nicolas De Loof
276c229458 move run logic inside backend
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-06-13 14:43:16 +02:00
Nicolas De Loof
9b67a48c33 (refactoting) Move watch logic into a dedicated Watcher type
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-06-05 16:48:05 +02:00