fix: only pin --project-directory when compose has mounts

--project-directory was added unconditionally in 87b914996 to fix
relative bind mount resolution for git-based compose deploys with a
nested composePath (#5181). It also moves where build.context and the
generated .env resolve, breaking any compose file in a subdirectory
that has context: . alongside its Dockerfile (#5230), or interpolates
env vars (#5242).

Only pin --project-directory when the compose actually has mounts
configured; otherwise build.context and .env resolve against the
compose file's own directory like plain docker compose. Also pass
--env-file explicitly pointing at the generated .env next to the
compose file, so it's found even when --project-directory is pinned
(credit: tonnenpinguin, PR #5235).

Fixes #5230
Fixes #5242
This commit is contained in:
Mauricio Siu
2026-09-01 00:50:05 -06:00
parent e8f4a1715c
commit ec8e645758
3 changed files with 77 additions and 3 deletions
@@ -55,4 +55,69 @@ describe("compose createCommand --project-directory", () => {
);
expect(cmd).toContain("-f docker-compose.yml");
});
it("resolves build.context against the compose file's own directory when there are no mounts", () => {
const cmd = createCommand({
...base,
composePath: "./backend/docker-compose.yml",
} as any);
expect(cmd).not.toContain("--project-directory");
expect(cmd).toContain("-f ./backend/docker-compose.yml");
});
});
describe("compose createCommand --env-file", () => {
it("points --env-file at the generated .env next to a nested compose file", () => {
const cmd = createCommand(
{
...base,
composePath: "./deploy/docker-compose.yml",
createEnvFile: true,
} as any,
"/etc/dokploy/compose/compose-app/code",
);
expect(cmd).toContain("--env-file deploy/.env");
expect(cmd).toContain(
"--project-directory /etc/dokploy/compose/compose-app/code",
);
});
it("omits --env-file when createEnvFile is disabled", () => {
const cmd = createCommand(
{ ...base, composePath: "./deploy/docker-compose.yml" } as any,
"/etc/dokploy/compose/compose-app/code",
);
expect(cmd).not.toContain("--env-file");
});
it("uses the code-root .env for raw sourceType", () => {
const cmd = createCommand(
{
...base,
sourceType: "raw",
composePath: "docker-compose.yml",
createEnvFile: true,
} as any,
"/etc/dokploy/compose/compose-app/code",
);
expect(cmd).toContain("--env-file .env");
});
it("does not add --env-file to stack deploy (unsupported flag)", () => {
const cmd = createCommand(
{
...base,
composeType: "stack",
composePath: "./deploy/docker-compose.yml",
createEnvFile: true,
} as any,
"/etc/dokploy/compose/compose-app/code",
);
expect(cmd).not.toContain("--env-file");
});
});
+4 -1
View File
@@ -551,7 +551,10 @@ export const composeRouter = createTRPCRouter({
const compose = await findComposeById(input.composeId);
const { COMPOSE_PATH } = paths(!!compose.serverId);
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
const command = createCommand(compose, projectPath);
const command = createCommand(
compose,
compose.mounts.length > 0 ? projectPath : undefined,
);
return `docker ${command}`;
}),
refreshToken: protectedProcedure
@@ -22,7 +22,10 @@ export const getBuildComposeCommand = async (rawCompose: ComposeNested) => {
const { COMPOSE_PATH } = paths(!!compose.serverId);
const { sourceType, appName, mounts, composeType, domains } = compose;
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
const command = createCommand(compose, projectPath);
const command = createCommand(
compose,
mounts.length > 0 ? projectPath : undefined,
);
const envCommand = compose.createEnvFile
? getCreateEnvFileCommand(compose)
: "";
@@ -133,7 +136,10 @@ export const createCommand = (compose: ComposeNested, projectPath?: string) => {
const projectDirectoryFlag = projectPath
? `--project-directory ${quote([projectPath])} `
: "";
command = `compose -p ${quote([appName])} ${projectDirectoryFlag}-f ${quote([path])} up -d --build --remove-orphans`;
const envFileFlag = compose.createEnvFile
? `--env-file ${quote([join(dirname(compose.composePath || "docker-compose.yml"), ".env")])} `
: "";
command = `compose -p ${quote([appName])} ${projectDirectoryFlag}${envFileFlag}-f ${quote([path])} up -d --build --remove-orphans`;
} else if (composeType === "stack") {
command = `stack deploy -c ${quote([path])} ${quote([appName])} --prune --with-registry-auth`;
}