fix: COMPOSE_REMOVE_ORPHANS resolves identically for every command carrying the flag - #14139
fix: COMPOSE_REMOVE_ORPHANS resolves identically for every command carrying the flag#14139ndeloof wants to merge 1 commit into
Conversation
…rrying the flag The variable had three resolution mechanisms: up read it in PreRunE after the project's .env was injected into the process environment; down and kill read it at cobra-tree construction time — before that injection, so a value declared in the project's .env worked for up but not for them; create and run never read it at all. All five commands now resolve it through one helper, from PreRunE: explicit flag wins, then the process environment as completed by setEnvWithDotEnv from the local .env. create also gains the COMPOSE_IGNORE_ORPHANS handling (its ignoreOrphans field was sent to the API without ever being assigned) with the same conflict guard as up. setEnvWithDotEnv's remote-config exclusion is now documented as a product decision, not a technical constraint: COMPOSE_* variables exist so a local user doesn't repeat flags — they are the local user's choice, and a remote model must not steer the CLI consuming it. Unit tests pin the .env → process env → flag resolution order and the remote exclusion (epic docker#14074, D.1 and G.3). Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
docker-agent
left a comment
There was a problem hiding this comment.
Assessment: 🟡 NEEDS ATTENTION
Lower-confidence findings (not posted inline)
- [medium→low] cmd/compose/compose.go:757 — Remote-config exclusion guard in
setEnvWithDotEnvonly works whenConfigPathsis pre-populated; silently skipped when paths are discovered dynamically (confidence: weak 52/100) - [medium→low] cmd/compose/create.go:100 — Asymmetric env sources:
removeOrphansreads fromos.Getenv(process env) whileignoreOrphansreads fromproject.Environment(loader-resolved); conflict guard may behave differently for remote configs (confidence: weak 52/100)
| display.Mode = display.ModeQuiet | ||
| backendOptions.Add(compose.WithEventProcessor(display.Quiet())) | ||
| } | ||
| options.removeOrphans = removeOrphansFromEnv(cmd.Flags(), options.removeOrphans) |
There was a problem hiding this comment.
[medium] Missing ignoreOrphans vs removeOrphans conflict guard in run subcommand
This PR correctly adds removeOrphansFromEnv to run's PreRunE so COMPOSE_REMOVE_ORPHANS is now resolved for run — but the corresponding conflict guard that both up and create have was not added to run's RunE.
In up.go (line 129) and create.go (line 103):
if create.ignoreOrphans && create.removeOrphans {
return fmt.Errorf("cannot combine %s and --remove-orphans", ComposeIgnoreOrphans)
}In run.go's RunE, after options.ignoreOrphans = utils.StringToBool(project.Environment[ComposeIgnoreOrphans]) (line 217), there is no equivalent check. Now that removeOrphans is properly resolved for run, a user with both COMPOSE_IGNORE_ORPHANS=true in their project .env and COMPOSE_REMOVE_ORPHANS=true (or --remove-orphans) will get conflicting options silently accepted for run, while up and create would return an error.
Fix: Add the same guard in run.go's RunE after options.ignoreOrphans is assigned:
options.ignoreOrphans = utils.StringToBool(project.Environment[ComposeIgnoreOrphans])
if options.ignoreOrphans && options.removeOrphans {
return fmt.Errorf("cannot combine %s and --remove-orphans", ComposeIgnoreOrphans)
}| Confidence | Score |
|---|---|
| 🟢 strong | 97/100 |
There was a problem hiding this comment.
Agreed and confirmed: run is the only command missing this guard; the fix above resolves it.
There was a problem hiding this comment.
Thank you for confirming! Adding the conflict guard to run will ensure consistent validation across all commands that support orphan handling.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Epic #14074, D.1 (and G.3).
COMPOSE_REMOVE_ORPHANShad three resolution mechanisms:upread it after the project's.envwas injected into the process environment;down/killread it at cobra-tree construction time — before that injection, so a value in the project's.envworked forupbut not for them;create/runnever read it.All five commands now resolve it identically from
PreRunEthrough one helper: explicit flag > process env > local.env.createalso gainsCOMPOSE_IGNORE_ORPHANShandling (itsignoreOrphansfield was sent to the API without ever being assigned), withup's conflict guard.Behavioral notes:
down/killnow honor the variable from the project's.env; the shell-exported case behaves as before (the--helpoutput no longer reflects it as the flag default, since resolution moved out of the flag definition).setEnvWithDotEnv: COMPOSE_* variables are the local user's choice; a remote model must not steer the CLI consuming it..env→ process env → flag resolution order and the remote exclusion.🤖 Generated with Claude Code