Skip to content

fix: an explicit working dir must survive a remote resource loader - #930

Merged
glours merged 2 commits into
compose-spec:mainfrom
ndeloof:14224-working-dir
Sep 18, 2026
Merged

glours merged 2 commits into
compose-spec:mainfrom
ndeloof:14224-working-dir

Conversation

@ndeloof

@ndeloof ndeloof commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Fixes docker/compose#14224: docker compose -f oci://... --project-directory DIR resolved relative bind mounts against the downloaded artifact's own cache directory instead of DIR.

Context

LoadConfigFiles defaults the project's working dir to a remote resource loader's (git, oci) downloaded copy directory whenever it's still empty — intentional, so a self-contained remote artifact (extends, bundled env files) resolves against itself. But the check only looked at whether a working dir had already been set, never at whether the caller's workingDir argument was itself an explicit request (--project-directory) or just a default (the current directory). Once that value reaches LoadConfigFiles as a plain string, the two are indistinguishable — so an explicit request was silently overridden the same way a mere default would be.

What this PR brings

Options gains workingDirExplicit (set via SetWorkingDirExplicit, mirroring the existing projectName/projectNameImperativelySet pair), and LoadConfigFiles's remote-default assignment now skips itself when that flag is set. cli.ProjectOptions.ReadConfigFiles sets it from options.WorkingDir != "" — exactly the condition GetWorkingDir already uses to decide whether an explicit working dir was requested.

The self-contained-artifact default is untouched for the common case (no explicit --project-directory): only an explicit request is now protected from being overridden.

🤖 Generated with Claude Code

@glours glours left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

LoadConfigFiles defaults the project's working dir to a remote loader's
(git, oci) downloaded copy directory whenever config.WorkingDir is
still empty -- intentional, so a self-contained remote artifact
(extends, bundled env files) resolves against itself. But the check
only looked at config.WorkingDir, never at whether the caller's
workingDir parameter was itself an explicit request (--project-directory)
or just a default (the current directory): an explicit request was
silently overridden the same way a default was, with no way to tell
the two apart once they reached LoadConfigFiles as a plain string.

Options gains workingDirExplicit (set via SetWorkingDirExplicit,
mirroring the existing projectName/projectNameImperativelySet pair),
and LoadConfigFiles's remote-default assignment now skips itself when
that flag is set. cli.ProjectOptions.ReadConfigFiles sets it from
options.WorkingDir != "" -- exactly the same condition GetWorkingDir
already uses to decide whether an explicit working dir was requested.

Fixes docker/compose#14224: `docker compose -f oci://... --project-directory
DIR` resolved relative bind mounts against the downloaded artifact's own
cache directory instead of DIR.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This PR introduces workingDirExplicit for the same "caller provided
this on purpose, not a default/guess" distinction that the existing
projectNameImperativelySet field already captures, but under a
different name. Line them up under the same, more idiomatic term:
"imperatively set" reads as a contrast between imperative and
declarative styles, which isn't the distinction being made here and
risks confusing readers about what the flag actually means. "Explicit"
says plainly what both fields mean: user-provided, not defaulted.

Renames projectNameImperativelySet -> projectNameExplicit and,
correspondingly, SetProjectName's imperativelySet parameter ->
explicit. SetProjectName is a public API, but the parameter is
positional, so no caller is affected.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
@glours
glours enabled auto-merge (rebase) September 18, 2026 07:11
@glours
glours merged commit 4d56f81 into compose-spec:main Sep 18, 2026
8 checks passed
ndeloof added a commit to ndeloof/compose that referenced this pull request Sep 21, 2026
Replaces the previous commit's temporary fork replace: compose-spec/compose-go#930
is merged, so TestOciRemoteProjectDirectory now passes against the real,
released compose-go pin instead of a personal fork branch.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.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.

When using docker compose OCI artifact, parameter --project-directory does not work for resolving relative volume paths

2 participants