Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: added env support to Dokploy stack compose #637

Open
wants to merge 11 commits into
base: canary
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -185,18 +185,12 @@ const Service = (
<div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList
className={cn(
"md:grid md:w-fit max-md:overflow-y-scroll justify-start",
"md:grid md:w-fit max-md:overflow-y-scroll justify-start md:grid-cols-6",
data?.serverId ? "md:grid-cols-6" : "md:grid-cols-7",
data?.composeType === "docker-compose" ? "" : "md:grid-cols-6",
data?.serverId && data?.composeType === "stack"
? "md:grid-cols-5"
: "",
)}
>
<TabsTrigger value="general">General</TabsTrigger>
{data?.composeType === "docker-compose" && (
<TabsTrigger value="environment">Environment</TabsTrigger>
)}
<TabsTrigger value="environment">Environment</TabsTrigger>
{!data?.serverId && (
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
)}
Expand Down
48 changes: 47 additions & 1 deletion packages/server/src/utils/builders/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import {
createWriteStream,
existsSync,
mkdirSync,
readFileSync,
writeFileSync,
} from "node:fs";
import { dirname, join } from "node:path";
import { paths } from "@dokploy/server/constants";
import type { InferResultType } from "@dokploy/server/types/with";
import boxen from "boxen";
import dotenv from "dotenv";
import {
writeDomainsToCompose,
writeDomainsToComposeRemote,
Expand All @@ -28,6 +30,7 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
const command = createCommand(compose);
await writeDomainsToCompose(compose, domains);
createEnvFile(compose);
processComposeFile(compose);

const logContent = `
App Name: ${appName}
Expand Down Expand Up @@ -84,6 +87,7 @@ export const getBuildComposeCommand = async (
const command = createCommand(compose);
const envCommand = getCreateEnvFileCommand(compose);
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
const processComposeFileCommand = getProcessComposeFileCommand(compose);

const newCompose = await writeDomainsToComposeRemote(
compose,
Expand Down Expand Up @@ -119,6 +123,8 @@ Compose Type: ${composeType} ✅`;

cd "${projectPath}";

${processComposeFileCommand}

docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; }

echo "Docker Compose Deployed: ✅" >> "${logPath}"
Expand All @@ -145,7 +151,7 @@ export const createCommand = (compose: ComposeNested) => {
const { composeType, appName, sourceType } = compose;

const path =
sourceType === "raw" ? "docker-compose.yml" : compose.composePath;
sourceType === "raw" ? "docker-compose.processed.yml" : compose.composePath;
let command = "";

if (composeType === "docker-compose") {
Expand Down Expand Up @@ -188,6 +194,46 @@ const createEnvFile = (compose: ComposeNested) => {
writeFileSync(envFilePath, envFileContent);
};

export const processComposeFile = (compose: ComposeNested) => {
const { COMPOSE_PATH } = paths();
const { env, appName, sourceType, composeType } = compose;

if (composeType === "stack") {
const inputPath =
sourceType === "raw" ? "docker-compose.yml" : compose.composePath;
const composeInputFilePath =
join(COMPOSE_PATH, appName, "code", inputPath) ||
join(COMPOSE_PATH, appName, "code", "docker-compose.yml");

const outputPath = "docker-compose.processed.yml";
const composeOutputFilePath =
join(COMPOSE_PATH, appName, "code", outputPath) ||
join(COMPOSE_PATH, appName, "code", "docker-compose.processed.yml");

const envContent = prepareEnvironmentVariables(env || "").join("\n");
const envVariables = dotenv.parse(envContent);

let templateContent = readFileSync(composeInputFilePath, "utf8");

templateContent = templateContent.replace(
/\$\{([^}]+)\}/g,
(_, varName) => {
return envVariables[varName] || "";
},
);

writeFileSync(composeOutputFilePath, templateContent);
}
};

export const getProcessComposeFileCommand = (compose: ComposeNested) => {
const { composeType } = compose;
if (composeType === "stack") {
return "set -a; source .env; set +a; envsubst < docker-compose.yml > docker-compose.processed.yml";
}
return "cp docker-compose.yml docker-compose.processed.yml";
};

export const getCreateEnvFileCommand = (compose: ComposeNested) => {
const { COMPOSE_PATH } = paths(true);
const { env, composePath, appName } = compose;
Expand Down