diff --git a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx
index af6dd033..43a3cb69 100644
--- a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx
+++ b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx
@@ -174,9 +174,8 @@ export const AddDomain = ({
isLoading={isLoadingGenerate}
onClick={() => {
generateDomain({
- applicationId:
- application?.applicationId || "",
- // appName: application?.appName || "",
+ appName: application?.appName || "",
+ serverId: application?.serverId || "",
})
.then((domain) => {
field.onChange(domain);
diff --git a/apps/dokploy/components/dashboard/application/general/deploy-application.tsx b/apps/dokploy/components/dashboard/application/general/deploy-application.tsx
index d8a33384..f9115c76 100644
--- a/apps/dokploy/components/dashboard/application/general/deploy-application.tsx
+++ b/apps/dokploy/components/dashboard/application/general/deploy-application.tsx
@@ -45,14 +45,17 @@ export const DeployApplication = ({ applicationId }: Props) => {
Cancel
{
- toast.success("Deploying Application....");
-
- await refetch();
await deploy({
applicationId,
- }).catch(() => {
- toast.error("Error to deploy Application");
- });
+ })
+ .then(async () => {
+ toast.success("Application deployed succesfully");
+ await refetch();
+ })
+
+ .catch(() => {
+ toast.error("Error to deploy Application");
+ });
await refetch();
}}
diff --git a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx
index 5e410790..056c003a 100644
--- a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx
+++ b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx
@@ -310,6 +310,7 @@ export const AddDomainCompose = ({
isLoading={isLoadingGenerate}
onClick={() => {
generateDomain({
+ serverId: compose?.serverId || "",
appName: compose?.appName || "",
})
.then((domain) => {
diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts
index 9b812efc..591904bc 100644
--- a/apps/dokploy/server/api/routers/compose.ts
+++ b/apps/dokploy/server/api/routers/compose.ts
@@ -152,9 +152,7 @@ export const composeRouter = createTRPCRouter({
.query(async ({ input }) => {
const compose = await findComposeById(input.composeId);
const domains = await findDomainsByComposeId(input.composeId);
-
const composeFile = await addDomainToCompose(compose, domains);
-
return dump(composeFile, {
lineWidth: 1000,
});
diff --git a/apps/dokploy/server/api/routers/domain.ts b/apps/dokploy/server/api/routers/domain.ts
index 1487bd79..186c31a6 100644
--- a/apps/dokploy/server/api/routers/domain.ts
+++ b/apps/dokploy/server/api/routers/domain.ts
@@ -21,6 +21,7 @@ import {
removeDomainById,
updateDomainById,
} from "../services/domain";
+import { z } from "zod";
export const domainRouter = createTRPCRouter({
create: protectedProcedure
@@ -47,9 +48,9 @@ export const domainRouter = createTRPCRouter({
return await findDomainsByComposeId(input.composeId);
}),
generateDomain: protectedProcedure
- .input(apiFindOneApplication)
+ .input(z.object({ serverId: z.string(), appName: z.string() }))
.mutation(async ({ input }) => {
- return generateTraefikMeDomain(input.applicationId);
+ return generateTraefikMeDomain(input.serverId, input.appName);
}),
update: protectedProcedure
diff --git a/apps/dokploy/server/api/services/application.ts b/apps/dokploy/server/api/services/application.ts
index e815392b..e22db2a3 100644
--- a/apps/dokploy/server/api/services/application.ts
+++ b/apps/dokploy/server/api/services/application.ts
@@ -164,30 +164,29 @@ export const deployApplication = async ({
try {
if (application.serverId) {
- let command = `
- set -e
- `;
+ let command = "set -e";
if (application.sourceType === "github") {
command += await getGithubCloneCommand(application, deployment.logPath);
- command += getBuildCommand(application, deployment.logPath);
} else if (application.sourceType === "gitlab") {
command += await getGitlabCloneCommand(application, deployment.logPath);
- command += getBuildCommand(application, deployment.logPath);
} else if (application.sourceType === "bitbucket") {
command += await getBitbucketCloneCommand(
application,
deployment.logPath,
);
- command += getBuildCommand(application, deployment.logPath);
} else if (application.sourceType === "git") {
command += await getCustomGitCloneCommand(
application,
deployment.logPath,
);
- command += getBuildCommand(application, deployment.logPath);
} else if (application.sourceType === "docker") {
command += await buildRemoteDocker(application, deployment.logPath);
}
+
+ if (application.sourceType !== "docker") {
+ command += getBuildCommand(application, deployment.logPath);
+ }
+
await executeCommand(application.serverId, command);
await mechanizeDockerContainer(application);
} else {
@@ -210,6 +209,8 @@ export const deployApplication = async ({
}
}
+ console.log("Command", "Finish");
+
await updateDeploymentStatus(deployment.deploymentId, "done");
await updateApplicationStatus(applicationId, "done");
diff --git a/apps/dokploy/server/api/services/compose.ts b/apps/dokploy/server/api/services/compose.ts
index 6cb26985..9db65fbe 100644
--- a/apps/dokploy/server/api/services/compose.ts
+++ b/apps/dokploy/server/api/services/compose.ts
@@ -8,10 +8,15 @@ import {
getBuildComposeCommand,
} from "@/server/utils/builders/compose";
import { randomizeSpecificationFile } from "@/server/utils/docker/compose";
-import { cloneCompose, loadDockerCompose } from "@/server/utils/docker/domain";
+import {
+ cloneCompose,
+ cloneComposeRemote,
+ loadDockerCompose,
+ loadDockerComposeRemote,
+} from "@/server/utils/docker/domain";
import { sendBuildErrorNotifications } from "@/server/utils/notifications/build-error";
import { sendBuildSuccessNotifications } from "@/server/utils/notifications/build-success";
-import { execAsync } from "@/server/utils/process/execAsync";
+import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync";
import {
cloneBitbucketRepository,
getBitbucketCloneCommand,
@@ -38,8 +43,8 @@ import { eq } from "drizzle-orm";
import { getDokployUrl } from "./admin";
import { createDeploymentCompose, updateDeploymentStatus } from "./deployment";
import { validUniqueServerAppName } from "./project";
-import { getBuildCommand } from "@/server/utils/builders";
import { executeCommand } from "@/server/utils/servers/command";
+import type { ComposeSpecification } from "@/server/utils/docker/types";
export type Compose = typeof compose.$inferSelect;
@@ -136,10 +141,20 @@ export const loadServices = async (
const compose = await findComposeById(composeId);
if (type === "fetch") {
- await cloneCompose(compose);
+ if (compose.serverId) {
+ await cloneComposeRemote(compose);
+ } else {
+ await cloneCompose(compose);
+ }
}
- let composeData = await loadDockerCompose(compose);
+ let composeData: ComposeSpecification | null;
+
+ if (compose.serverId) {
+ composeData = await loadDockerComposeRemote(compose);
+ } else {
+ composeData = await loadDockerCompose(compose);
+ }
if (compose.randomize && composeData) {
const randomizedCompose = randomizeSpecificationFile(
@@ -196,8 +211,8 @@ export const deployCompose = async ({
try {
if (compose.serverId) {
let command = `
- set -e
- `;
+ set -e;
+ `;
if (compose.sourceType === "github") {
command += await getGithubCloneCommand(
compose,
@@ -225,8 +240,23 @@ export const deployCompose = async ({
} else if (compose.sourceType === "raw") {
command += getCreateComposeFileCommand(compose);
}
- command += getBuildComposeCommand(compose, deployment.logPath);
- await executeCommand(compose.serverId, command);
+
+ // await executeCommand(compose.serverId, command);
+ command += await getBuildComposeCommand(compose, deployment.logPath);
+
+ console.log(command);
+
+ // console.log(buildCommand);
+ try {
+ const { stderr, stdout } = await execAsyncRemote(
+ compose.serverId,
+ command,
+ );
+ console.log(stderr);
+ console.log(stdout);
+ } catch (error) {
+ console.log(error);
+ }
} else {
if (compose.sourceType === "github") {
await cloneGithubRepository(compose, deployment.logPath, true);
diff --git a/apps/dokploy/server/api/services/domain.ts b/apps/dokploy/server/api/services/domain.ts
index 9a338c28..5f944596 100644
--- a/apps/dokploy/server/api/services/domain.ts
+++ b/apps/dokploy/server/api/services/domain.ts
@@ -6,6 +6,7 @@ import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { findAdmin } from "./admin";
import { findApplicationById } from "./application";
+import { findServerById } from "./server";
export type Domain = typeof domains.$inferSelect;
@@ -33,11 +34,21 @@ export const createDomain = async (input: typeof apiCreateDomain._type) => {
});
};
-export const generateTraefikMeDomain = async (appName: string) => {
- const application = await findApplicationById(appName);
+export const generateTraefikMeDomain = async (
+ serverId: string,
+ appName: string,
+) => {
+ if (serverId) {
+ const server = await findServerById(serverId);
+ return generateRandomDomain({
+ serverIp: server.ipAddress,
+ projectName: appName,
+ });
+ }
+ const admin = await findAdmin();
return generateRandomDomain({
- serverIp: application.server?.ipAddress || "",
- projectName: application.appName,
+ serverIp: admin?.serverIp || "",
+ projectName: appName,
});
};
diff --git a/apps/dokploy/server/utils/builders/compose.ts b/apps/dokploy/server/utils/builders/compose.ts
index 6143c415..2dd98683 100644
--- a/apps/dokploy/server/utils/builders/compose.ts
+++ b/apps/dokploy/server/utils/builders/compose.ts
@@ -8,7 +8,10 @@ import { dirname, join } from "node:path";
import { COMPOSE_PATH } from "@/server/constants";
import type { InferResultType } from "@/server/types/with";
import boxen from "boxen";
-import { writeDomainsToCompose } from "../docker/domain";
+import {
+ writeDomainsToCompose,
+ writeDomainsToComposeRemote,
+} from "../docker/domain";
import { prepareEnvironmentVariables } from "../docker/utils";
import { spawnAsync } from "../process/spawnAsync";
@@ -65,13 +68,16 @@ Compose Type: ${composeType} ✅`;
}
};
-export const getBuildComposeCommand = (
+export const getBuildComposeCommand = async (
compose: ComposeNested,
logPath: string,
) => {
const { sourceType, appName, mounts, composeType, domains } = compose;
const command = createCommand(compose);
+ const envCommand = getCreateEnvFileCommand(compose);
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
+
+ const newCompose = await writeDomainsToComposeRemote(compose, domains);
const logContent = `
App Name: ${appName}
Build Compose 🐳
@@ -80,8 +86,19 @@ Command: docker ${command}
Source Type: docker ${sourceType} ✅
Compose Type: ${composeType} ✅`;
+ const logBox = boxen(logContent, {
+ padding: {
+ left: 1,
+ right: 1,
+ bottom: 1,
+ },
+ width: 80,
+ borderStyle: "double",
+ });
+
const bashCommand = `
-echo "${logContent}" >> ${logPath};
+${newCompose}
+echo "${logBox}" >> ${logPath};
cd ${projectPath} || exit 1;
docker ${command.split(" ").join(" ")} >> ${logPath} 2>&1;
echo "Docker Compose Deployed: ✅" >> ${logPath};
@@ -144,3 +161,26 @@ const createEnvFile = (compose: ComposeNested) => {
}
writeFileSync(envFilePath, envFileContent);
};
+
+export const getCreateEnvFileCommand = (compose: ComposeNested) => {
+ const { env, composePath, appName } = compose;
+ const composeFilePath =
+ join(COMPOSE_PATH, appName, "code", composePath) ||
+ join(COMPOSE_PATH, appName, "code", "docker-compose.yml");
+
+ const envFilePath = join(dirname(composeFilePath), ".env");
+ let envContent = env || "";
+ if (!envContent.includes("DOCKER_CONFIG")) {
+ envContent += "\nDOCKER_CONFIG=/root/.docker/config.json";
+ }
+
+ if (compose.randomize) {
+ envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`;
+ }
+
+ const envFileContent = prepareEnvironmentVariables(envContent).join("\n");
+ return `
+ mkdir -p ${envFilePath};
+ echo "${envFileContent}" > ${envFilePath} 2>/dev/null;
+ `;
+};
diff --git a/apps/dokploy/server/utils/docker/domain.ts b/apps/dokploy/server/utils/docker/domain.ts
index 4d9f9874..d7b5da01 100644
--- a/apps/dokploy/server/utils/docker/domain.ts
+++ b/apps/dokploy/server/utils/docker/domain.ts
@@ -5,17 +5,33 @@ import type { Compose } from "@/server/api/services/compose";
import type { Domain } from "@/server/api/services/domain";
import { COMPOSE_PATH } from "@/server/constants";
import { dump, load } from "js-yaml";
-import { cloneRawBitbucketRepository } from "../providers/bitbucket";
-import { cloneGitRawRepository } from "../providers/git";
-import { cloneRawGithubRepository } from "../providers/github";
-import { cloneRawGitlabRepository } from "../providers/gitlab";
-import { createComposeFileRaw } from "../providers/raw";
+import {
+ cloneRawBitbucketRepository,
+ cloneRawBitbucketRepositoryRemote,
+} from "../providers/bitbucket";
+import {
+ cloneGitRawRepository,
+ cloneRawGitRepositoryRemote,
+} from "../providers/git";
+import {
+ cloneRawGithubRepository,
+ cloneRawGithubRepositoryRemote,
+} from "../providers/github";
+import {
+ cloneRawGitlabRepository,
+ cloneRawGitlabRepositoryRemote,
+} from "../providers/gitlab";
+import {
+ createComposeFileRaw,
+ createComposeFileRawRemote,
+} from "../providers/raw";
import { randomizeSpecificationFile } from "./compose";
import type {
ComposeSpecification,
DefinitionsService,
PropertiesNetworks,
} from "./types";
+import { execAsyncRemote } from "../process/execAsync";
export const cloneCompose = async (compose: Compose) => {
if (compose.sourceType === "github") {
@@ -31,6 +47,20 @@ export const cloneCompose = async (compose: Compose) => {
}
};
+export const cloneComposeRemote = async (compose: Compose) => {
+ if (compose.sourceType === "github") {
+ await cloneRawGithubRepositoryRemote(compose);
+ } else if (compose.sourceType === "gitlab") {
+ await cloneRawGitlabRepositoryRemote(compose);
+ } else if (compose.sourceType === "bitbucket") {
+ await cloneRawBitbucketRepositoryRemote(compose);
+ } else if (compose.sourceType === "git") {
+ await cloneRawGitRepositoryRemote(compose);
+ } else if (compose.sourceType === "raw") {
+ await createComposeFileRawRemote(compose);
+ }
+};
+
export const getComposePath = (compose: Compose) => {
const { appName, sourceType, composePath } = compose;
let path = "";
@@ -57,6 +87,23 @@ export const loadDockerCompose = async (
return null;
};
+export const loadDockerComposeRemote = async (
+ compose: Compose,
+): Promise => {
+ const path = getComposePath(compose);
+ try {
+ if (!compose.serverId) {
+ return null;
+ }
+ const { stdout } = await execAsyncRemote(compose.serverId, `cat ${path}`);
+ if (!stdout) return null;
+ const parsedConfig = load(stdout) as ComposeSpecification;
+ return parsedConfig;
+ } catch (err) {
+ return null;
+ }
+};
+
export const readComposeFile = async (compose: Compose) => {
const path = getComposePath(compose);
if (existsSync(path)) {
@@ -84,12 +131,39 @@ export const writeDomainsToCompose = async (
}
};
+export const writeDomainsToComposeRemote = async (
+ compose: Compose,
+ domains: Domain[],
+) => {
+ if (!domains.length) {
+ return;
+ }
+ const composeConverted = await addDomainToCompose(compose, domains);
+ const path = getComposePath(compose);
+
+ try {
+ if (compose.serverId) {
+ const composeString = dump(composeConverted, { lineWidth: 1000 });
+ return `echo "${composeString}" >> ${path};`;
+ }
+ } catch (error) {
+ throw error;
+ }
+};
+
export const addDomainToCompose = async (
compose: Compose,
domains: Domain[],
) => {
const { appName } = compose;
- let result = await loadDockerCompose(compose);
+
+ let result: ComposeSpecification | null;
+
+ if (compose.serverId) {
+ result = await loadDockerComposeRemote(compose);
+ } else {
+ result = await loadDockerCompose(compose);
+ }
if (!result || domains.length === 0) {
return null;
diff --git a/apps/dokploy/server/utils/providers/bitbucket.ts b/apps/dokploy/server/utils/providers/bitbucket.ts
index e831674e..cc263b2f 100644
--- a/apps/dokploy/server/utils/providers/bitbucket.ts
+++ b/apps/dokploy/server/utils/providers/bitbucket.ts
@@ -11,6 +11,7 @@ import type { InferResultType } from "@/server/types/with";
import { TRPCError } from "@trpc/server";
import { recreateDirectory } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync";
+import { execAsyncRemote } from "../process/execAsync";
export type ApplicationWithBitbucket = InferResultType<
"applications",
@@ -117,6 +118,46 @@ export const cloneRawBitbucketRepository = async (entity: Compose) => {
}
};
+export const cloneRawBitbucketRepositoryRemote = async (compose: Compose) => {
+ const {
+ appName,
+ bitbucketRepository,
+ bitbucketOwner,
+ bitbucketBranch,
+ bitbucketId,
+ serverId,
+ } = compose;
+
+ if (!serverId) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Server not found",
+ });
+ }
+ if (!bitbucketId) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Bitbucket Provider not found",
+ });
+ }
+
+ const bitbucketProvider = await findBitbucketById(bitbucketId);
+ const basePath = COMPOSE_PATH;
+ const outputPath = join(basePath, appName, "code");
+ await recreateDirectory(outputPath);
+ const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`;
+ const cloneUrl = `https://${bitbucketProvider?.bitbucketUsername}:${bitbucketProvider?.appPassword}@${repoclone}`;
+
+ try {
+ await execAsyncRemote(
+ serverId,
+ `git clone --branch ${bitbucketBranch} --depth 1 ${cloneUrl} ${outputPath}`,
+ );
+ } catch (error) {
+ throw error;
+ }
+};
+
export const getBitbucketCloneCommand = async (
entity: ApplicationWithBitbucket | ComposeWithBitbucket,
logPath: string,
diff --git a/apps/dokploy/server/utils/providers/git.ts b/apps/dokploy/server/utils/providers/git.ts
index 707915ae..10c7d75c 100644
--- a/apps/dokploy/server/utils/providers/git.ts
+++ b/apps/dokploy/server/utils/providers/git.ts
@@ -4,8 +4,9 @@ import { updateSSHKeyById } from "@/server/api/services/ssh-key";
import { APPLICATIONS_PATH, COMPOSE_PATH, SSH_PATH } from "@/server/constants";
import { TRPCError } from "@trpc/server";
import { recreateDirectory } from "../filesystem/directory";
-import { execAsync } from "../process/execAsync";
+import { execAsync, execAsyncRemote } from "../process/execAsync";
import { spawnAsync } from "../process/spawnAsync";
+import { Compose } from "@/server/api/services/compose";
export const cloneGitRepository = async (
entity: {
@@ -143,6 +144,7 @@ export const getCustomGitCloneCommand = async (
command.push(`echo "Cloned Custom Git ${customGitUrl}: ✅" >> ${logPath}`);
return command.join("\n");
} catch (error) {
+ console.log(error);
throw error;
}
};
@@ -264,3 +266,63 @@ export const cloneGitRawRepository = async (entity: {
throw error;
}
};
+
+export const cloneRawGitRepositoryRemote = async (compose: Compose) => {
+ const {
+ appName,
+ customGitBranch,
+ customGitUrl,
+ customGitSSHKeyId,
+ serverId,
+ } = compose;
+
+ if (!serverId) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Server not found",
+ });
+ }
+ if (!customGitUrl) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Git Provider not found",
+ });
+ }
+
+ const keyPath = path.join(SSH_PATH, `${customGitSSHKeyId}_rsa`);
+ const basePath = COMPOSE_PATH;
+ const outputPath = join(basePath, appName, "code");
+ const knownHostsPath = path.join(SSH_PATH, "known_hosts");
+
+ if (customGitSSHKeyId) {
+ await updateSSHKeyById({
+ sshKeyId: customGitSSHKeyId,
+ lastUsedAt: new Date().toISOString(),
+ });
+ }
+ try {
+ const command = [];
+ if (!isHttpOrHttps(customGitUrl)) {
+ command.push(addHostToKnownHostsCommand(customGitUrl));
+ }
+ command.push(`rm -rf ${outputPath};`);
+ command.push(`mkdir -p ${outputPath};`);
+ if (customGitSSHKeyId) {
+ command.push(
+ `GIT_SSH_COMMAND="ssh -i ${keyPath} -o UserKnownHostsFile=${knownHostsPath}"`,
+ );
+ }
+
+ command.push(
+ `if ! git clone --branch ${customGitBranch} --depth 1 --progress ${customGitUrl} ${outputPath} ; then
+ echo "[ERROR] Fail to clone the repository ";
+ exit 1;
+ fi
+ `,
+ );
+
+ await execAsyncRemote(serverId, command.join("\n"));
+ } catch (error) {
+ throw error;
+ }
+};
diff --git a/apps/dokploy/server/utils/providers/github.ts b/apps/dokploy/server/utils/providers/github.ts
index 9642ec32..81cfbcae 100644
--- a/apps/dokploy/server/utils/providers/github.ts
+++ b/apps/dokploy/server/utils/providers/github.ts
@@ -12,6 +12,7 @@ import type { Compose } from "@/server/api/services/compose";
import { type Github, findGithubById } from "@/server/api/services/github";
import type { apiFindGithubBranches } from "@/server/db/schema";
import { executeCommand } from "../servers/command";
+import { execAsyncRemote } from "../process/execAsync";
export const authGithub = (githubProvider: Github) => {
if (!haveGithubRequirements(githubProvider)) {
@@ -233,6 +234,39 @@ export const cloneRawGithubRepository = async (entity: Compose) => {
}
};
+export const cloneRawGithubRepositoryRemote = async (compose: Compose) => {
+ const { appName, repository, owner, branch, githubId, serverId } = compose;
+
+ if (!serverId) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Server not found",
+ });
+ }
+ if (!githubId) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "GitHub Provider not found",
+ });
+ }
+ const githubProvider = await findGithubById(githubId);
+ const basePath = COMPOSE_PATH;
+ const outputPath = join(basePath, appName, "code");
+ const octokit = authGithub(githubProvider);
+ const token = await getGithubToken(octokit);
+ const repoclone = `github.com/${owner}/${repository}.git`;
+ await recreateDirectory(outputPath);
+ const cloneUrl = `https://oauth2:${token}@${repoclone}`;
+ try {
+ await execAsyncRemote(
+ serverId,
+ `git clone --branch ${branch} --depth 1 ${cloneUrl} ${outputPath}`,
+ );
+ } catch (error) {
+ throw error;
+ }
+};
+
export const getGithubRepositories = async (githubId?: string) => {
if (!githubId) {
return [];
diff --git a/apps/dokploy/server/utils/providers/gitlab.ts b/apps/dokploy/server/utils/providers/gitlab.ts
index 0a32f2d8..f105593b 100644
--- a/apps/dokploy/server/utils/providers/gitlab.ts
+++ b/apps/dokploy/server/utils/providers/gitlab.ts
@@ -13,6 +13,7 @@ import { TRPCError } from "@trpc/server";
import { recreateDirectory } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync";
import { executeCommand } from "../servers/command";
+import { execAsyncRemote } from "../process/execAsync";
export const refreshGitlabToken = async (gitlabProviderId: string) => {
const gitlabProvider = await findGitlabById(gitlabProviderId);
@@ -361,6 +362,39 @@ export const cloneRawGitlabRepository = async (entity: Compose) => {
}
};
+export const cloneRawGitlabRepositoryRemote = async (compose: Compose) => {
+ const { appName, gitlabPathNamespace, branch, gitlabId, serverId } = compose;
+
+ if (!serverId) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Server not found",
+ });
+ }
+ if (!gitlabId) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Gitlab Provider not found",
+ });
+ }
+ const gitlabProvider = await findGitlabById(gitlabId);
+
+ await refreshGitlabToken(gitlabId);
+ const basePath = COMPOSE_PATH;
+ const outputPath = join(basePath, appName, "code");
+ await recreateDirectory(outputPath);
+ const repoclone = `gitlab.com/${gitlabPathNamespace}.git`;
+ const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`;
+ try {
+ await execAsyncRemote(
+ serverId,
+ `git clone --branch ${branch} --depth 1 ${cloneUrl} ${outputPath}`,
+ );
+ } catch (error) {
+ throw error;
+ }
+};
+
export const testGitlabConnection = async (
input: typeof apiGitlabTestConnection._type,
) => {
diff --git a/apps/dokploy/server/utils/providers/raw.ts b/apps/dokploy/server/utils/providers/raw.ts
index 47603638..43228bb8 100644
--- a/apps/dokploy/server/utils/providers/raw.ts
+++ b/apps/dokploy/server/utils/providers/raw.ts
@@ -4,6 +4,7 @@ import { join } from "node:path";
import type { Compose } from "@/server/api/services/compose";
import { COMPOSE_PATH } from "@/server/constants";
import { recreateDirectory } from "../filesystem/directory";
+import { execAsyncRemote } from "../process/execAsync";
export const createComposeFile = async (compose: Compose, logPath: string) => {
const { appName, composeFile } = compose;
@@ -45,3 +46,19 @@ export const createComposeFileRaw = async (compose: Compose) => {
throw error;
}
};
+
+export const createComposeFileRawRemote = async (compose: Compose) => {
+ const { appName, composeFile, serverId } = compose;
+ const outputPath = join(COMPOSE_PATH, appName, "code");
+ const filePath = join(outputPath, "docker-compose.yml");
+
+ try {
+ const command = `
+ mkdir -p ${outputPath};
+ echo "${composeFile}" > ${filePath};
+ `;
+ await execAsyncRemote(serverId, command);
+ } catch (error) {
+ throw error;
+ }
+};